做一个合格的程序猿之浅析Spring AOP源码(十四) 分析ProxyFactoryBean
2016-03-24 15:20
1046 查看
Spring AOP 的实现设计图:
(图片来自《Spring技术内幕:深入分析Spring架构和设计原理》)
最基本的实现有三个,AspectJProxyFactory.java ,ProxyFactory.java ProxyFactoryBean这三个,他们的父类ProxyCreatorSupport只是给了他们一些通用的AOP的实现,最为核心的就是怎么生成代理对象就是在该方法中实现的,如图ProxyCreatorSupport.java核心代码:
这就是生成代理的入口,你会发现入参是this,其实传入的就是this的父类AdvisedSupport.java中的advisor等生成代理的核心参数
而AdvisedSupport.java和ProxyConfig.java这2个类就是他们的所共用的数据。例如AOP最核心的通知器advisors,interfaces等等。如图AdvisedSupport.java中核心数据,这些数据就是生成代理对象的关键
好了,到现在spring AOP实现的基本架构思维就是AspectJProxyFactory.java ,ProxyFactory.java ProxyFactoryBean这三个最基本的类要共同要做的事情就是构建advisors,然后就是用自己的方式将spring生成的bean替换成代理对象,而他们的父类就是帮助他们完成代理对象的生成
现在我们先看下三个子类中的ProxyFactoryBean的源代码:
首先看下ProxyFactoryBean.java的继承关系:
好了,继承自ProxyCreatorSupport这个我们刚刚上面讲过了,实现了三个接口,这三个接口的作用,我们在前面的章节都一一分析过
我们逐一看实现这三个接口的意义:
①实现BeanClassLoaderAware这个接口,我们以前分析过,这个接口的实现会知道当前spring容器的类加载器是什么,那么为什么需要实现这个接口呢,因为上一节将jdk的动态代理的时候,知道创建一个proxy,需要三个参数:
第一个参数就是classloader,也就说需要一个加载器,所以此处获取容器的加载器来给jdk的动态代理时的classloader用,具体实现如下:
setBeanClassLoader这个方法就是BeanClassLoaderAware的具体实现,而setProxyClassLoader这个方法,则给使用者提供了setter注入的形式来修改容器默认提供的classloader
②实现BeanFactoryAware这个接口,也是很重要的,实现BeanFactoryAware这个接口,最重要的就是可以获取当前容器的beanfactory,不错,这个ProxyFactoryBean这个的确是生成代理对象的,但是如果连对象还没有生成,何来生成代理,一屋不扫何以扫天下,生成代理之前,容器必须把被代理的对象实例化好~,所以只要拿到beanfactory,何愁实例化不了对象:
③最核心的实现FactoryBean,ProxyFactoryBean看名字也就知道这是一个FactoryBean,factoryBean以前讲过,它的核心方法是getObject(),该方法将会返回一个Object
也就说有可能这个Object就是我们需要的代理对象,打开源码:
好了,不出所料,的确是在这边初始化和返回的代理对象
到目前为止,我们已经简单的了解了ProxyFactoryBean.java的基本结构和一些细节
下面我们来用ProxyFactoryBean来实现一个Spring AOP的功能(不是很常用)
我们的例子背景是这样的:我们选用jdk的动态代理来实现AOP,我们在调用目标对象之前,要进行2个操作,第一就是记录该方法调用的次数 ,第二就是进入这个方法之前,打一个logger
首先,我们先定义目标对象和目标对象实现的接口
MethodInvokeCountAdvice.java
MethodLoggerAdvice.java
proxy-factory-bean.xml
运行结果:
好了,代码写完了,分析还没有完
我们接着上文ProxyFactoryBean.java中的getObject分析
测试代码中
我们来分析一下getObject方法中的initializeAdvisorChain()看看具体实现:
这一段就是核心代码,其实就是很简单,就是我们在spring的配置文件中配置的
这2个“拦截器”先用beanfactory(BeanFactoryAware接口的作用体现了)去实例化两个继承Advice(MethodBeforeAdvice继承于Advice),然后将其封装一下,加入advisor的链中
我们再看addAdvisorOnChainCreation这个方法
用beanfactory实例化好的bean去构造一个advisor,然后加入advisor链中
接着看namedBeanToAdvisor这个方法
好了,我们看advisorAdapterRegistry这个对象是如何去编制advisor的
接着看wrap这个方法
这边还有2个点要解释:
1)DefaultPointcutAdvisor这个是什么东西:还记得我们AOP首讲,我们讲Advisor(通知器)就是由两部分组成的,第一部分是advice(通知)也就是我们在切面要做的事情,还有一个就是在哪切,对pointcut,就是这个概念,其实这边就是创建了一个万能匹配的pointcut和我们传入的advice构建了advisor
所谓万能就是该advice可以切任何方法(这个后面还会讲到)
2)this.adapters这是什么鬼?
看图:
原来就是继承MethodBeforeAdvice AfterReturningAdviceAdapter或者ThrowsAdviceAdapter的子类,而我们的MethodInvokeCountAdvice和MethodLoggerAdvice正好继承MethodBeforeAdvice,所以如果大家debug的话,就在这边全部转化为advisor了
好了,休息一下,到目前为止,我们初始化好了advisor链,这个生成代理的核心数据
我们接着看:getObject剩下的方法
因为我们默认是单例,我们看243行
关于createAopProxy其实很简单,根据代理的目标对象是否实现了接口,来返回JdkDynamicAopProxy的动态代理或者cglib的代理,并且传入core(advisor)这个非常非常重要(JdkDynamicAopProxy这个实现了InvocationHandler,要实现invoke的关键就是传入的advisor)
最后再看getProxy这个方法
好了,我们传入的classloader有效果了,这就是实现BeanClassLoaderAware的意义
好了,到此为止,代理对象终于生成了~,然后返回了,结束了
结束了吗?结束了,真的结束了吗?没有,我们还要接着分析传入的advisor在invoke怎么使用的~下次一起研究吧~
这篇blog历时 3个小时,吐血之作,希望大家能看懂~
(图片来自《Spring技术内幕:深入分析Spring架构和设计原理》)
最基本的实现有三个,AspectJProxyFactory.java ,ProxyFactory.java ProxyFactoryBean这三个,他们的父类ProxyCreatorSupport只是给了他们一些通用的AOP的实现,最为核心的就是怎么生成代理对象就是在该方法中实现的,如图ProxyCreatorSupport.java核心代码:
这就是生成代理的入口,你会发现入参是this,其实传入的就是this的父类AdvisedSupport.java中的advisor等生成代理的核心参数
而AdvisedSupport.java和ProxyConfig.java这2个类就是他们的所共用的数据。例如AOP最核心的通知器advisors,interfaces等等。如图AdvisedSupport.java中核心数据,这些数据就是生成代理对象的关键
好了,到现在spring AOP实现的基本架构思维就是AspectJProxyFactory.java ,ProxyFactory.java ProxyFactoryBean这三个最基本的类要共同要做的事情就是构建advisors,然后就是用自己的方式将spring生成的bean替换成代理对象,而他们的父类就是帮助他们完成代理对象的生成
现在我们先看下三个子类中的ProxyFactoryBean的源代码:
首先看下ProxyFactoryBean.java的继承关系:
好了,继承自ProxyCreatorSupport这个我们刚刚上面讲过了,实现了三个接口,这三个接口的作用,我们在前面的章节都一一分析过
我们逐一看实现这三个接口的意义:
①实现BeanClassLoaderAware这个接口,我们以前分析过,这个接口的实现会知道当前spring容器的类加载器是什么,那么为什么需要实现这个接口呢,因为上一节将jdk的动态代理的时候,知道创建一个proxy,需要三个参数:
第一个参数就是classloader,也就说需要一个加载器,所以此处获取容器的加载器来给jdk的动态代理时的classloader用,具体实现如下:
setBeanClassLoader这个方法就是BeanClassLoaderAware的具体实现,而setProxyClassLoader这个方法,则给使用者提供了setter注入的形式来修改容器默认提供的classloader
②实现BeanFactoryAware这个接口,也是很重要的,实现BeanFactoryAware这个接口,最重要的就是可以获取当前容器的beanfactory,不错,这个ProxyFactoryBean这个的确是生成代理对象的,但是如果连对象还没有生成,何来生成代理,一屋不扫何以扫天下,生成代理之前,容器必须把被代理的对象实例化好~,所以只要拿到beanfactory,何愁实例化不了对象:
③最核心的实现FactoryBean,ProxyFactoryBean看名字也就知道这是一个FactoryBean,factoryBean以前讲过,它的核心方法是getObject(),该方法将会返回一个Object
也就说有可能这个Object就是我们需要的代理对象,打开源码:
好了,不出所料,的确是在这边初始化和返回的代理对象
到目前为止,我们已经简单的了解了ProxyFactoryBean.java的基本结构和一些细节
下面我们来用ProxyFactoryBean来实现一个Spring AOP的功能(不是很常用)
我们的例子背景是这样的:我们选用jdk的动态代理来实现AOP,我们在调用目标对象之前,要进行2个操作,第一就是记录该方法调用的次数 ,第二就是进入这个方法之前,打一个logger
首先,我们先定义目标对象和目标对象实现的接口
<span style="font-size:14px;">package org.study.spring.aop.proxyfactorybean; public interface IBussinessService { public void bussiness(); } </span>BussinessServiceImpl.java
<span style="font-size:14px;">package org.study.spring.aop.proxyfactorybean; public class BussinessServiceImpl implements IBussinessService{ public void bussiness() { System.out.println("I do someting"); } } </span>然后定义2个通知(切面要干的事情,也就是我们这边的方法调用个数统计和logger处理)
MethodInvokeCountAdvice.java
<span style="font-size:14px;">package org.study.spring.aop.proxyfactorybean; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import org.springframework.aop.MethodBeforeAdvice; /** * 方法调用次数的统计 * @author lyncc * */ public class MethodInvokeCountAdvice implements MethodBeforeAdvice{ private Map<String,Integer> maps = new HashMap<String,Integer>(); public void before(Method method, Object[] args, Object target) throws Throwable { String name = method.getName(); Integer count = maps.get(name); count = count == null ? 1 : count+1; maps.put(name, count); System.out.println("调用了:"+maps.get(name)+"次"); } } </span>
MethodLoggerAdvice.java
<span style="font-size:14px;">package org.study.spring.aop.proxyfactorybean; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; /** * 进入方法是的logger统计 * @author lyncc * */ public class MethodLoggerAdvice implements MethodBeforeAdvice{ public void before(Method method, Object[] args, Object target) throws Throwable { String name = method.getName(); System.out.println("method name "+ name +" now is invoke"); } } </span>spring的配置文件
proxy-factory-bean.xml
<span style="font-size:14px;"><?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd"> <bean id="methodCount" class="org.study.spring.aop.proxyfactorybean.MethodInvokeCountAdvice"/> <bean id="methodLogger" class="org.study.spring.aop.proxyfactorybean.MethodLoggerAdvice"/> <bean id="bussinessService" class="org.study.spring.aop.proxyfactorybean.BussinessServiceImpl"/> <bean id="methodProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>org.study.spring.aop.proxyfactorybean.IBussinessService</value> </property> <property name="target"> <ref bean="bussinessService"/> </property> <property name="interceptorNames"> <list> <value>methodCount</value> <value>methodLogger</value> </list> </property> </bean> </beans> </span>测试代码:
<span style="font-size:14px;">package org.study.spring.aop.proxyfactorybean; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestProxyFactoryBean { @Test public void test(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("proxy-factory-bean.xml"); IBussinessService bussinessServiceImpl = applicationContext.getBean("methodProxy",IBussinessService.class); bussinessServiceImpl.bussiness(); } } </span>
运行结果:
好了,代码写完了,分析还没有完
我们接着上文ProxyFactoryBean.java中的getObject分析
测试代码中
<span style="font-size:14px;">IBussinessService bussinessServiceImpl = applicationContext.getBean("methodProxy",IBussinessService.class);</span>其实就是调用ProxyFactoryBean的getObject方法,而这个方法返回一个代理,就会有了如上的运行结果,感觉简单粗暴
我们来分析一下getObject方法中的initializeAdvisorChain()看看具体实现:
这一段就是核心代码,其实就是很简单,就是我们在spring的配置文件中配置的
这2个“拦截器”先用beanfactory(BeanFactoryAware接口的作用体现了)去实例化两个继承Advice(MethodBeforeAdvice继承于Advice),然后将其封装一下,加入advisor的链中
我们再看addAdvisorOnChainCreation这个方法
用beanfactory实例化好的bean去构造一个advisor,然后加入advisor链中
接着看namedBeanToAdvisor这个方法
好了,我们看advisorAdapterRegistry这个对象是如何去编制advisor的
接着看wrap这个方法
这边还有2个点要解释:
1)DefaultPointcutAdvisor这个是什么东西:还记得我们AOP首讲,我们讲Advisor(通知器)就是由两部分组成的,第一部分是advice(通知)也就是我们在切面要做的事情,还有一个就是在哪切,对pointcut,就是这个概念,其实这边就是创建了一个万能匹配的pointcut和我们传入的advice构建了advisor
所谓万能就是该advice可以切任何方法(这个后面还会讲到)
2)this.adapters这是什么鬼?
看图:
原来就是继承MethodBeforeAdvice AfterReturningAdviceAdapter或者ThrowsAdviceAdapter的子类,而我们的MethodInvokeCountAdvice和MethodLoggerAdvice正好继承MethodBeforeAdvice,所以如果大家debug的话,就在这边全部转化为advisor了
好了,休息一下,到目前为止,我们初始化好了advisor链,这个生成代理的核心数据
我们接着看:getObject剩下的方法
因为我们默认是单例,我们看243行
关于createAopProxy其实很简单,根据代理的目标对象是否实现了接口,来返回JdkDynamicAopProxy的动态代理或者cglib的代理,并且传入core(advisor)这个非常非常重要(JdkDynamicAopProxy这个实现了InvocationHandler,要实现invoke的关键就是传入的advisor)
最后再看getProxy这个方法
好了,我们传入的classloader有效果了,这就是实现BeanClassLoaderAware的意义
好了,到此为止,代理对象终于生成了~,然后返回了,结束了
结束了吗?结束了,真的结束了吗?没有,我们还要接着分析传入的advisor在invoke怎么使用的~下次一起研究吧~
这篇blog历时 3个小时,吐血之作,希望大家能看懂~
相关文章推荐
- 黑马程序员_模拟Spring可配置的AOP框架
- 浅谈spring——自动创建代理(八)
- 用ProxyFactoryBean创建AOP代理
- Spring源码-AOP(五)-ProxyFactoryBean
- Spring AOP API
- Spring Mvc那点事---(30)Spring Mvc传统AOP自动代理实现
- Spring Mvc那点事---(29)Spring Mvc基于ProxyFactoryBean的传统AOP使用正则拦截
- Spring Mvc那点事---(28)Spring Mvc基于ProxyFactoryBean的传统AOP
- Spring3系列:Spring AOP——Advice
- AOP第二部分应用-事务管理
- Spring源码阅读-使用ProxyFactoryBean实现AOP
- Spring基于ProxyFactoryBean创建AOP代理
- Java并发编程:Callable、Future和FutureTask
- java中的volatile和synchronized
- 记录Java的垃圾回收机制和几种引用
- JAVA 集合之MAP
- java ClassNotFoundException和NoClassDefFoundException的差别
- Eclipse中使用Android5.0新特性CardView
- 深入理解Java内存模型(一)——基础
- java quartz 中的时间格式