开发者社区> 问答> 正文

啦啦啦

<div id="cnblogs_post_body" cnblogs-markdown"="">

代理模式


我们知道,Spring AOP的主要作用就是不通过修改源代码的方式、将非核心功能代码织入来实现对方法的增强。那么Spring AOP的底层如何实现对方法的增强?实现的关键在于使用了代理模式
代理模式的作用就是为其它对象提供一种代理,以控制对这个对象的访问,用于解决在直接访问对象时带来的各种问题。代理主要分为两种方式: 静态代理动态代理

静态代理


静态代理主要通过将目标类与代理类实现同一个接口,让代理类持有真实类对象,然后在代理类方法中调用真实类方法,在调用真实类方法的前后添加我们所需要的功能扩展代码来达到增强的目的
示例代码:<code cs"="">/*** 代理类与目标类的共同接口*/public interface Subject {void request();void response();}/*** 目标类*/public class RealSubject implements Subject {@Overridepublic void request() {System.out.println("执行目标对象的request方法......");}@Overridepublic void response() {System.out.println("执行目标对象的response方法......");}}/*** 代理类*/public class ProxySubject implements Subject {private Subject subject;public ProxySubject(Subject subject) {this.subject = subject;}@Overridepublic void request() {System.out.println("before 前置增强");subject.request();System.out.println("after 后置增强");}@Overridepublic void response() {System.out.println("before 前置增强");subject.response();System.out.println("after 后置增强");}}public class Main {public static void main(String[] args) {//目标对象Subject realSubject = new RealSubject();//代理对象 通过构造器注入目标对象Subject proxySubject = new ProxySubject(realSubject);proxySubject.request();proxySubject.response();}}
运行结果:<code erlang"="">before 前置增强执行目标对象的request方法......after 后置增强before 前置增强执行目标对象的response方法......after 后置增强
通过以上的代码示例,我们不难发现静态代理的缺点。假如我们的Subject接口要增加其它的方法,则ProxySubject代理类也必须同时代理这些新增的方法。同时我们也看到,request方法和response方法所织入的代码是一样的,这会使得代理类中出现大量冗余的代码,非常不利于扩展和维护。为了解决静态代理的这些缺陷,于是有了动态代理

动态代理


与静态代理相比,动态代理的代理类不需要程序员自己手动定义,而是在程序运行时动态生成
动态代理可以分为 JDK动态代理CgLib动态代理

1.JDK动态代理


JDK动态代理与静态代理一样,目标类需要实现一个代理接口,它的开发步骤如下:
1.定义一个java.lang.reflect.InvocationHandler接口的实现类,重写invoke方法
2.将InvocationHandler对象作为参数传入java.lang.reflect.Proxy的newProxyInstance方法中
3.通过调用java.lang.reflect.Proxy的newProxyInstance方法获得动态代理对象
4.通过代理对象调用目标方法
示例代码:<code java"="">/*** 自定义InvocationHandler的实现类*/public class JdkProxySubject implements InvocationHandler {private Subject subject;public JdkProxySubject(Subject subject) {this.subject = subject;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("before 前置通知");Object result = null;try {result = method.invoke(subject, args);}catch (Exception ex) {System.out.println("ex: " + ex.getMessage());throw ex;}finally {System.out.println("after 后置通知");}return result;}}public class Main {public static void main(String[] args) {//获取InvocationHandler对象 在构造方法中注入目标对象InvocationHandler handler = new JdkProxySubject(new RealSubject());//获取代理类对象Subject proxySubject = (Subject)Proxy.newProxyInstance(Main.class.getClassLoader(), new Class[]{Subject.class}, handler);//调用目标方法proxySubject.request();proxySubject.response();}}
运行结果:<code erlang"="">before 前置通知执行目标对象的request方法......after 后置通知before 前置通知执行目标对象的response方法......after 后置通知

2.CgLib动态代理


CgLib动态代理的原理是对指定的业务类生成一个子类,并覆盖其中的业务方法来实现代理。它的开发步骤:
1.定义一个org.springframework.cglib.proxy.MethodInterceptor接口的实现类,重写intercept方法
2.获取org.springframework.cglib.proxy.Enhancer类的对象
3.分别调用Enhancer对象的setSuperclass和setCallback方法,使用create方法获取代理对象
4.通过代理对象调用目标方法
示例代码:<code java"="">/*** 自定义MethodInterceptor实现类*/public class MyMethodInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {System.out.println("before 前置通知");Object result = null;try {result = methodProxy.invokeSuper(obj, args);}catch (Exception ex) {System.out.println("ex: " + ex.getMessage());throw ex;}finally {System.out.println("after 后置通知");}return result;}}public class Main {public static void main(String[] args) {//获取Enhancer 对象Enhancer enhancer = new Enhancer();//设置代理类的父类(目标类)enhancer.setSuperclass(RealSubject.class);//设置回调方法enhancer.setCallback(new MyMethodInterceptor());//获取代理对象Subject proxySubject = (Subject)enhancer.create();//调用目标方法proxySubject.request();proxySubject.response();}}
运行结果:<code erlang"="">before 前置通知执行目标对象的request方法......after 后置通知before 前置通知执行目标对象的response方法......after 后置通知

3.两种代理的区别


JDK动态代理和CgLib动态代理的主要区别:
JDK动态代理只能针对实现了接口的类的接口方法进行代理
CgLib动态代理基于继承来实现代理,所以无法对final类、private方法和static方法实现代理

Spring AOP的代理


Spring AOP中的代理使用的默认策略是:
如果目标对象实现了接口,则默认采用JDK动态代理
如果目标对象没有实现接口,则采用CgLib进行动态代理
如果目标对象实现了接口,且强制CgLib代理,则采用CgLib进行动态代理

展开
收起
ldd123 2018-12-21 18:54:22 7136 0
1 条回答
写回答
取消 提交回答
  • Re啦啦啦
    斜体 宋体 汉字 English
    斜体 雅黑 汉字 English
    斜体 楷体 汉字 English
    ​斜体 黑体 汉字 English
    斜体 arial 汉字 English
    斜体 arial black 汉字 English
    斜体 times new roman 汉字 English
    2018-12-28 11:37:51
    赞同 展开评论 打赏
问答分类:
问答地址:
问答排行榜
最热
最新

相关电子书

更多
低代码开发师(初级)实战教程 立即下载
冬季实战营第三期:MySQL数据库进阶实战 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载