设计模式之动态代理(spring、cglib、 jdkproxy)
静态代理与动态代理的区别:
静态代理的目标对象比较单一 是某一类或实现同一接口的实例,不利于扩展,而动态代理的目标对象就没有限制,目标对象可以任意实例,如果目标对象实现了接口则可以使用jdk自带的代理类实现,如果没有实现接口则可以使用第三方的组件Cglib来实现。
动态代理
1) 先创建一个通用接口
package com.arno.summary.proxy.dynamicproxy.jdkproxy; /** * Created by Arno */ public interface IPerson { void findLover(); }
2)实现该接口的两个实现类
package com.arno.summary.proxy.dynamicproxy.jdkproxy; /** * Created by Arno */ public class Person1 implements IPerson { public void findLover() { System.out.println("Person1要求:有车有房学历高"); } }
package com.arno.summary.proxy.dynamicproxy.jdkproxy; /** * Created by Arno */ public class Person2 implements IPerson { public void findLover() { System.out.println("Person2要求:肤白貌美大长腿"); } }
3)创建一个代理类,实现java.lang.reflect.InvocationHandler,通过invoke来反射来生成有目标类的实例引用的代理class。
package com.arno.summary.proxy.dynamicproxy.jdkproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * Created by Arno */ public class JdkMeipo implements InvocationHandler { private IPerson target; public IPerson getInstance(IPerson target){ this.target = target; Class<?> clazz = target.getClass(); return (IPerson) Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(); Object result = method.invoke(this.target,args); after(); return result; } private void after() { System.out.println("双方同意,开始交往"); } private void before() { System.out.println("我是媒婆,已经收集到你的需求,开始物色"); } }
4)开始测试
package com.arno.summary.proxy.dynamicproxy.jdkproxy; /** * Created by Arno */ public class Test { public static void main(String[] args) { JdkMeipo jdkMeipo = new JdkMeipo(); IPerson person1 = jdkMeipo.getInstance(new Person1()); person1.findLover(); IPerson person2 = jdkMeipo.getInstance(new Person2()); person2.findLover(); } }
5)运行结果
我是媒婆,已经收集到你的需求,开始物色 Person1要求:有车有房学历高 双方同意,开始交往 我是媒婆,已经收集到你的需求,开始物色 Person2要求:肤白貌美大长腿 双方同意,开始交往
6)分析
要想使用jdk原生的代理,必须实现接口InvocationHandler;且被代理的类都要实现接口。
静态代理:
1)创建一个实例
package com.arno.summary.proxy.staticproxy; /** * Created by Arno */ public class Person2 { public void findLover() { System.out.println("子女自己相处"); } }
2)创建第二个实例。有第一个实例的引用,且他可以通过该饮用调用第一个实例的方法
package com.arno.summary.proxy.staticproxy; /** * Created by Arno */ public class Person1 { private Person2 person2; public Person1(Person2 person2) { this.person2 = person2; } public void findLover() { System.out.println("父母帮忙物色"); person2.findLover(); System.out.println("开始交往"); } }
3)测试
package com.arno.summary.proxy.staticproxy; /** * Created by Arno */ public class Test { public static void main(String[] args) { Person1 person1 = new Person1(new Person2()); person1.findLover(); } }
4)运行结果
父母帮忙物色 子女自己相处 开始交往
5)分析
spring中的依赖注入都是静态代理。如果想要使用被代理的类的新增方法,一定要修改代理类里的方法,比动态代理僵硬,只能硬编码
cglib实现动态代理的原理及与jdk原生的动态代理的区别
1)cglib的实现
CGLib代理执行代理方法的效率之所以比JDK的高,是因为CGlib采用了FastClass机制,它的原理简单来说就是:为代理类和被代理类各生成一个类,这个类会为代理类或被代理类的方法分配index(int类型);这个index当做一个入参,FastClass就可以直接定位要调用的方法并直接进行调用欧冠,省去了反射调用,所以调用效率比JDK代理通过反射调用高。cglib无法代理final标记的方法
2)cglib与jdk的比较
a)JDK动态代理实现了被代理对象的接口,cglib代理继承了被代理对象。
b)JDK动态代理和cglib代理都在运行期间生成字节码,jdk动态代理直接写class字节码,cglib使用asm框架写class字节码,cglib代码实现原理更复杂,生成代理类比jdk动态代理低
c)JDK动态代理调用代理方法是通过反射机制调用的,cglib代理是通过fastclass机制直接调用方法,cglib执行效率更高。
3)spring中的代理选择策略
在spring当中,使用了jdk代理,也使用了cglib代理;
默认的代理选择原则为:
1)当bean有实现接口时,则使用jdk动态代理
2)当bean没有实现接口时,使用cglib实现动态代理
3)spring可以通过配置强行使用cglib代理:
<aop:aspectj-autoproxy proxy-target-class="true" />
总结
1)静态代理与动态代理的本质区别
a)静态代理只能通过手动完成代理操作,如果被代理类增加了新的方法,代理类需要同步增加,违背开闭原则。
b)动态代理采用在运行时动态生成字节码的方式,取消了代理类的扩展限制,遵循开闭原则。
c)若动态代理要对目标类的增强逻辑进行扩展,结合策略模式,只增强新增策略类便可完成,无需修改代理类代码。
2)代理模式的优缺点:
优点
a)代理模式能将代理对象与真实被调用目标对象隔离
b)在一定程度上降低了系统的耦合性,扩展性好
c)可以起到保护目标对象作用
d)可以增强目标对象的功能
缺点
a)代理模式会造成系统设计中类的数量增加
b)在客户端与目标对象中增加一个代理对象,会导致请求处理速度变慢
c)增加系统的复杂度
- 代理设计模式(普通静态代理、JDK动态代理、cglib动态代理)
- Java设计模式--代理模式与JDK动态代理,cglib动态代理
- 设计模式之Proxy(代理):模拟JDK的动态代理
- 设计模式(2)--java动态代理及jdk和cglib的区别
- Spring(十)通过动态代理(JDK的Proxy)和cglib实现AOP技术
- 设计模式——代理模式(静态代理和JDK、CGLib动态代理)
- 设计模式之代理模式(静态代理、JDK动态代理和cglib动态代理)
- 0104 Java设计模式03-动态代理(实战篇JDK和cglib)【进阶】
- 设计模式之JDK动态代理和Cglib动态代理
- spring02 注解方式实现MVC、spring的继承、代理模式(静/动) :jdk动态代理,cglib动态代理
- Java设计模式(七) Spring AOP JDK动态代理 vs. Cglib
- Spring设计模式之JDK的动态代理!
- 简说动态代理设计模式(Spring)
- 【设计模式】动态代理Proxy_01
- Java动态代理模式jdk和cglib的2种实现以及二者的区别(AOP面向切面的前奏)
- JDK设计模式之—动态代理
- 设计模式之JDK动态代理
- Spring中AOP实现的两种方式之JDK和cglib的动态代理
- Java设计模式(七) Spring AOP JDK动态代理 VS. cglib
- 设计模式之代理模式(下) CGLIB动态代理