java中静态代理和动态代理
Posted 天涯浪子心
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java中静态代理和动态代理相关的知识,希望对你有一定的参考价值。
一、概述
代理是一种模式,提供了对目标对象的间接访问方式,即通过代理访问目标对象。如此便于在目标实现的基础上增加额外的功能操作,前拦截,后拦截等,以满足自身的业务需求,同时代理模式便于扩展目标对象功能的特点也为多人所用。
按照代理的创建时期,代理类可以分为两种:
静态:由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。
动态:在程序运行时运用反射机制动态创建而成。
我们根据加载被代理类的时机不同,将代理分为静态代理和动态代理。如果我们在代码编译时就确定了被代理的类是哪一个,那么就可以直接使用静态代理;如果不能确定,那么可以使用类的动态加载机制(反射),在代码运行期间加载被代理的类这就是动态代理,比如RPC框架和Spring AOP机制。
二、图形描述
三、静态代理
静态代理的实现比较简单,代理类通过实现与目标对象相同的接口,并在类中维护一个代理对象。通过构造器塞入目标对象,赋值给代理对象,进而执行代理对象实现的接口方法,并实现前拦截,后拦截等所需的业务功能,一个典型的代理模式通常有三个角色,这里称之为**代理三要素**:共同的接口,代理对象、被代理对象
package com.bjsxt.staticProxy; /** * Created by Administrator on 2019/3/10. */ public class TestStaticProxy { public static void main(String[] args){ //用法类似于线程的代理对象 new Thread(线程对象).start(); new WeddingCompany(new You()).happyMarry(); } } /** * 共同的接口 */ interface Marry{ void happyMarry(); } /** * 真实的角色,被代理角色 */ class You implements Marry{ @Override public void happyMarry() { System.out.println("你结婚了。。。"); } } /** * 代理角色,代理真实的角色 */ class WeddingCompany implements Marry{ private Marry marry; //代理对象内部维护一个真实的角色(需要代理的角色) public WeddingCompany(Marry marry){ this.marry=marry; } @Override public void happyMarry() { ready(); marry.happyMarry(); after(); } private void ready() { System.out.println("布置婚礼。。。。"); } private void after() { System.out.println("闹洞房。。。。"); } }
静态代理的总结
优点:可以做到不对目标对象进行修改的前提下,对目标对象进行功能的扩展和拦截。
缺点:因为代理对象,需要实现与目标对象一样的接口,会导致代理类十分繁多,不易维护,同时一旦接口增加方法,则目标对象和代理类都需要维护。
四、动态代理
在上面的示例中,一个代理只能代理一种类型,而且是在编译器就已经确定被代理的对象。而动态代理是在运行时,通过反射机制实现动态代理,并且能够代理各种类型的对象,动态代理有两种方式jdk动态代理和cglib动态代理
(1)使用jdk动态代理
我们看到jdk的代理机制必须要求被代理类实现某个方法,这样在生成代理类的时候才能知道重写那些方法。(事实上jdk动态代理会动态生成一个被代理类所实现的接口的实现类,跟静态代理类似)这样一个没有实现任何接口的类就无法通过jdk的代理机制进行代理,当然解决方法是使用cglib的代理机制进行代理。
package com.bjsxt.dynamicProxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Map; /** * JDK动态代理:使用前提(基于接口的实现) * JDK动态代理:本质上生产了一个代理类,该代理与被代理目标实现相同的接口, * 当前用户访 问代理类中的方法时,将委派InvacationHandler中的invoke()方法进行处理, * 在invoke()方法中添加业务处理代理和回调被代理目标中方法。 */ public class TestJdkProxy { public static void main(String[] args){ You you=new You();//创建被代理类 WeddingCompany weddingCompany=new WeddingCompany(you); //生成代理类 Marry marry=(Marry)weddingCompany.createProxy(); //通过代理类,调用被代理类的方法 marry.happyMarry(); } } /** * 共同的接口 */ interface Marry{ void happyMarry(); } /** * 真实的角色,被代理角色 */ class You implements Marry { @Override public void happyMarry() { System.out.println("你结婚了。。。"); } } class WeddingCompany implements InvocationHandler { private Object target; //被代理的对象 public WeddingCompany(Object target){ this.target=target; } /** * 生成代理 * @return */ public Object createProxy(){ //获得加载被代理类的 类加载器 ClassLoader loader = target.getClass().getClassLoader(); //指明被代理对象实现的接口 Class<?>[] interfaces = target.getClass().getInterfaces(); //this是当前类的对象,也是代理类,之后想要调用被代理类的方法时,都会委托给这个类的 return Proxy.newProxyInstance(loader, interfaces, this); } /** * * @param proxy 代理对象 * @param method 原对象被调用的方法 * @param args 方法传递的参数 * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { ready(); Object returnValue=method.invoke(target,args); after(); return returnValue; } private void ready() { System.out.println("布置婚礼。。。。"); } private void after() { System.out.println("闹洞房。。。。"); } }
jdk动态代理总结
优点:代理对象无需实现接口,免去了编写很多代理类的烦恼,同时接口增加方法也无需再维护目标对象和代理对象,只需在事件处理器中添加对方法的判断即可。
缺点:代理对象不需要实现接口,但是目标对象一定要实现接口,否则无法使用JDK动态代理。
(2)使用cglib动态代理
cglib是通过继承的方式做的动态代理,因此,如果某个类被标记为final,那么它是无法使用cglib做动态代理。cglib会生成的代理类继承当前的被代理类,并在代理类中对代理方法进行强化处理(前置处理、后置处理等),因此被代理类有没有实现接口都是一样的
当然使用cglib需要添加下cglib所需的jar包:cglib-2.2.2.jar,asm-3.3.1.jar,asm-util-3.3.1.jar,ant-1.6.2.jar
package com.bjsxt.dynamicCglibProxy; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class TestCglibProxy { public static void main(String[] args){ You you=new You();//创建被代理类 WeddingCompany weddingCompany=new WeddingCompany(you); //生成代理类 You you1=(You)weddingCompany.createProxy(); //通过代理类,调用被代理类的方法 you1.happyMarry(); } } /** * 真实的角色,被代理角色 */ class You { public void happyMarry() { System.out.println("你结婚了。。。"); } } /** * 动态没生成代理对象 * 实现 MethodInterceptor方法代理接口,创建代理类 * 当访问代理中的方法时,委派给MethodInteceptor中的处理程序(intercept方法)进行出来, * 在处理程序中添加了业务逻辑和回掉了被代理目标中的方法。 */ class WeddingCompany implements MethodInterceptor { private Object target; //被代理的对象 public WeddingCompany(Object target){ this.target=target; } /** * 创建代理对象 * @return */ public Object createProxy() { //创建加强器,用来创建动态代理类 Enhancer enhancer = new Enhancer(); //为加强器指定要代理的类(即:为下面生成的代理类指定父类) enhancer.setSuperclass(this.target.getClass()); //设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦 enhancer.setCallback(this); // 创建动态代理类对象并返回 return enhancer.create(); } /** * * @param proxy 生成的代理对象 * @param method 被调用的方法 * @param args 方法的入参 * @param methodProxy * @return * @throws Throwable */ @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { ready(); Object value = method.invoke(target, args);//回掉被代理对象中的方法 after(); return value; } private void ready() { System.out.println("布置婚礼。。。。"); } private void after() { System.out.println("闹洞房。。。。"); } }
以上是关于java中静态代理和动态代理的主要内容,如果未能解决你的问题,请参考以下文章