静态代理和动态代理
2017-11-28 18:47
162 查看
以前在学习代理这方面知识点的时候,一直都没关注过静态代理和动态代理的区别,只是知道代理是怎么一回事情,知道动态代理是什么,但是有一天学习过程中,看到静态代理这个词,突然才发现,原来不知道静态代理具体指什么,然后就又学习了一下静态代理,并且顺便把动态代理也复习了一下,学完之后感觉对代理方面的知识算是又深入了一点吧。
什么是代理
代理,也叫做Proxy,通俗一点的理解就是指当我去调用一个类的方法时,实际去调用了另一个类的方法,在另一个类的方法里面再去调用我真正想调用的那个类的方法。额,这样说着好绕,好吧,换一种说法,就是假设当我想调用类A的do()方法时,并不直接去调用,而是调用类B的do()方法,类B的do()方法内部再去调用类A的do()方法。
这样的话,就有个好处,原来直接调用A的do()方法,现在通过B再去调用A的do()方法,就可以在调用do()方法的前后加上一些其他的逻辑了,这就是AOP。
下面看个例子吧:
先定义一个Hello接口:
然后定义一个这个接口的实现类HelloImpl:
那么现在问题来了,如果想要在HelloImpl的System.out.println(“hello world”);前后加点逻辑,应该怎么组织代码呢?
最先考虑到的是直接在HelloImpl的say()方法里面改,在println的前后加代码,但是这样的话,代码耦合性就高了,不优雅。所以一般尽量不采用这种方式,而是定义一个代理类来实现这种功能。
静态代理
接下来定义一个StaticHelloProxy代理类:
StaticHelloProxy这个代理类实现了Hello接口,并且里面定义了Hello的一个成员变量,实际new的是HelloImpl类的实例,这样在StaticHelloProxy中重写say方法的时候,就可以调用实际HelloImpl类的say方法了。
在这里,HelloImpl成为目标类,StaticHelloProxy称为代理类。
从StaticHelloProxy名字上也可以看出,这种代理,属于静态代理。一开始就把代理类写好了,在运行之前,就已经有了代理类的字节码。
静态代理也有缺点,比如,StaticHelloProxy这个代理类,在创建的时候就写死了实现Hello接口,这样每当需要一个代理类的时候,就需要新建一个类,整个项目中全是Proxy类文件,而且如果有一天需要在Hello接口中新增一个方法,那么不仅仅要修改HelloImpl,还要修改StaticHelloProxy,这样想想,也挺麻烦的。所以,接下来看看动态代理是怎么实现的。
动态代理
java提供了一个Proxy.newProxyInstance()方法,用来创建代理类的实例对象,下面是这个方法的声明:
这个方法接收三个参数,乍一看挺迷糊的,其实想想,也就那回事,结合静态代理的创建过程,当我们创建一个静态代理类的时候,指定了这个代理类实现的那些接口,并且在代理类中定义了目标类的对象,所以,创建动态代理类的时候,也是类似的,不同点就在于,当我们自己创建一个类的时候,需要额外指定这个类的类加载器(默认是和目标类的类加载器一样就可以了)。
创建动态代理类的时候,目标类是作为参数动态的传进去的,
分析完这些,再看这个方法接收的三个参数,就比较明白了,第一个参数就是这个动态代理类的类加载器,第二个参数就是说明这个动态代理类要实现哪些接口,第三个参数就是实现了InvocationHandler接口的代理类的实例对象。
接下来,定义一个动态代理类,动态代理类要实现InvocationHandler接口。
DynamicProxy中定义了private Object target,这就是被代理的目标类,每次创建动态代理类实例的时候就通过构造方法动态的传进去。并且DynamicProxy还需要实现InvocationHandler接口,重写invoke方法,并且在invoke方法里面通过反射去调用目标类的方法。
下面代码是如何使用动态代理的:
当调用helloDynamicPro
4000
xy.say();的时候,就会调用DynamicProxy里重写的invoke方法,这就是动态代理。
什么是代理
代理,也叫做Proxy,通俗一点的理解就是指当我去调用一个类的方法时,实际去调用了另一个类的方法,在另一个类的方法里面再去调用我真正想调用的那个类的方法。额,这样说着好绕,好吧,换一种说法,就是假设当我想调用类A的do()方法时,并不直接去调用,而是调用类B的do()方法,类B的do()方法内部再去调用类A的do()方法。
这样的话,就有个好处,原来直接调用A的do()方法,现在通过B再去调用A的do()方法,就可以在调用do()方法的前后加上一些其他的逻辑了,这就是AOP。
下面看个例子吧:
先定义一个Hello接口:
public interface Hello { void say(); }
然后定义一个这个接口的实现类HelloImpl:
public class HelloImpl implements Hello { public void say() { System.out.println("hello world"); } }
那么现在问题来了,如果想要在HelloImpl的System.out.println(“hello world”);前后加点逻辑,应该怎么组织代码呢?
最先考虑到的是直接在HelloImpl的say()方法里面改,在println的前后加代码,但是这样的话,代码耦合性就高了,不优雅。所以一般尽量不采用这种方式,而是定义一个代理类来实现这种功能。
静态代理
接下来定义一个StaticHelloProxy代理类:
public class StaticHelloProxy implements Hello{ private Hello hello; public StaticHelloProxy() { this.hello = new HelloImpl(); } public void say() { before(); hello.say(); after(); } private void before() { System.out.println("before"); } private void after() { System.out.println("after"); } }
StaticHelloProxy这个代理类实现了Hello接口,并且里面定义了Hello的一个成员变量,实际new的是HelloImpl类的实例,这样在StaticHelloProxy中重写say方法的时候,就可以调用实际HelloImpl类的say方法了。
在这里,HelloImpl成为目标类,StaticHelloProxy称为代理类。
从StaticHelloProxy名字上也可以看出,这种代理,属于静态代理。一开始就把代理类写好了,在运行之前,就已经有了代理类的字节码。
静态代理也有缺点,比如,StaticHelloProxy这个代理类,在创建的时候就写死了实现Hello接口,这样每当需要一个代理类的时候,就需要新建一个类,整个项目中全是Proxy类文件,而且如果有一天需要在Hello接口中新增一个方法,那么不仅仅要修改HelloImpl,还要修改StaticHelloProxy,这样想想,也挺麻烦的。所以,接下来看看动态代理是怎么实现的。
动态代理
java提供了一个Proxy.newProxyInstance()方法,用来创建代理类的实例对象,下面是这个方法的声明:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
这个方法接收三个参数,乍一看挺迷糊的,其实想想,也就那回事,结合静态代理的创建过程,当我们创建一个静态代理类的时候,指定了这个代理类实现的那些接口,并且在代理类中定义了目标类的对象,所以,创建动态代理类的时候,也是类似的,不同点就在于,当我们自己创建一个类的时候,需要额外指定这个类的类加载器(默认是和目标类的类加载器一样就可以了)。
创建动态代理类的时候,目标类是作为参数动态的传进去的,
分析完这些,再看这个方法接收的三个参数,就比较明白了,第一个参数就是这个动态代理类的类加载器,第二个参数就是说明这个动态代理类要实现哪些接口,第三个参数就是实现了InvocationHandler接口的代理类的实例对象。
接下来,定义一个动态代理类,动态代理类要实现InvocationHandler接口。
public class DynamicProxy implements InvocationHandler { /** * 被代理的目标类 */ private Object target; public DynamicProxy(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(); Object result = method.invoke(target, args); after(); return result; } private void before() { System.out.println("before"); } private void after() { System.out.println("after"); } }
DynamicProxy中定义了private Object target,这就是被代理的目标类,每次创建动态代理类实例的时候就通过构造方法动态的传进去。并且DynamicProxy还需要实现InvocationHandler接口,重写invoke方法,并且在invoke方法里面通过反射去调用目标类的方法。
下面代码是如何使用动态代理的:
Hello hello = new HelloImpl(); DynamicProxy dynamicProxy = new DynamicProxy(hello); Hello helloDynamicProxy = (Hello) Proxy.newProxyInstance( hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), dynamicProxy ); helloDynamicProxy.say();
当调用helloDynamicPro
4000
xy.say();的时候,就会调用DynamicProxy里重写的invoke方法,这就是动态代理。
相关文章推荐
- 【java项目实战】代理模式(Proxy Pattern),静态代理 VS 动态代理
- 静态代理,动态代理,Cglib代理
- java 静态代理 JDK动态代理 Cglib动态代理
- 代理-->静态代理&动态代理
- 静态代理和动态代理
- java设计模式-代理模式(静态代理,动态代理)
- spring技术框架基础知识二(静态)动态代理
- Atitit 代理CGLIB 动态代理 AspectJ静态代理区别
- Spring入门4 静态代理 动态代理 CGLIB AOP切入点切面 AOP注解
- 静态代理和动态代理
- JDK静态代理及动态代理
- 代理模式--静态代理和动态代理
- spring AOP 静态代理和动态代理
- 动态代理和静态代理
- 代理设计模式之静态代理与动态代理(超..)详解
- 代理模式(静态代理、动态代理)
- java [ 静态(接口)代理 ,动态(接口)代理,CglibProxy动态(实体类)代理]
- JDK动态代理与静态代理(一)
- 设计模式之静态代理&动态代理
- 第37天(就业班) 静态代理与动态代理、oglib代理、手动实现aop编程、注解实现AOP编程、aop相关的几个注解、xml实现aop、切入点表达式、spring对aop模式