java静态代理和动态代理
2017-10-23 22:03
525 查看
按照代理的创建时期,代理类可以分为两种:
静态代理:由程序员创建代理类或特定工具自动生成源代码,再对其编译。在程序运行前代理类的.class文件就已经存在了。
动态代理:在程序运行时用反射机制动态创建。
(1)Subject接口:
(2)RealSubject类:继承Subject接口,并实现其中的方法
(3)代理类Proxy:继承Subject类,并把Subject作为参数通过构造参数传递。
Subject是个接口,因此在调用的时候传递的应该是他的实现类。
(4)Client客户端调用:
控制台输出:
代理模式:
(1)接口
(2)实现类
(3)代理类:继承InvocationHandler接口并重写invole方法,并把目标类作为参数传递进去
(4)客户端
控制台打印:
cglib,code generate library,代理类可对类进行代理,使用第三方cglib库来实现,其内部使用asm框架生成代理类的字节码,其字节码文件更加复杂,不能代理final方法,因为代理类是委托类的子类。
代理对象的生成过程由Enhancer类(CGLib的字节码增强器)实现,大概步骤如下:
1、生成代理类Class的二进制字节码;
2、通过Class.forName加载二进制字节码,生成Class对象;
3、通过反射机制获取实例构造,并初始化代理类对象。
(1)定义业务逻辑
(2)实现MethodInterceptor接口,定义方法的拦截器
(3)使用Enhancer类生成代理类
控制台输出:
(1)代理使客户端不需要知道实现类是什么,怎么做的,而客户端只需知道代理即可(解耦合)
静态代理的缺点:
(1)一个代理类只能代理一个业务类。如果业务类增加方法时,相应的代理类也要增加方法。。
(2)如果接口增加一个方法,除了实现类需要实现这个方法外,代理类也需要实现此方法。增加了代码维护的复杂度。
jdk和cglib动态代理实现的区别
1、jdk动态代理生成的代理类和委托类实现了相同的接口;
2、cglib动态代理中生成的字节码更加复杂,生成的代理类是委托类的子类,且不能处理被final关键字修饰的方法;
3、jdk采用反射机制调用委托类的方法,cglib采用类似索引的方式直接调用委托类方法;
静态代理:由程序员创建代理类或特定工具自动生成源代码,再对其编译。在程序运行前代理类的.class文件就已经存在了。
动态代理:在程序运行时用反射机制动态创建。
静态代理
代理对象(Proxy)和目标对象(RealSubject)实现了相同的接口(Subject),目标对象作为代理对象的一个属性,具体接口实现中,代理对象可以在调用目标对象相应方法前后加上其他业务处理逻辑。(1)Subject接口:
public interface Subject { public abstract void dealTask(); }
(2)RealSubject类:继承Subject接口,并实现其中的方法
public class RealSubject implements Subject { @Override public void dealTask() { System.out.println("我要吃饭"); } }
(3)代理类Proxy:继承Subject类,并把Subject作为参数通过构造参数传递。
Subject是个接口,因此在调用的时候传递的应该是他的实现类。
public class Proxy implements Subject { // 目标对象 private Subject subject; // 通过构造方法传入目标对象 public Proxy(Subject subject) { this.subject = subject; } @Override public void dealTask() { System.out.println("代理来帮你做饭"); subject.dealTask(); System.out.println("代理来帮你刷碗"); } }
(4)Client客户端调用:
public class Client { public static void main(String[] args) { // Proxy类中构造方法传递的是一个接口,在调用的时候就必须传递这个接口的实现类,因此是RealSubject Subject subject = new Proxy(new RealSubject()); subject.dealTask(); } }
控制台输出:
代理来帮你做饭 我要吃饭 代理来帮你刷碗
动态代理之JDK
为某个对象提供一个代理,以控制对这个对象的访问。 代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代。代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理。代理模式:
(1)接口
public interface SubjectService { public void getName(String name); public void getAge(Integer age); }
(2)实现类
public class SubjectServiceImpl implements SubjectService{ @Override public void getName(String name) { System.out.println("getName方法的实现类:" + name); } @Override public void getAge(Integer age) { System.out.println("getage方法的实现类"+age); } }
(3)代理类:继承InvocationHandler接口并重写invole方法,并把目标类作为参数传递进去
public class MyInvocationHandler implements InvocationHandler { // 目标方法 private Object target; public MyInvocationHandler() { } // 把目标方法作为参数传递 public MyInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 是getName()方法 if ("getName".equals(method.getName())) { System.out.println("before----" + method.getName()); Object result = method.invoke(target, args); System.out.println("after----" + method.getName()); return result; // 是getAge()方法 } else if ("getAge".equals(method.getName())) { System.out.println("before----" + method.getName()); Object result = method.invoke(target, args); System.out.println("after----" + method.getName()); return result; } else { Object result = method.invoke(target, args); return result; } } }
(4)客户端
public class Client { public static void main(String[] args) { //多态的方式 SubjectService subjectService = new SubjectServiceImpl(); //参数是接口,真正调用传递的就应该是实现类 InvocationHandler invocationHandler = new MyInvocationHandler(subjectService); //创建代理类 SubjectService serviceproxy = (SubjectService) Proxy.newProxyInstance( subjectService.getClass().getClassLoader(), subjectService.getClass().getInterfaces(), invocationHandler); serviceproxy.getName("小红"); serviceproxy.getAge(20); } }
控制台打印:
before----getName getName方法的实现类:小红 after----getName before----getAge getage方法的实现类20 after----getAge
动态代理之CGLIB
cglib需要的jar包有asm.jar、cglib.jarcglib,code generate library,代理类可对类进行代理,使用第三方cglib库来实现,其内部使用asm框架生成代理类的字节码,其字节码文件更加复杂,不能代理final方法,因为代理类是委托类的子类。
代理对象的生成过程由Enhancer类(CGLib的字节码增强器)实现,大概步骤如下:
1、生成代理类Class的二进制字节码;
2、通过Class.forName加载二进制字节码,生成Class对象;
3、通过反射机制获取实例构造,并初始化代理类对象。
(1)定义业务逻辑
public class Subject { public void say(String name) { System.out.println("hello " + name); } }
(2)实现MethodInterceptor接口,定义方法的拦截器
public class MyInterceptor implements MethodInterceptor { @Override public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("before----------" + method.getName() + "()"); // 调用MyInterceptor父类的方法,因为在Client类中设置了MyInterceptor的父类是Subject Object returnObj = methodProxy.invokeSuper(object, args); System.out.println("after----------" + method.getName() + "()"); return returnObj; } }
(3)使用Enhancer类生成代理类
public class Client { public static void main(String[] args) { // 利用Enhancer类生成代理类 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Subject.class); // 继承被代理类 enhancer.setCallback(new MyInterceptor()); // 设置回调 //采用多态的形式,因为上面通过setSuperclass设置了继承关系 Subject subject = (Subject) enhancer.create(); // 生成代理对象 subject.say("yes"); } }
控制台输出:
before----------say hello yes after----------say
静态代理和动态代理的比较
静态代理的优点:(1)代理使客户端不需要知道实现类是什么,怎么做的,而客户端只需知道代理即可(解耦合)
静态代理的缺点:
(1)一个代理类只能代理一个业务类。如果业务类增加方法时,相应的代理类也要增加方法。。
(2)如果接口增加一个方法,除了实现类需要实现这个方法外,代理类也需要实现此方法。增加了代码维护的复杂度。
jdk和cglib动态代理实现的区别
1、jdk动态代理生成的代理类和委托类实现了相同的接口;
2、cglib动态代理中生成的字节码更加复杂,生成的代理类是委托类的子类,且不能处理被final关键字修饰的方法;
3、jdk采用反射机制调用委托类的方法,cglib采用类似索引的方式直接调用委托类方法;
相关文章推荐
- java静态代理和动态代理
- 浅谈Java代理(jdk静态代理、动态代理和cglib动态代理)
- Java的静态代理、动态代理,CGLib的动态代理,使用动态代理基于AOP的AspectJ框架—深入探究
- JAVA的静态代理与动态代理比较--转载
- JAVA的静态代理与动态代理比较
- Java 静态代理和动态代理
- Java静态代理与动态代理
- Java代理学习笔记(静态代理&动态代理)
- JAVA学习篇--静态代理VS动态代理
- java 静态代理,jdk动态代理,CGLIB动态代理详解
- java 静态代理 JDK动态代理 Cglib动态代理
- Java动态代理和静态代理
- java静态代理和动态代理
- 代理设计模式之(静态代理+Java自身提供的动态代理机制)
- Java之静态代理和动态代理模式
- Java静态代理和动态代理
- JAVA的静态代理与动态代理比较
- Java代理方式——静态代理和动态代理详解
- Java代理(静态/动态 JDK,cglib)
- Java静态代理和jdk动态代理、Cglib动态代理