先介绍下什么是SpringAOP,Aspect切面, Oriented面向, Programming编程,连起来就是面向切面编程。面向切面编程及横向重复,纵向抽取,什么意思呢?去掉横向重复代码,纵向抽取公共接口。也就是所说面向接口编程,请看下图
aop结构 PlaceOrder等几个功能,他们都有一段公共代码,日志,缓存,事务控制一定是相同的,不同的只是业务逻辑上有差异。他们使用同一个日志,缓存,事务控制,一个东西解决一类问题,这就是AOP。Spring的AOP底层通过动态代理实现,Spring能够为容器中管理的对象生成动态代理对象。我们如果使用JDK提供的方法实现动态代理是非常复杂的,Spring对该方法进行了封装,我们只需要通过对applicationContext中的标签进行配置,即可实现动态代理。Spring提供的实现动态代理有两种方式,
一个是被代理对象需要实现JDK提供的动态代理接口。通过cglib的jar包实现动态代理,该方法只需要对目标对象继承即可
Spring支持两种方法,那么我们在使用spring进行动态代理时究竟使用的哪一种方法呢?spring优先支持实现接口的方式,如果没有接口则使用cglib方式。下面我们看一看这两种方法有什么区别。 下面我们通过JDK实现动态代理,需求是如下:有一个服务层对象ServiceImpl 如下
他们有三个方法,增删改。我们知道执行增删改操作时需要开启事务,提交事务。接下来我们通过动态代理的方式为这三个方法织如事务控制。以伪代码的形式。因为JDK动态代理需要使用接口,那我们为他创建一个接口。
接下来我们使用ServiceImpl的代理工厂生成代理对象,创建代理工厂类ServiceProxyFactory如下
第一眼看上去可能有点混乱,一步一步来,既然代理工厂生成代理对象,我们首先创建一个getInstance方法返回代理对象。JDK提供了一个Proxy下的一个静态方法newProxyInstance(),帮助我们生成代理对象。该方法需要传入三个参数,
第一个参数为的类加载器, Java有三种类加载器,这里不做重点描述,提供任意一个类的class对象有一个方法getClassLoader()返回一个classLoader对象,源码中该对象是被final修饰的,防止黑客修改类加载以达到不可告人的目的,sun公司在jvm中有着大量的代码维护反射和类加载器,防止被坏人利用。第二个参数为Class<?>[] 类型数组,什么意思呢,这里可以传入任意的Class类,那么如何获取Class类数组呢,通过任意的class对象getInterfaces()方法可以获得Class[],但是这里我们必须传入需要被代理对象的class对象。为什么呢,前面说过需要的参数为Class<?>[],由于Class类实现了Type接口,在生成代理对象的过程中Class数组的泛型类型?会被替换成传入的class类型的类型,就是说我传入一个A.class.getInterfaces(),进入到底层时会变成Class<A>[]。因为我们这里必须传入被代理对象的class的Class[]。第三个参数需要传入一个执行器对象,该执行器必须符合InvocationHandler接口规范,就是实现这个接口的invoke方法。该方法同样要求传入三个参数,
参数一:局部变量:被代理对象实例参数二:Method类型对象,该参数有JDK的Proxy负责传入,method为我们被代理对象的执行方法对象。参数三:Object[],它是被执行方法参数,在方法执行中参数由Proxy负责传入至Object[]中。
那么第3个参数我们实质只需要传入被代理对象实例即可。那么传入被代理方法对象有两种方法,一个是构造器传入,另一个是set方法传入,也可以使用spring注入。我们使用method对象调用invoke()方法,该方法需要两个参数,第一个参数:全局变量的被代理对象实例,这里与全局变量被代理对象实例做一个区分帮助大家更清晰的理解。看图中,被代理对象实例由set方法传入全局变量si,然后si作为InvocationHandler的实现类下的invoke方法的参数method对象下的invoke方法参数传入。 这个参数也就是invoke的调用对象。第二个参数就是被代理对象实例调用的方法参数,也就是上方的参数三Object[]。该invoke方法返回一个Object对象,因为我使用的自动生成变量所以这个Object对象名也是invoke,不好意思!最后我们将该对象invoke返回即可。这样就可以创建一个代理对象了,我们使用动态代理的目的是在原编码不变的基础上对方法进行增强,请看下图
该方法相当于对图中三行代码进行一个封装,封装成了一个方法。执行顺序自上而下。下面看一下如果使用代理对象调用被代理对象的方法
1先创建一个被代理对象实例,用于传入代理对象工厂。
2然后创建代理对象工厂实例,为内部的被代理对象赋值。
3代理对象工厂实例调用getInstance方法生成代理对象
4代理对象调用增强后的方法
下面请看执行结果
执行的是我们增强后的方法,这就说明代理对象的作用已经达到了。这就是JDK提供的动态代理。下面我们看看由第三方人员提供的拓展类库cglib是如何实现动态代理的。
这就是cglib创建动态代理的代码,具体就不详细介绍了,只需了解即可。下面看执行代码
结果还需要看吗?
可以看到cglib的代理方式不需要传入被代理对象实例即可完成动态代理。cglib和jdk代理有什么区别呢?jdk的代理对象与被代理对象实现了同一接口,底层通过clone()方法,将实现类的方法复制过来在按照invoke中的配置对方法进行增强。而cglib代理则是代理对象继承了被代理对象的方法,然后自身进行增强。这两种代理思想在外来的自动生成代码方向会经常被使用,实现完全体代码的复用性。以上就是springAOP的实现原理了。
如果您认为本文对您产生了积极的影响请分享给其他人,我们虽然不具备发明计算机的能力但是我们可以成为更好的计算机使用使用者,cn互联网前进的每一步,都有你的一步!关注作者,每天都有最新的互联网技术,纯原创文章精心手写,能扩展的地方我都尽量扩展,大家有遇到的问题也可以找我帮助解决在评论区留言即可,让我们一起进步,感谢!