相关背景及资源:html
曹工说Spring Boot源码(1)-- Bean Definition究竟是什么,附spring思惟导图分享java
曹工说Spring Boot源码(2)-- Bean Definition究竟是什么,我们对着接口,逐个方法讲解git
曹工说Spring Boot源码(3)-- 手动注册Bean Definition不比游戏好玩吗,咱们来试一下spring
曹工说Spring Boot源码(4)-- 我是怎么自定义ApplicationContext,从json文件读取bean definition的?express
曹工说Spring Boot源码(5)-- 怎么从properties文件读取beanjson
曹工说Spring Boot源码(6)-- Spring怎么从xml文件里解析bean的数组
曹工说Spring Boot源码(7)-- Spring解析xml文件,到底从中获得了什么(上)数据结构
曹工说Spring Boot源码(8)-- Spring解析xml文件,到底从中获得了什么(util命名空间)app
曹工说Spring Boot源码(9)-- Spring解析xml文件,到底从中获得了什么(context命名空间上)ide
曹工说Spring Boot源码(10)-- Spring解析xml文件,到底从中获得了什么(context:annotation-config 解析)
曹工说Spring Boot源码(11)-- context:component-scan,你真的会用吗(此次来讲说它的奇技淫巧)
曹工说Spring Boot源码(12)-- Spring解析xml文件,到底从中获得了什么(context:component-scan完整解析)
曹工说Spring Boot源码(13)-- AspectJ的运行时织入(Load-Time-Weaving),基本内容是讲清楚了(附源码)
曹工说Spring Boot源码(14)-- AspectJ的Load-Time-Weaving的两种实现方式细细讲解,以及怎么和Spring Instrumentation集成
曹工说Spring Boot源码(15)-- Spring从xml文件里到底获得了什么(context:load-time-weaver 完整解析)
曹工说Spring Boot源码(16)-- Spring从xml文件里到底获得了什么(aop:config完整解析【上】)
曹工说Spring Boot源码(17)-- Spring从xml文件里到底获得了什么(aop:config完整解析【中】)
工程结构图:
本篇是接着前两篇讲的,为了不没必要要的重复,请你们先看下。
曹工说Spring Boot源码(16)-- Spring从xml文件里到底获得了什么(aop:config完整解析【上】)
曹工说Spring Boot源码(17)-- Spring从xml文件里到底获得了什么(aop:config完整解析【中】)
本篇主要讲解spring如何在bean生成过程当中,完成“狸猫换太子”操做的。(利用代理对象,替换ioc容器中的原有bean)。
spring解析的xml以下:
<!--目标对象--> <bean id="performer" class="foo.Performer"/> <!--切面--> <bean id="performAspect" class="foo.PerformAspect"/> <!--配置切入点--> <aop:config> <aop:pointcut id="mypointcut" expression="execution(public * foo.Perform.sing(..))"/> <aop:aspect id="myAspect" ref="performAspect"> <aop:after method="afterPerform" pointcut-ref="mypointcut"/> </aop:aspect> </aop:config>
经前文的理解,总共生成了以下几个bean definition。
bean definition 中bean class | 备注 |
---|---|
PerformAspect | 通知 |
Performer | 要切的目标 |
AspectJExpressionPointcut | 切点,即
|
org.springframework.aop.aspectj.AspectJPointcutAdvisor | advisor,解析
|
AspectJAwareAdvisorAutoProxyCreator | 实现了BeanPostProcessor接口,解析<aop:config> 获得 |
解析xml、注解,经过各类渠道,获得bean definition;
从bean definition集合中,找出bean class实现了BeanFactoryPostProcessor接口的子集,而后经过getBean来获取这部分特殊的bean,而后依次调用其postProcessBeanFactory方法
来对其他的bean definition进行处理;
public interface BeanFactoryPostProcessor { /** * Modify the application context's internal bean factory after its standard * initialization. All bean definitions will have been loaded, but no beans * will have been instantiated yet. This allows for overriding or adding * properties even to eager-initializing beans. * @param beanFactory the bean factory used by the application context * @throws org.springframework.beans.BeansException in case of errors */ void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory); }
从bean definition集合中,找出bean class实现了BeanPostProcessor接口的子集,而后经过getBean来获取这部分特殊的bean,而后保存起来。
找出不具备特殊功能的(没实现BeanFactoryPostProcessor,也没实现BeanPostProcessor)bean definition 集合,再过滤出单例bean,且lazy-init属性为false(说明要在spring容器初始化过程当中,实例化的bean)的这部分,做为子集;而后依次调用其getBean方法。
以上就是spring比较粗的流程,固然,不少细节没说,不过核心流程是这样的。
在前面的spring流程中,第三步,就会去查找实现了BeanPostProcessor的bean definition集合,其中,就会包含AspectJAwareAdvisorAutoProxyCreator 这个bean definition;而后经过getBean方法,将这个bean definition实例化为bean。(这个过程,相似于经过class来建立对象)
这个步骤的具体实现入口在:
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); /** * 配置beanFactory */ prepareBeanFactory(beanFactory); try { postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // 入口在这里!这里面会去 getBean registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); /** * 这里对单例bean、且lazy-init=false进行实例化 */ finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } } }
具体跟进去后,在以下位置,809行,就经过getBean,获取到了AspectJAwareAdvisorAutoProxyCreator这个bean了:
在“spring大体启动流程”中的第四步,去预先实例化bean时,会进入如下逻辑:
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { ... try { ... // Check for listener beans and register them. registerListeners(); /** * 入口在这里。这里对单例bean、且lazy-init=false进行实例化 */ finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } } }
而后会进入如下逻辑:
org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons public void preInstantiateSingletons() throws BeansException { if (this.logger.isInfoEnabled()) { this.logger.info("Pre-instantiating singletons in " + this); } // 其中 this.beanDefinitionNames 保存了全部的bean definition名称 for (String beanName : this.beanDefinitionNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); // 实例化那些:非抽象、单例、非lazy-init的bean definition if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { ... if (isEagerInit) { getBean(beanName); } } else { getBean(beanName); } } } }
因此,这里就是对那些:非抽象、单例、非lazy-init的bean definition 进行实例化。
咱们这里,你们看下当前容器中包含的所有的bean definition:
我这边的demo,第一个要实例化的bean,就是performer。在getBean()处理performer这个bean的过程当中,会经历如下的流程:
其中,AspectJAwareAdvisorAutoProxyCreator 做为beanPostProcessor,在实例化performer这个bean时,有两个时间点参与进来。
哪两个时间点呢,你们再看看,AspectJAwareAdvisorAutoProxyCreator 的类图:
其实它不止实现了BeanPostProcessor
接口,它还实现了InstantiationAwareBeanPostProcessor
接口。这个多出来的接口,干吗的?你们看看它的方法就知道了:
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor { // 注意,before Instantiation的意思是,实例化以前调用 Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException; // 这个,实例化以后调用 boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException; ...无关方法 }
因此,InstantiationAwareBeanPostProcessor扩展了两个时间点出来,一个是实例化前,一个是实例化后。
什么叫实例化?把一个对象new出来,通俗来说,就叫作实例化。
在spring的getBean流程里,实例化确定是早于初始化的。因此,一个bean,会经历以下顺序(你们直接看前面点的图,更清晰):
InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation;
根据bean definition来实例化,假设bean class为A,bean definition中的constructorArgumentValues参数,若是为空,则使用A的默认构造函数;若是constructorArgumentValues有值,表示:在此以前,须要先获取到相应的构造函数值,才能去反射经过构造器来建立对象
这里面,会涉及到bean的递归调用。
好比,之前一篇和开头提到的,AspectJPointcutAdvisor 这个bean definition来讲,其中它的构造函数,就要求一个AbstractAspectJAdvice 对象:
public AspectJPointcutAdvisor(AbstractAspectJAdvice advice) { Assert.notNull(advice, "Advice must not be null"); this.advice = advice; this.pointcut = advice.buildSafePointcut(); }
那AbstractAspectJAdvice 这个对象要怎么生成,这个在咱们的场景下,是被抽象成一个内部bean的,bean class为AspectJAfterAdvice。AspectJAfterAdvice这个类呢,构造函数又是下面这样的:
public AspectJAfterAdvice( Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) { super(aspectJBeforeAdviceMethod, pointcut, aif); }
又依赖了一堆其余的参数,这三个参数,其中2个也是被定义为了内部bean definition
,一个为bean 引用。(具体请参照前一篇)。
因此,这个bean的实例化过程就相对繁琐,涉及到bean的递归生成。
InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation;
属性注入,此时是autowired等发挥做用的地方;
BeanPostProcessor的postProcessBeforeInitialization
BeanPostProcessor#postProcessAfterInitialization
这里面6个步骤,AspectJAwareAdvisorAutoProxyCreator 在其中两个地方,实现了本身的业务逻辑。
具体实如今:
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { Object cacheKey = getCacheKey(beanClass, beanName); if (beanName == null || !this.targetSourcedBeans.contains(beanName)) { if (this.advisedBeans.containsKey(cacheKey)) { return null; } // 入口在这:shouldSkip if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return null; } } // Create proxy here if we have a custom TargetSource. // Suppresses unnecessary default instantiation of the target bean: // The TargetSource will handle target instances in a custom fashion. if (beanName != null) { TargetSource targetSource = getCustomTargetSource(beanClass, beanName); if (targetSource != null) { this.targetSourcedBeans.add(beanName); Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource); Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } } return null; }
以上逻辑中,咱们须要进入到shouldSkip方法,重点是下面的findCandidateAdvisors方法:
@Override protected boolean shouldSkip(Class beanClass, String beanName) { // TODO: Consider optimization by caching the list of the aspect names /** * 这里调用了父类中实现的findCandidateAdvisors,获取候选的advisor bean;这里也是真正根据bean * definition去生成advisor bean的地方 */ List<Advisor> candidateAdvisors = **findCandidateAdvisors()**; for (Advisor advisor : candidateAdvisors) { /** * 若是当前要检查的bean,就是advisor里的通知类,则跳过 */ if (advisor instanceof AspectJPointcutAdvisor) { if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) { return true; } } } return super.shouldSkip(beanClass, beanName); }
下面会找出ioc容器中,实现了Advisor接口的bean definition,并所有实例化。Advisor是什么?
咱们前面提到的AspectJPointcutAdvisor,就实现了这个接口。
public List<Advisor> findAdvisorBeans() { // Determine list of advisor bean names, if not cached already. String[] advisorNames = null; synchronized (this) { advisorNames = this.cachedAdvisorBeanNames; if (advisorNames == null) { // 1.从spring容器查找Advisor类型的bean definition advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Advisor.class, true, false); this.cachedAdvisorBeanNames = advisorNames; } } if (advisorNames.length == 0) { return new LinkedList<Advisor>(); } List<Advisor> advisors = new LinkedList<Advisor>(); for (String name : advisorNames) { if (isEligibleBean(name) && !this.beanFactory.isCurrentlyInCreation(name)) { // 遍历那些bean definition,经过getBean,来获取bean advisors.add(this.beanFactory.getBean(name, Advisor.class)); } } return advisors; }
再啰嗦一句,advisor差很少是aop的核心数据结构,你经过Aspect注解方式,最终也是解析为一个个的Advisor。
一个切点+一个切面方法 基本就等于一个Advisor对象。好比,一个before方法,算一个;在一个after,又算一个。
这是第二个时间点,在这里,检查bean要不要被拦截,生成代理。你们能够简单理解,由于每一个bean的建立过程,都要被它处理,它呢,就会检查,这个bean,是否是匹配切点,若是匹配,就生成代理。
举个例子,之前看过一个小说,是京官去很偏远的地方上任,路上被人杀了,并被另一我的拿了印章,到了地方,靠着印章,招摇撞骗,当了地方官。假设切点是:每一个过路人;切面:偷天换日。那这个PostProcessor,就是那伙人,拦截每一个过路人,并判断是否是那个倒霉的京官,若是是,就杀了而且换我的拿了印章去当地方官。
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (!this.earlyProxyReferences.contains(cacheKey)) { // 返回生成的代理对象 return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }
这里的下面这句,bean是原始bean,wrapIfNecessary返回的,就做为最终的bean。若是你不须要切这个bean,那你就返回它自己;若是要代理,你就返回另外一个代理对象便可。
return wrapIfNecessary(bean, beanName, cacheKey);
咱们仔细看这个方法内部:
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { if (beanName != null && this.targetSourcedBeans.contains(beanName)) { return bean; } if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // 获取前面2.1章节里的Advisor对象,并保存到Object[] specificInterceptors 里 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != null) { this.advisedBeans.put(cacheKey, Boolean.TRUE); // 建立代理,注意,Advisor数组,已经被传进去了。 Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
你们看上面的注释吧,这里获取了ioc容器里的Advisor对象,若是advisor数组不为null,则建立代理,并返回代理。你们看下面的debug图就理解了。
建立代理的过程就简单了,基本就是:有接口就搞个jdk 动态代理,不然就cglib代理。
我作了个小测试,
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { if (bean.getClass().getName().equals("foo.Performer")) { return "hahha"; } ...其余代码省略,主要加了上面那个if return bean; }
public final class Main { public static void main(String[] args) { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( "context-namespace-test-aop.xml"); Perform performer = (Perform) ctx.getBean(Perform.class); performer.sing(); } }
而后在倒数第二行,获取Perform类型的bean时,报错了。为啥呢?由于原本foo.Performer实现了Perform接口,但如今,我用一个string做为代理返回去了,因此就没有实现Perform接口的bean存在了
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [foo.Perform] is defined at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:296) at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1196) at foo.Main.main(Main.java:23)
spring aop这个东西,仍是不简单,我原本打算这一讲把所有内容说清楚;但如今发现,建立代理这部分,仍是得放到下一篇。
至于源码那些,在第16篇里给了地址的,你们能够看看。有啥问题,及时联系我。