JDK 动态代理的使用步骤:
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | /** * 抽象接口 */ public interface ISubject { void operate(); } /** * 委托类, 也叫被代理类 * 真正的处理逻辑 */ public class RealSubject implements ISubject{ @Override public void operate() { System.out.println( "实际操作" ); } } /** * 代理对象的处理类 */ public class ProxySubject implements InvocationHandler { private ISubject realSubject; public ProxySubject(ISubject subject) { this .realSubject = subject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println( "调用方法前---前置操作" ); //动态代理调用RealSubject中的方法 Object result = method.invoke(realSubject, args); System.out.println( "调用方法后---后置操作" ); return result; } } /** * 客户端调用类 */ public class JdkProxyClient { public static void main(String[] args) { ISubject subject = new RealSubject(); ISubject result = (ISubject)Proxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), new ProxySubject(subject)); result.operate(); } } |
CGLIB 动态代理的使用步骤:
复制代码
1 2 3 4 5 | <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version> 3.3 . 0 </version> </dependency> |
第一步: 创建委托类
复制代码
1 2 3 4 5 | public class RealSubject { public void operate() { System.out.println( "实际操作的动作" ); } } |
第二步: 创建拦截器类, 实现MethodInterceptor 接口. 在这里面可以对方法进行增强处理
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class ProxyMethodInterceptor implements MethodInterceptor { <a href= "/profile/992988" data-card-uid= "992988" class = "js-nc-card" target= "_blank" from-niu= "default" > @Override public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println( "调用真实操作之前---操作前处理" ); // 调用真实用户需要处理的业务逻辑 Object object = methodProxy.invokeSuper(o, args); System.out.println( "调用真实操作之后---操作后处理" ); return object; } }</a> |
第三步: 创建代理对象Proxy:通过 Enhancer.create() 创建委托类对象的代理对象
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public class CglibProxyFactory { public static Object getProxy(Class<?> clazz) { // 创建cglib动态代理的增强类 Enhancer enhancer = new Enhancer(); // 设置类加载器 enhancer.setClassLoader(clazz.getClassLoader()); // 设置委托类 enhancer.setSuperclass(clazz); // 设置方法拦截器 enhancer.setCallback( new ProxyMethodInterceptor()); // 创建代理类 return enhancer.create(); } } |
第四步: 客户端调用
复制代码
1 2 3 4 5 6 | public class CglibClient { public static void main(String[] args) { RealSubject proxy = (RealSubject)CglibProxyFactory.getProxy(RealSubject. class ); proxy.operate(); } } |
JDK 动态代理和 CGLIB 动态代理对比
1)JDK 动态代理是基于实现了接口的委托类,通过接口实现代理;而 CGLIB 动态代理是基于继承了委托类的子类,通过子类实现代理。
2)JDK 动态代理只能代理实现了接口的类,且只能增强接口中现有的方法;而 CGLIB 可以代理未实现任何接口的类。
3)就二者的效率来说,大部分情况都是 JDK 动态代理的效率更高,随着 JDK 版本的升级,这个优势更加明显。
4. 什么情况下使用动态代理?
1)我们知道, 设计模式的开闭原则,对修改关闭,对扩展开放,在工作中, 经常会接手前人写的代码,有时里面的代码逻辑很复杂不容易修改,那么这时我们就可以使用代理模式对原来的类进行增强。
2)在使用 RPC 框架的时候,框架本身并不能提前知道各个业务方要调用哪些接口的哪些方法 。那么这个时候,就可用通过动态代理的方式来建立一个中间人给客户端使用,也方便框架进行搭建逻辑,某种程度上也是客户端代码和框架松耦合的一种表现。
3)Spring AOP 采用了动态代理模式
静态代理和动态代理对比
1)灵活性 :动态代理更加灵活,不需要必须实现接口,可以直接代理实现类,并且可以不需要针对每个目标类都创建一个代理类。另外,静态代理中,接口一旦新增加方法,目标对象和代理对象都要进行修改,这是非常麻烦的
2)JVM 层面 :静态代理在编译时就将接口、实现类、代理类这些都变成了一个个实际的 .class 字节码文件。而动态代理是在运行时动态生成类字节码,并加载到 JVM 中的。