基於個人理解的springAOP部分原始碼分析,內含較多原始碼,慎入
阿新 • • 發佈:2020-07-29
## 本文原始碼較多,講述一些個人對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
//該方法中呼叫的時返回