1. 程式人生 > >基於個人理解的springAOP部分原始碼分析,內含較多原始碼,慎入

基於個人理解的springAOP部分原始碼分析,內含較多原始碼,慎入

## 本文原始碼較多,講述一些個人對spring中AOP程式設計的一個原始碼分析理解,只代表個人理解,希望能和大家進行交流,有什麼錯誤也渴求指點!!!接下來進入正題 AOP的實現,我認為簡單的說就是利用代理模式,對目標方法所在的類進行封裝代理。請求目標方法時,是直接請求代理物件,再根據使用者指定的通知(切點),在代理物件中進行操作,到了該使用目標方法的時候,呼叫代理物件中包裝的真正目標方法完成,以實現面向切面程式設計,以下對兩個問題進行一個分析: - 代理物件什麼時候被建立 - 切面類我們定義的切點資訊是怎麼載入的 - 找到在何處進行掃描 - 探究如何進行掃描 ## 代理物件是什麼時候被建立的? 這裡是通過name來獲取bean的情況,注意使用type的方式來獲取bean進行除錯,就會和本文有所出入 現在從Main方法出發 ```java //1.建立IOC容器 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); //2.從IOC中獲取bean例項 ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator) ctx.getBean("arithmeticCalculatorImpl"); ``` - 我們進入getBean的程式碼檢視,發現bean是直接在一個名為singletonObjects的concurrentHashMap(ioc容器)中取出來的,取出時就已經是一個proxy物件了,可以證明,是在初始化例項的時候就建立了![](https://img2020.cnblogs.com/blog/1924372/202007/1924372-20200729180313794-540470765.png) - 我們知道spring會在程式啟動的時候,初始化ioc容器,而對於我們指定的切面類,在初始化例項時,就將找到我們指定的類,對其進行建立代理,代理物件建立後,放置到ioc容器中 - 具體的流程是在初始化到我們指定的物件時,他會先創建出一個未代理的例項![](https://img2020.cnblogs.com/blog/1924372/202007/1924372-20200729180352919-1991595064.png) 該例項會經過一個applyBeanPostProcessorsAfterInitialization方法,7個spring的後置處理器進行遍歷,如果該類符合某個後置處理器的條件,則會被後置處理器載入,而我們aop的類會被(AnnotationAwareAspectJAutoProxyCreator)後置處理器處理,如下為7個後置處理器![](https://img2020.cnblogs.com/blog/1924372/202007/1924372-20200729180431026-1659835012.png) - 進入到該後置處理器我們會發現,他會通過判斷這個類是否註釋了切面程式設計的標記,如果註釋了則進行處理,也就是我們的註解起了作用,這裡是經過了AnnotationAwareAspectJAutoProxyCreator後置處理器的處理,以下是AnnotationAwareAspectJAutoProxyCreator處理器的applyBeanPostProcessorsAfterInitialization初始化方法 ```java //applyBeanPostProcessorsAfterInitialization方法的原始碼 public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; Object current; for(Iterator var4 = this.getBeanPostProcessors().iterator(); var4.hasNext(); result = current) { BeanPostProcessor processor = (BeanPostProcessor)var4.next(); //processor=AnnotationAwareAspectJAutoProxyCreator時,會進入postProcessAfterInitialization方法 current = processor.postProcessAfterInitialization(result, beanName); if (current == null) { return result; } } return result; } ``` ```java //進入AnnotationAwareAspectJAutoProxyCreator後置處理器的操作,通過除錯我們看到,在wrapIfNecessary方法中進行了代理 public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { Object cacheKey = this.getCacheKey(bean.getClass(), beanName); //判斷是否需要代理 if (this.earlyProxyReferences.remove(cacheKey) != bean) { //代理 return this.wrapIfNecessary(bean, beanName, cacheKey); } } ``` ```java //該方法是真正對proxy進行代理的方法 protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { return bean; } else if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } else if (!this.isInfrastructureClass(bean.getClass()) && !this.shouldSkip(bean.getClass(), beanName)) { //獲取切點資訊 Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, (TargetSource)null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); //建立了代理物件 Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); //返回 return proxy; } else { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } } else { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } } ``` - 後置處理器的處理方式,是在一個(postProcessAfterInitialization)方法中進行的處理,通過判斷指定是使用jdbc的動態代理建立proxy還是通過cglib,處理後返回到變數中,完成後新增到ioc容器中,完成初始化,之後呼叫時都是已經代理過的例項,就可以進行切面程式設計了 ```java //最終是呼叫了DefaultAopProxyFactory類的createAopProxy來實現代理 //可以看到這裡根據一些配置條件來判斷我們要建立的代理是jdk動態代理還是cglib public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) { //建立返回 return new JdkDynamicAopProxy(config); } else { Class targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: Either an interface or a target is required for proxy creation."); } else { //建立返回 return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config)); } } } ``` 也就是說,spring在初始化容器的時候,會為@Aspect註解的類進行一個代理操作,而其中主要起作用的是7個後置處理器中的AnnotationAwareAspectJAutoProxyCreator處理器對其進行了代理 ## 切點資訊是如何獲取、封裝,然後儲存在List中的 ### 先找到他在何處進行的掃描 以上的建立代理過程中,我們知道了如下程式碼是獲得了切點資訊的一個語句 ```java //該方法中呼叫的時返回