先是生成代理对象,而后是拦截器的做用,最后是编织的具体实现。这是AOP实现的三个步骤,固然Spring AOP也是同样。
java
而从Spring AOP总体架构上看,其核心都是创建在代理上的。当咱们创建加强实例时,咱们必须先使用 ProxyFactory 类加入咱们须要织入该类的全部加强,而后为该类建立代理。通常而言,AOP实现代理的方法有三种,而 Spring 内部用到了其中的两种方法:动态代理和静态代理,而动态代理又分为JDK动态代理和CGLIB代理。而前面提到的 ProxyFactory 类控制着 Spring AOP 中的织入和建立代理的过程。在真正建立代理以前,咱们必须指定被加强对象或者目标对象。咱们是经过 setTarget() 方法来完成这个步骤的。而 ProxyFactory 内部将生成代理的过程所有转给 DefaultAopProxyFactory 对象来完成,而后根据设置转给其余的类来完成。下面是 Spring AOP 生成代理的原理图:
spring
而特别须要注意的是,在 Spring AOP 中,一个 Advisor(通知者,也翻做 通知器或者加强器)就是一个切面,他的主要做用是整合切面加强设计(Advice)和切入点设计(Pointcut)。Advisor有两个子接口:IntroductionAdvisor 和 PointcutAdvisor,基本全部切入点控制的 Advisor 都是由 PointcutAdvisor 实现的。而下面的是Spring AOP的总体架构图架构
乍一看,很是的复杂,但若是结合上面的Spring AOP生成代理的原理图一块儿看,也就那么回事,只是丰富的许多属性了,咱们会慢慢介绍的。框架
分析 Spring AOP 源码的话,直接从最简单业务代码入手,一步步的对源码进行解析。但愿借此能看清楚 Spring AOP 纵向和横向代码之间的联系,并且思惟也不会太跳跃。下面就是 Spring AOP 测试程序 Test 项目的结构图:函数
注:Spring 源码版本是 Spring-4.1.6,个人源码分析也是基于这一版本的,JDK 版本是 1.8,aspect 是用的 aspectjrt-1.7.4 和 aspectjweaver-1.7.4。
源码分析
在实际项目中,Bean应该能够算是核心逻辑了,其中的 printTest 方法中可能会封装整个的核心业务逻辑,如此重要的地方咱们想在printTest方法先后加入日志来进行跟踪或者调试也是很天然地想法,可是若是直接修改源码是不符合面向对象的设计原则的,它并不符合面向对象的设计方式,并且随意的改动原有的代码也会形成必定的风险,这里就体现 AOP 的优越性了。测试
package test; /** * 测试Bean * * @Auther kay * @Date 2016-03-08 */ public class TestBean { private String testStr = "testStr"; public String getTestStr(){ return testStr; } public void setTestStr(String testStr){ this.testStr = testStr; } public void printTest(){ System.out.println("test Bean"); } }
Spring AOP 实现的核心,这里采用了@AspectJ注释对POJO进行标注,使AOP的工做大大简化。
ui
package test; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; /** * Aspect切面 * * @Auther kay * @Date 2016-03-08 */ @Aspect public class AspectTest { /** * 配置切入点,主要为方便同类中其余方法使用此处配置的切入点 */ private final String POINT_CUT = "execution(* test.TestBean.*(..))"; /** * 配置前置通知,使用在方法aspect()上注册的切入点 * 同时接受JoinPoint切入点对象,能够没有该参数 */ @Before(POINT_CUT) public void beforeTest(){ System.out.println("before Test"); } /** * 配置后置通知,使用在方法aspect()上注册的切入点 */ @After(POINT_CUT) public void afterTest(){ System.out.println("after Test"); } /** * 配置环绕通知,使用在方法aspect()上注册的切入点 * * @param point JoinPoint的支持接口 * @return Object */ @Around(POINT_CUT) public Object arountTest(ProceedingJoinPoint point){ System.out.println("before1"); Object object = null; try{ object = point.proceed(); } catch (Throwable e){ e.printStackTrace(); } System.out.println("after1"); return object; } }
XML是Spring的基础,尽管Spring一再简化配置,而且大有使用注解取代XML配置之势,但不管如何XML仍是Spring的基石。
this
<?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-4.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd"> <!-- 激活自动代理功能 --> <aop:aspectj-autoproxy /> <!-- 业务逻辑切面配置 --> <bean id="test" class = "test.TestBean" /> <bean class="test.AspectTest" /> </beans>
测试程序,验证效果。
spa
package test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * 测试程序 * * @Auther kay * @Date 2016-03-08 */ public class Test { public static void main(String[] arge){ ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml"); TestBean bean = context.getBean("test", TestBean.class); bean.printTest(); } }
控制台打印以下代码:
Spring AOP是如何实现AOP的?首先咱们知道,Spring是否支持注释的AOP是由一个配置文件来控制的,也就是<aop:aspectj-autoproxy />,下面咱们分析就从这句配置开始。
首先spring-config.xml配置文件里的<aop:aspectj-autoproxy>进行解析,发现其若是不是bean标签,则会用不一样的类来解析。解析AOP的是:http\://www.springframework.org/schema/aop=org.springframeworl.aop.config.AopNamespaceHandler。也就是 AopNamespaceHandler 类来解析,咱们对 AopNamespaceHandler 类进行分析
发现 AopNamespaceHandler 的一段代码是 <aop:aspectj-autoproxy> 解析的入口
AopNamespaceHandler.java
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
由此,咱们知道只要配置文件中出现“aspectj-autoproxy”的注解时就会使用解析器对 AspectJAutoProxyBeanDefinitionParser 进行解析
全部解析器,都是由 BeanDefinitionParser 接口的统一实现,入口都是从 parse函数开始的,AspectJAutoProxyBeanDefinitionParser 的 parse 函数以下:
AspectJAutoProxyBeanDefinitionParser .java
public BeanDefinition parse(Element element, ParserContext parserContext) { // 注册 AnnotationAwareAspectJAutoProxyCreator AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element); // 对于注释中子类进行处理 extendBeanDefinition(element, parserContext); return null; }
其中的 registerAspectJAnnotationAutoProxyCreatorIfNecessary 函数是 AnnotationAwareAspectJAutoProxyCreator 注册的地方,也是注册的主要逻辑实现的地方。
AopNamespaceUtils.java
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary( ParserContext parserContext, Element sourceElement) { // 注册或升级 AutoProxyCreator 定义 beanName 为 org.Springframework.aop.config.internalAutoProxyCreator的 // BeanDefinition BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary( parserContext.getRegistry(), parserContext.extractSource(sourceElement)); // 对于 proxy-target-class 以及 expose-proxy 属性的处理 useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement); // 注册组件并通知,便于监听器做进一步处理 // 其中 beanDefinition 的 className 为 AnnotationAwareAspectJAutoProxyCreator registerComponentIfNecessary(beanDefinition, parserContext); }
在对于AOP实现上,基本上都是靠 AnnotationAwareAspectJAutoProxyCreator 去完成的,它能够根据@Point 注解定义的切点来自动代理相匹配的 bean。可是为了配置简便,Spring 使用了自定义配置来帮咱们自动注册 AnnotationAwareAspectJAutoProxyCreator。具体实现以下
AopNamespaceUtils.java
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) { return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source); }
AopConfigUtils.java
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); // 若是已经存在自动代理建立器且存在的自动代理建立器与如今的不一致那么须要根据优先级来判断到底须要任何使用 if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { // AUTO_PROXY_CREATOR_BEAN_NAME="org.springframework.aop.config.internalAutoProxyCreator" 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) { // 改变bean 最重要的就是改变bean 所对应的 className 属性 apcDefinition.setBeanClassName(cls.getName()); } } // 若是已经存在自动代理建立器而且与将要建立的一致,那么无需再此建立 return null; } RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); beanDefinition.setSource(source); beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); // AUTO_PROXY_CREATOR_BEAN_NAME="org.springframework.aop.config.internalAutoProxyCreator" registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); return beanDefinition; }
以上代码中实现了自动注册 AnnotationAwareAspectJAutoProxyCreator 类的功能,同时这里还涉及了一个优先级的问题,若是已经存在了自动代理建立器,并且存在的自动代理建立器与如今的不一致,那么就须要根据优先级来判断到底须要使用哪个?
通常而言,Spring AOP 内部使用 JDK 动态代理或者 CGLIB 来为目标对象建立代理。若是被代理的目标对象实现了至少一个接口,则会使用 JDK 动态代理。全部该目标类型实现的接口都将被代理。若该目标对象没有实现任何接口,则建立一个 CGLIB 代理。通常状况下,使用 CGLIB 须要考虑加强(advise)Final 方法不能被复写以及须要指定 CGLIB 包的位置,尽管 CGLIB 效率更高,但仍是推荐使用 JDK 动态代理。
而 AOP 配置中的 prioxy-target-class 和 expose-proxy 属性在代理生成中起到了相当重要的。prioxy-target-class 主要负责上面两种代理的实现,而 expose-proxy 则负责自我调用切面中的加强。
AopNamespaceUtils.java
private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) { if (sourceElement != null) { // 对于 proxy-target-class 属性的处理 boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE)); if (proxyTargetClass) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } // 对于 expose-proxy 属性的处理 boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE)); if (exposeProxy) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } } }
AopConfigUtils.java
public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) { // 强制使用,其实也是一个属性设置 if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE); } } static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) { if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); definition.getPropertyValues().add("exposeProxy", Boolean.TRUE); } }
这些,基本就是Spring AOP部分的实现框架了,下节就要对AOP的主要实现类 AnnotationAwareAspectJAutoProxyCreator 进行分析。
——水门(2016年3月于杭州)