浅谈Spring的AOP实现-代理商机制

作者 : 开心源码 本文共3393个字,预计阅读时间需要9分钟 发布时间: 2022-05-12 共207人阅读

说起Spring的AOP(Aspect-Oriented Programming)面向切面编程大家都很熟习(Spring不是这次博文的重点),但是我先提出几个问题,看看同学们能否理解,假如理解的话可以不用继续往下读:

  1. Spring的AOP的实现方式有哪些?

  2. 为什么使用代理商机制?

  3. 它们是怎样实现的?

  4. 它们的区别是什么?

下面进入正题,Spring采用代理商的方式实现AOP,具体采用了JDK的动态代理商和CGLib实现。使用动态代理商和CGLib的目的是在现有类的基础上添加少量功能。简单地将就是有一个Proxy类,实现了原始类的方法,并且在原始类的基础上添加了新的功能。那么这么做可以实现很多功能:

1. 在方法前后进行日志解决。

2. 进行额外的校验,比方参数的验证功能等。

3. 实现少量懒加载,也就是实例化的时候假如不去调用真正的方法的时候,这个类的属性就不会存在(Hibernate有这样相似的功能)。

下面咱们用简单的代码实现它是如何进行代理商的,首先采用的是JDK的动态代理商实现:

定义一个接口:

package com.hqs.proxy; /** * 操作系统光接口 * @author hqs * */public interface OpSystem { public void work();}

定义一个实现类:

package com.hqs.proxy; /** * Mac 的实现 * @author hqs * */public class Mac implements OpSystem { public void work() {        System.out.println("Mac is running");        }}

位置来了,我们通过实现JDK自带的反射机制的包的InvocationHandler来进行反射解决,实现它之后需要实现里边的invoke方法,这个invoke方法里边的参数分别为:代理商类实例,用于调用method的;method参数是实际执行的方法;args所传输的参数数组。

package com.hqs.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class OpHandler implements InvocationHandler {        private final OpSystem ops;         public OpHandler(OpSystem ops) {        this.ops = ops;    }        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        System.out.println("Before system running");        method.invoke(ops, args);        System.out.println("After system running");        return null;    }        public static void main(String[] args) {        Mac mac = new Mac();        OpHandler oph = new OpHandler(mac);        OpSystem os = (OpSystem)Proxy.newProxyInstance(oph.getClass().getClassLoader(),                mac.getClass().getInterfaces(), oph);                os.work();        System.out.println(os.getClass());    }    }输出:Before system runningMac is runningAfter system runningclass com.sun.proxy.$Proxy0

而后看到里边的main方法中,代理商类实例化对象的方法Proxy.newProxyInstance,这个是JDK的反射方法去实例化代理商类,其中有三个参数分别是,去实例化代理商类的class loader;所代理商的类的所有接口Class数组;hander解决类,用于做阻拦使用的类。最后我输出了一下os.getClass(),大家可以看到的是代理商类的实例,而不是真正代理商类的实例,这么做的好处就是很方便的复用这个代理商类,比方你可以重复调用它而不用去重新实例化新类,再一点就是你可以针对不同的方法进行阻拦,比方你可以method.getName()去判断调用的方法名字是什么从而更细粒度的阻拦方法。咱们继续看用CGLib的实现:

package com.hqs.proxy;import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;/** * CGLib Interceptor用于方法阻拦 * @author hqs * */public class CGLibInterceptor implements MethodInterceptor {        private final Mac mac;        public CGLibInterceptor(Mac mac) {        this.mac = mac;    }    @Override    public Object intercept(Object obj, Method method, Object[] args,             MethodProxy methodProxy) throws Throwable {        System.out.println("Before system running");        method.invoke(mac, args);        System.out.println("After system running");        return null;    }        public static void main(String[] args) {        Mac mac = new Mac(); //实例而非接口        MethodInterceptor handler = new CGLibInterceptor(mac);        Mac m = (Mac)Enhancer.create(mac.getClass(), handler);        m.work();        System.out.println(m.getClass());            }}输出:Before system runningMac is runningAfter system runningclass com.hqs.proxy.Mac$$EnhancerByCGLIB$$1f2c9d4a

首先需要引入cglib包,而后才能使用他的MethodInterptor,它也采用method.invoke实现对代理商类的调用。它的代理商类创立采用Enhancer的create方法,其中传入了需要创立的类的class,以及Callback对象,由于MethodInterceptor继承了Callback对象。用于指向方法前后进行调用的类。

public interface MethodInterceptorextends Callback

这是这两个类的基本实现,那么它们的区别是什么呢?

  1. JDK的动态代理商只能针对接口和其实现类,假如没有实现类只有接口也是可以代理商的,这里就不在举例了。为什么JDK的动态代理商只针对接口代理商,由于这个是JDK的定义。
  2. 假如不针对接口实现动态代理商那就用到了CGLib了,也就是可以针对具体的类进行代理商,大家可以参考我的代码。

这些是它们的根本区别,但是Spring推荐使用JDK的动态代理商,面向接口去编程。使用CGLib去做代理商的时候需要注意,它生成的代理商类存放在JVM的Perm space里边,那么是不是生成的代理商对象就不进行回收了?其实不是的,不经常回收但是还是回收的,当类被加载,加载类的classLoader什么时候变得对垃圾回收可用的时候才进行回收。也就是你自己创立所有类移除classLoader之后,那么这个classLoader就会被回收,一般非常精通CGLib的话可以进行这块内容深入开发,由于它可以做出amzing的事情假如你熟习的话。

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 浅谈Spring的AOP实现-代理商机制

发表回复