spring源碼系列:Aop基礎編程以及Spring Aop基於Aspect註解方式源碼分析

AOP編程中的基本概念

  1. 連接點: 程序執行某個特定位置,如類的初始化前後,某個方法調用前後,方法報出異常後,一個類或者一段代碼擁有一些邊界性質的特定點。Spring僅支持方法的連接點
  2. 切點: 每個程序都擁有多個連接點。AOP通過切點定位連接點,一個切點可以對應多個連接點。
  3. 增強: 增強是一段代碼。是織入到目標類的連接點上的一段代碼。
  4. 目標對象: 增強邏輯的織入目標類
  5. 引介: 引介是特殊的增強,他爲類添加一些屬性和方法
  6. 織入: 將增強添加到具體目標對象的連接點的過程
  7. 切面: 切面是由切點和增強組成

Spring中的概念

  • advisor: 封裝了SpringAop的切點和通知(類似爲切面) 後面我們把advisor結尾的類稱爲切面類
  • advice: 通知,也就是增強。後面我們把spring中以advice結尾的類稱爲增強類
  • creator: 相當於織入(只不過spring是通過動態代理織入增強的) 爲了方便稱呼我們後面把creator結尾的類成爲織入類

核心類

advisorCreator自動織入類:

  • BeanNameAutoProxyCreator: 根據指定的名稱創建代理對象,通過設置advisor,可以對指定的beanName進行代理。支持模糊
  • AbstractAdvisorAutoProxyCreator: 掃描所有的advisor的實現類。動態匹配每一個類,判斷是否可以被代理。默認的實現類是DefaultAdvisorAutoProxyCreator
  • AspectJAwareAdvisorAutoProxyCreator: AspectJ的實現方式,spring最常用的實現方式。其子類(AnnotationAwareAspectJAutoProxyCreator)是默認的支持方式,會掃描@Aspect註解的類,生產對應的切面。

advisor核心類(都集成Advisor接口)

  • StaticMethodMatcherPointcut: 靜態方法切面,抽象類。定義了一個classFilter,通過重寫getClassFilter()方法來指定切面規則。另外實現了StaticMethodMatcher接口,通過重寫matches來指定方法匹配規則
  • StaticMethodMatcherPointcutAdvisor: 靜態方法匹配切面,擴展了排序方法。
  • NameMatchMethodPointcut: 名稱匹配切面,通過指定方法集合變量mappedNames,模糊匹配。
  • NameMatchMethodPointcutAdvisor: 方法名稱切面,內部封裝了NameMatchMethodPointcut,通過設置方法名稱模糊匹配規則和通知來實現切面功能
  • DefaultPointcutAdvisor: 默認的切面類
  • RegexpMethodPointcutAdvisor: 用於支持正則表達式的切面類,可支持函多個正則表達式
  • NameMatchMethodPointcutAdvisor: 方法名稱切面
  • InstantiationModelAwarePointcutAdvisorImpl: 自動封裝的切面實現。在自動織入的時候會默認會把AspectJ註解默認包裝改該類。比較常用的切面類

advice增強核心類

  • AspectJMethodBeforeAdvice: 前置增強(@Before標註的方法會被解析成該通知)
  • AspectJAfterReturningAdvice: 後置增強(@AfterReturning 標註的方法會被解析成該通知)
  • AspectJAroundAdvice: 環繞增強(@Around標註的方法會被解析成該通知)
  • AspectJAfterAdvice: 返回增強(@After 標註的方法會被解析成該通知)忽略異常

SpringAop基於AspectJ註解方式

目標對象

@Component
public class TargetA {

  public void sayHello(){
    System.out.println("sayHello");
  }
}

增強

@Component
@Aspect
public class ProxyA {

  @Pointcut("execution(* org.springframework.apo..*.*(..))")
  public void point(){
  }

  @Before("point()")
  public void before(){
    System.out.println("begin say..");
  }

  @After("point()")
  public void after(){
    System.out.println("after say ...");
  }
}

啓動類

@ComponentScan("org.springframework.apo")
@EnableAspectJAutoProxy
public class App {
  public static void main(String[] args) {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(App.class);
    TargetA bean = applicationContext.getBean(TargetA.class);
    bean.sayHello();
  }
}

可以看到在spring中我們只需要定義增強 其他的不需要我們關心。 spring的creator會幫我織入到目標類。上面的流程最關鍵的兩點 其一是AspectJ連接點表達式比較關鍵 其二是在啓動類上加@EnableAspectAutoProxy註解(springboot引入了spring-boot-starter-aop就不需要再手動Enabled)。下面我們從註解入手看一下 spring織入的整個流程。

Spring AOP源碼分析

啓動註解EnableAspectJAutoProxy

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
	boolean proxyTargetClass() default false;
	boolean exposeProxy() default false;

}

我們看到上述代碼中使用@Import標籤向spring容器中導入了一個AspectJAutoProxyRegistrar。繼續跟進AspectJAutoProxyRegistrar

@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
          //向IOC容器中注入AnnotationAwareAspectJAutoProxyCreator 
		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
		if (enableAspectJAutoProxy != null) {
			if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}

上面代碼其實主要是向容器中加了AnnotationAwareAspectJAutoProxyCreator 這個織入類。並根據我們的配置(註解中有兩個屬性 後續會講解)。到這這個註解的使命就完成了。那爲什麼像springIOC容器注入了一個AnnotationAwareAspectJAutoProxyCreator 就能實現織入的能力呢?下面我們從這個類入手瞭解一下spring的整個織入流程。

類的繼承關係

AnnotationAwareAspectJAutProxyCreator繼承關係

在看spring源碼的時候我們可以發現 spring框架中大量運用了模板方法模式。所以只要出現Abstract開頭的類 我們就應該好好的去看一下。分析這一部分的源碼我們就從第第一個抽象類入手AbstractAutoProxyCreator。
看一下初始化過程

父類初始化AbstractAutoProxyCreator

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
		implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
   @Override
	public void setBeanFactory(BeanFactory beanFactory) {
		super.setBeanFactory(beanFactory);
		if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
			throw new IllegalArgumentException(
					"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
		}
		initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
	}
	
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
	}
}

子類初始化

public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
 //這個方法是在bean初始化之前調用 在spring啓動期間會把BeanFactory注入進來 是一個初始化方法。
   @Override
	protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		super.initBeanFactory(beanFactory);
		if (this.aspectJAdvisorFactory == null) {
		//ReflectiveAspectJAdvisorFactory是一個支持AspectJ註解的類。可以解析AspectJ註解包裝成Advisor。簡單的理解是對AspectJ的語法的支持。
			this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
		}
		//這裏是對ReflectiveAspectJAdvisorFactory的包裝 內部真正解析AspectJ註解的是ReflectiveAspectJAdvisorFactory類。
		this.aspectJAdvisorsBuilder =
				new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
	}
}

可以發現它實現了SmartInstantiationAwareBeanPostProcessor 。這個接口是springIOC容器的擴展接口其最頂層的父接口是BeanPostProcessor。在springIOC容器啓動和 bean的創建 初始化前後調用。如果對這一塊比較模糊可以去看一下BeanFactoryPostProcessor和BeanPostProcessor這兩個父接口衍生出來的幾個接口的註釋。裏面對於調用點的註釋還挺清楚。我們這裏就不做過多解釋了。

下面我們把這個類中我們需要用的方法複製出來

     //這個方法是InstantiationAwareBeanPostProcessor接口中的方法 是在bean實例化之前被調用
     @Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		Object cacheKey = getCacheKey(beanClass, beanName);
		if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
		    //advisedBeans用於存儲不能被代理的bean  如果當前bean出現在集合中立馬返回
			if (this.advisedBeans.containsKey(cacheKey)) {
				return null;
			}
			//如果當前類繼承 Advice,Pointcut,Advisor,AopInfrastructureBean等這些類也不能被
			//代理
			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
				this.advisedBeans.put(cacheKey, Boolean.FALSE);
				return null;
			}
		}
		//得到目標源 這是一次嘗試 因爲如果我們設置customTargetSourceCreators 這個屬性 這個時候就
		//會獲取我們設置的TargetSource對象 如果沒設置就跳過了這個方法。 下面的代理過程我們暫且先不管
		TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
		if (targetSource != null) {
			if (StringUtils.hasLength(beanName)) {
			    //如果找到確實設置了TargetSource 就加入到緩存集合
				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這個方法 子類的實現

  @Override
	protected boolean shouldSkip(Class<?> beanClass, String beanName) {
		// 從bean工廠中查找所有的advisor 如果當前bean的名字在當前advisor的列表中 則跳過不需要代理
		//暫時不展開
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		for (Advisor advisor : candidateAdvisors) {
			if (advisor instanceof AspectJPointcutAdvisor &&
					((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
				return true;
			}
		}
		return super.shouldSkip(beanClass, beanName);
	}

上面我們分析了postProcessBeforeInstantiation方法 如果設置自定義的TargetSourceCreator 就只做了一件事件 找到所有的增強並封裝成切面

//這個方法BeanPostProcessor中的方法 在bean初始化(初始化方法)之後調用。
    @Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
			    //重點是這裏 進入這個方法
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (StringUtils.hasLength(beanName) && 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;
		}
		//前面都是判斷  直接來到這一行代碼 我們暫時不展開  大概的意思是從我們所有的切面中篩選符合當前bean的切面
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
		   //如果有符合當前類的切面 將當前類放到緩存中
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			//創建一個當前類的代理 相當於把增強織入到當前類
			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;
	}

到目前爲止 如果我們不展開getAdvicesAndAdvisorsForBean 方法和createProxy方法 其實整個過程已經結束了。


最後我們着重分析一下advisor的創建過程和代理類的創建過程

  1. advisor創建 getAdvicesAndAdvisorsForBean這個方法是一個抽象方法 是並且是AbstractAutoProxyCreator唯一的一個抽象方法 我們直接進入子類(AbstractAdvisorAutoProxyCreator)的實現

   protected Object[] getAdvicesAndAdvisorsForBean(
   		Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
   	//這裏繼續調用查找Advisor的方法	
   	List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
   	if (advisors.isEmpty()) {
   		return DO_NOT_PROXY;
   	}
   	return advisors.toArray();
   }

繼續跟進findEligibleAdvisors 當前所在AbstractAdvisorAutoProxyCreator類

  	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
  	    //這個方法被子類重寫就是查找被AspectJ語法修飾的切面
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		//找出所有切面應用在當前實例上面的
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		//擴展方法  子類實現的時候像 集合中加入了ExposeInvocationInterceptor
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

進入子類的findCandidateAdvisors方法

	@Override
	protected List<Advisor> findCandidateAdvisors() {
		// 先調用父類的方法獲取容器中所有實現Advisor的子類的實例
		List<Advisor> advisors = super.findCandidateAdvisors();
		if (this.aspectJAdvisorsBuilder != null) {
		//然後加入所有AspectJ註解修飾的切面
			advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		}
		return advisors;
	}

繼續展開this.aspectJAdvisorsBuilder.buildAspectJAdvisors() 這個方法是查找的核心 代碼有點多

public List<Advisor> buildAspectJAdvisors() {
//aspectBeanNames這個是緩存的所有 有AspectJ註解的實例  第一次是null
		List<String> aspectNames = this.aspectBeanNames;
		if (aspectNames == null) {
			synchronized (this) {
				aspectNames = this.aspectBeanNames;
				if (aspectNames == null) {
					List<Advisor> advisors = new ArrayList<>();
					aspectNames = new ArrayList<>();
         //這裏就是找到所有的bean 因爲傳的類型是Object 所以所有的實例的名字都會查找出來 					
					String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
							this.beanFactory, Object.class, true, false);
					for (String beanName : beanNames) {
						if (!isEligibleBean(beanName)) {
							continue;
						}
						Class<?> beanType = this.beanFactory.getType(beanName);
						if (beanType == null) {
							continue;
						}
						//這裏判斷當前類型是否有AspectJ註解
						if (this.advisorFactory.isAspect(beanType)) {
							aspectNames.add(beanName);
							AspectMetadata amd = new AspectMetadata(beanType, beanName);
							if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
								MetadataAwareAspectInstanceFactory factory =
										new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
     //這裏找到當前實例的Advisor 這裏不作展開了 就是通過反射拿到對應的方法封裝成InstantiationModelAwarePointcutAdvisorImpl的過程										
								List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
								//這裏緩存分爲單例和原型的方式緩存
								if (this.beanFactory.isSingleton(beanName)) {
									this.advisorsCache.put(beanName, classAdvisors);
								}
								else {
									this.aspectFactoryCache.put(beanName, factory);
								}
								//然後將本次解析結果加入集合
								advisors.addAll(classAdvisors);
							}
							else {
								// Per target or per this.
								if (this.beanFactory.isSingleton(beanName)) {
									throw new IllegalArgumentException("Bean with name '" + beanName +
											"' is a singleton, but aspect instantiation model is not singleton");
								}
								MetadataAwareAspectInstanceFactory factory =
										new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
								this.aspectFactoryCache.put(beanName, factory);
								advisors.addAll(this.advisorFactory.getAdvisors(factory));
							}
						}
					}
					this.aspectBeanNames = aspectNames;
					return advisors;
				}
			}
		}

		if (aspectNames.isEmpty()) {
			return Collections.emptyList();
		}
		List<Advisor> advisors = new ArrayList<>();
		for (String aspectName : aspectNames) {
			List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
			if (cachedAdvisors != null) {
				advisors.addAll(cachedAdvisors);
			}
			else {
				MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
				advisors.addAll(this.advisorFactory.getAdvisors(factory));
			}
		}
		return advisors;
	}

到此我們的解析Advisor流程就結束了


下面我們在看一下代理的創建

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {

		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}
//創建一個代理工廠  ProxyFactory區別於ProxyFactoryBean 關於ProxyFactoryBean後面會介紹
		ProxyFactory proxyFactory = new ProxyFactory();
//設置一些ProxyFactory的屬性例如proxyTargetClass,exposeProxy 因爲 ProxyFactory和AbstractAutoProxyCreator都繼承自ProxyConfig		
//下面都是對ProxyFactory的設置
		proxyFactory.copyFrom(this);
		if (!proxyFactory.isProxyTargetClass()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		//設置切面
		proxyFactory.addAdvisors(advisors);
		//設置代理源
		proxyFactory.setTargetSource(targetSource);
		//這個是擴展方法 留個子類實現可以對ProxyFactory自定義。
		//例如我們可以自定義一種織入策略  實現AbstractAutoProxyCreator 然後重寫該方法 去自定義ProxyFactory
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}
		//這裏是創建代理的邏輯
		return proxyFactory.getProxy(getProxyClassLoader());
	}

下面進入getProxy中 下面這個方法就是根據代理類是否有接口去創建不同的AopProxy
如果有接口通過JDK動態代理的創建模式 如果沒有接口通過CGLIB的創建方式。其實可以看到 springAop是側重於用JDK動態代理的 因爲不管我們配置的ProxyTargetClass這個參數是true還是false 只要當前實例是繼承接口的都會有JDK動態代理。

	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
			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.");
			}
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}

好了到這裏 我們把基本的流程敘述了一遍。這一塊的代碼太多 不可能很詳細 讀者可以下去自行翻閱。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章