对于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是如何使用该类实现代理的逻辑将在下一篇文章中进行讲解。