對於Spring Aop的實現,是很是複雜的,其實現過程主要包含xml標籤的解析,切面表達式的解析,判斷bean是否須要應用切面邏輯,以及使用Jdk代理或者是Cglib代理生成代理類。本文主要講解Xml標籤的解析的實現原理,在接下來幾篇文章中,會依次對Spring Aop剩餘的實現過程進行講解。java
關於Spring Aop的實現,因爲其是使用自定義標籤進行驅動的,於是讀者朋友若是對Spring如何實現自定義標籤比較熟悉,那麼能夠繼續往下閱讀,不然能夠閱讀完本文後再本人前面的文章Spring自定義標籤解析與實現。node
首先咱們聲明瞭一個切面類以下:正則表達式
@Aspect public class DogAspect { @Around("execution(public void com.business.Dog.*(..))") public Object aspect(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("before run."); Object result = joinPoint.proceed(); System.out.println("after run."); return result; } }
該切面類主要用於環繞com.business.Dog
類中的public類型的,而且返回值是void的全部方法,下面咱們就在com.business
包中聲明一個Dog
類以下:spring
public class Dog { public void run() { System.out.println("Tidy is running."); } }
這裏切面類和目標類都已經聲明完成,但若是不將其加入Spring容器中,其是不會工做的,加入容器的方式很是簡單,下面就是一種方式:app
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="dog" class="com.business.Dog"/> <bean id="aspect" class="com.business.DogAspect"/> <aop:aspectj-autoproxy/> </beans>
這裏須要說明的是,將DogAspect
聲明爲一個bean並不能使其工做,由於其也僅僅只是一個bean而已,要使其工做還須要使用上面的<aop:aspectj-autoproxy/>
標籤實現切面的自動裝配。下面使咱們運行整個程序的驅動類:ide
public class DogApp { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Dog dog = context.getBean(Dog.class); dog.run(); } }
執行結果以下:ui
before run. Tidy is running. after run.
能夠看到,咱們在驅動類中獲取的是Dog
的實例,而且運行其run()
方法,可是最終的運行結果中也運行了切面類中的環繞邏輯。spa
根據前面對Spring自定義標籤使用的講解,咱們知道這裏<aop:aspectj-autoproxy/>
就是一個自定義標籤,而且該標籤會在相應jar包的META-INF
目錄下有一個spring.handlers
文件,該文件中聲明瞭解析該標籤的類。經過查看該類咱們獲得以下配置:.net
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
這裏咱們打開AopNamespaceHandler
,其實現以下:scala
public class AopNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser()); registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser()); registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator()); registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser()); } }
能夠看到,咱們須要解析的標籤解析器在這個類中進行了註冊,即AspectJAutoProxyBeanDefinitionParser
,打開這個類其主要實現以下:
class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser { // 解析標籤的時候將會執行的方法 @Override @Nullable public BeanDefinition parse(Element element, ParserContext parserContext) { // 註冊一個類型爲AnnotationAwareAspectJAutoProxyCreator的bean到Spring容器中 AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element); // 經過讀取配置文件對擴展相關屬性 extendBeanDefinition(element, parserContext); return null; } private void extendBeanDefinition(Element element, ParserContext parserContext) { // 獲取前面註冊的AnnotationAwareAspectJAutoProxyCreator對應的BeanDefinition BeanDefinition beanDef = parserContext.getRegistry().getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME); // 解析當前標籤的子標籤 if (element.hasChildNodes()) { addIncludePatterns(element, parserContext, beanDef); } } // 解析子標籤中的name屬性,其能夠有多個,這個name屬性最終會被添加到 // AnnotationAwareAspectJAutoProxyCreator的includePatterns屬性中, // Spring在判斷一個類是否須要進行代理的時候會判斷當前bean的名稱是否與includePatterns中的 // 正則表達式相匹配,若是不匹配,則不進行代理 private void addIncludePatterns(Element element, ParserContext parserContext, BeanDefinition beanDef) { ManagedList<TypedStringValue> includePatterns = new ManagedList<>(); NodeList childNodes = element.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { Node node = childNodes.item(i); if (node instanceof Element) { Element includeElement = (Element) node; // 解析子標籤中的name屬性 TypedStringValue valueHolder = new TypedStringValue(includeElement.getAttribute("name")); valueHolder.setSource(parserContext.extractSource(includeElement)); includePatterns.add(valueHolder); } } // 將解析到的name屬性設置到AnnotationAwareAspectJAutoProxyCreator // 的includePatterns屬性中 if (!includePatterns.isEmpty()) { includePatterns.setSource(parserContext.extractSource(element)); beanDef.getPropertyValues().add("includePatterns", includePatterns); } } }
這裏咱們繼續看AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
方法,該方法的實現以下:
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary( ParserContext parserContext, Element sourceElement) { // 註冊AnnotationAwareAspectJAutoProxyCreator的BeanDefinition BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary( parserContext.getRegistry(), parserContext.extractSource(sourceElement)); // 解析標籤中的proxy-target-class和expose-proxy屬性值, // proxy-target-class主要控制是使用Jdk代理仍是Cglib代理實現,expose-proxy用於控制 // 是否將生成的代理類的實例防護AopContext中,而且暴露給相關子類使用 useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement); // 將註冊的BeanDefinition封裝到BeanComponentDefinition中 registerComponentIfNecessary(beanDefinition, parserContext); } private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, @Nullable Element sourceElement) { if (sourceElement != null) { // 解析標籤中的proxy-target-class屬性值 boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE)); if (proxyTargetClass) { // 將解析獲得的proxy-target-class屬性值設置到上面生成的 // AnnotationAwareAspectJAutoProxyCreator的BeanDefinition的proxyTargetClass // 屬性中 AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } // 解析標籤中的expose-proxy屬性值 boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE)); if (exposeProxy) { // 將解析獲得的expose-proxy屬性值設置到 // AnnotationAwareAspectJAutoProxyCreator的exposeProxy屬性中 AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } } } private static void registerComponentIfNecessary(@Nullable BeanDefinition beanDefinition, ParserContext parserContext) { // 若是生成的AnnotationAwareAspectJAutoProxyCreator的BeanDefinition成功,則將其封裝到 // BeanComponentDefinition中,而且將其添加到ParserContext中 if (beanDefinition != null) { BeanComponentDefinition componentDefinition = new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME); parserContext.registerComponent(componentDefinition); } }
這裏能夠看到AnnotationAwareAspectJAutoProxyCreator
的BeanDefinition
在第一步進行了註冊,而後讀取標籤中的proxy-target-class和expose-proxy屬性,而且將屬性值設置到生成的BeanDefinition
中。最後將生成的BeanDefinition
註冊到ParserContext
中。這裏咱們繼續看AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement))
方法,其實現以下:
@Nullable public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) { // 註冊AnnotationAwareAspectJAutoProxyCreator類型的BeanDefinition return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source); } @Nullable private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); // 若是已經註冊過AnnotationAwareAspectJAutoProxyCreator的Definition,若是其 // 和當前將要註冊的BeanDefinition是同一個類型,則再也不註冊,若是不一樣,則判斷其優先級比 // 當前將要註冊的BeanDefinition要高,則將其類名設置爲當前要註冊的BeanDefinition的名稱 if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); if (!cls.getName().equals(apcDefinition.getBeanClassName())) { int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); int requiredPriority = findPriorityForClass(cls); if (currentPriority < requiredPriority) { apcDefinition.setBeanClassName(cls.getName()); } } return null; } // 若是不存在已經註冊的Aop的bean,則生成一個,而且設置其執行優先級爲最高優先級,而且標識 // 該bean爲Spring的系統Bean,設置完以後則對該bean進行註冊 RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); beanDefinition.setSource(source); beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); return beanDefinition; }
能夠看到,在真正生成AnnotationAwareAspectJAutoProxyCreator
的BeanDefinition
的時候,首先會判斷是否已經生成過該bean,這裏不會將已經生成的bean進行覆蓋;若是沒有生成該bean,則建立一個並進行註冊。這裏須要說明的是,Spring註冊該bean的時候使用的order是Ordered.HIGHEST_PRECEDENCE
,這麼設置的緣由在於Spring使用該bean進行切面邏輯的織入,於是這個bean必須在全部用戶自定義的bean實例化以前進行實例化,而用戶自定義的bean的實例化優先級是比較低的,這樣才能實現織入代理邏輯的功能。
本文首先使用一個簡單的示例展現了Spring Aop的使用方式,而後對標籤中的<aop:aspectj-autoproxy/>
解析過程進行了講解。能夠看到,該標籤的解析過程最終是生成了一個AnnotationAwareAspectJAutoProxyCreator
的BeanDefinition
,關於Spring是如何使用該類實現代理的邏輯將在下一篇文章中進行講解。