纵观整个Spring的发展历史,注解的配置正逐步替代xml的配置,到SpringBoot时代,彻底能够用注解的配置替换繁杂的xml配置,例如咱们须要开启AOP功能只要在代码上配置上@EnableAspectJAutoProxy。废话很少说,咱们这节来分析下@EnableAspectJAutoProxy注解的背后的实现。java
先看下@EnableAspectJAutoProxy属性详情:spring
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(AspectJAutoProxyRegistrar.class) public @interface EnableAspectJAutoProxy { boolean proxyTargetClass() default false; }
@EnableAspectJAutoProxy有2个配置参数proxyTargetClass和@Import,@Import是个固定配置,写死成AspectJAutoProxyRegistrar类型,Spring在解析此注解配置时会建立AspectJAutoProxyRegistrar并调用registerBeanDefinitions方法。数组
在Spring中,动态代理有2种实现方式:缓存
基于CGLIB来实现框架
基于Java原生的Proxy实现,这种方式原类必需要定义接口。ide
这个参数就是表示动态代理实现方式,若是值设置true,表示须要代理类都基于CGLIB来实现;默认状况下值是设置成false表示若是原类若是定义了接口则经过Proxy实现不然基于CGLIB来实现。post
在Spring中@Import能够配置3种类型:ui
在基于@Configuration的类上引入beanthis
这个配置比较简单,直接在配置了@Configuration的类上配置@Import引入bean便可,举个例子:lua
@Configuration @Import(value={Bean.class}) public class Config { }
以上例子就会把Bean加入到Spring容器。
若是引入类须要通过注解上的参数来决定可使用此方式。
public interface ImportSelector { String[] selectImports(AnnotationMetadata importingClassMetadata); }
AnnotationMetadata类型能够获取注解上的参数配置。@EnableTransactionManagement就是经过次方式配置,来看下他配置:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(TransactionManagementConfigurationSelector.class) public @interface EnableTransactionManagement { boolean proxyTargetClass() default false; AdviceMode mode() default AdviceMode.PROXY; int order() default Ordered.LOWEST_PRECEDENCE; }
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> { @Override protected String[] selectImports(AdviceMode adviceMode) { switch (adviceMode) { case PROXY: return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()}; case ASPECTJ: return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME}; default: return null; } } }
以上例子就是经过获取AnnotationMetadata里的配置来决定引入那些bean。
在解析@Import配置传入AnnotationMetadata和BeanDefinitionRegistry两个参数到registerBeanDefinitions方法。
这种方式更加灵活,能够直接经过BeanDefinitionRegistry将本身想要的bean加入到Spring容器。
@EnableAspectJAutoProxy注解就是经过这种方式将代理建立器AnnotationAwareAspectJAutoProxyCreator加入到到Spring容器。
Spring的AOP的实现是基于Aspectj项目的注解及注解的解析实现,其核心的组件仍是Spring本身的实现包括Advisor(切面),Pointcut(切点),Advice(加强)。
切面就是将非逻辑代码抽离到一个指定位置,让编写逻辑代码的人感受不到非逻辑代码的存在,实际执行却能让非逻辑代码发挥效果,说白了就是切点和加强的组合
切点是对逻辑代码加强的位置,好比在逻辑代码执行前加强。
加强就是对切点位置的具体的实现,好比在逻辑代码执行前记录操做日志,而记录操做日志这个操做的具体实现就是加强
举个例子:
@Aspect //声明一个切面 public class LogAspect { @After(value="@annotation(com.just.spring4.ch1.aop.TestAction)") //经过@after注解声明一个建言,并使用@Pointcut定义的切点 public void after(JoinPoint joinPoint){ System.out.println("记录日志"); } }
@Aspect注解的LogAspect类就是切面。
@After注解的并匹配上的方法就是切点。
而System.out.println("记录日志")输出就是加强。
Advisor是一个接口它的实现表明了切面,切面包含了切点和加强,先看下Advisor接口的定义:
public interface Advisor { Advice getAdvice(); boolean isPerInstance(); }
getAdvice()方法返回了一个加强组件Advice。isPerInstance()方法在Spring框架中暂未被使用。
根据上面定义Advisor接口其实少了一个切点组件返回,因此Advisor通常不会被直接实现,Spring定义了2个接口来扩展Advisor的实现:
public interface IntroductionAdvisor extends Advisor, IntroductionInfo { ClassFilter getClassFilter(); void validateInterfaces() throws IllegalArgumentException; }
getClassFilter()方法返回了一个切点组件ClassFilter,它是Class的切点,来匹配Class是否知足条件来加强实现。validateInterfaces()方法的功能是Advice是否实现指定的接口。
IntroductionAdvisor主要作Class的匹配而不关心Method匹配状况。
public interface PointcutAdvisor extends Advisor { Pointcut getPointcut(); }
getPointcut()返回了一个切点组件Pointcut,Pointcut和ClassFilter不一样Pointcut包装了ClassFilter和MethodMatcher,也就是说Pointcut即匹配Class也匹配Method,2者同时知足状况下才能加强实现。
Pointcut表示切入的位置,在Spring中Pointcut接口是作一个匹配的功能包括Class和Method的匹配,只有匹配上才能作进一步加强。Pointcut接口以下
public interface Pointcut { ClassFilter getClassFilter(); MethodMatcher getMethodMatcher(); Pointcut TRUE = TruePointcut.INSTANCE; }
getClassFilter()返回的ClassFilter是Class匹配器,getMethodMatcher()返回的MethodMatcher是Class匹配器,但不必定每一个匹配器都会有做用,举个例子:
AnnotationMatchingPointcut是注解的切面类,它能够匹配Class上的注解或者Method的上的注解,看下它的构造方法:
public AnnotationMatchingPointcut( Class<? extends Annotation> classAnnotationType, Class<? extends Annotation> methodAnnotationType) { Assert.isTrue((classAnnotationType != null || methodAnnotationType != null), "Either Class annotation type or Method annotation type needs to be specified (or both)"); if (classAnnotationType != null) { this.classFilter = new AnnotationClassFilter(classAnnotationType); } else { this.classFilter = ClassFilter.TRUE; } if (methodAnnotationType != null) { this.methodMatcher = new AnnotationMethodMatcher(methodAnnotationType); } else { this.methodMatcher = MethodMatcher.TRUE; } }
构造方法有2个参数classAnnotationType表示Class上的注解,methodAnnotationType表示Method上的注解,2参数必传一个若是其中一个不传,会设置ClassFilter.TRUE或MethodMatcher.TRUE表示全类型匹配,这种匹配通常对整个类或单个方法进行加强。
StaticMethodMatcherPointcut是抽象类,自己是作一种规范,其规范必需要实现MethodMatcher的匹配逻辑来匹配Method,ClassFilter可不实现,不实现会全类型匹配。
Advice是加强的接口,Spring提供不少加强的实现。举例以下:
AspectJMethodBeforeAdvice
对应AspectJ中的@Before注解的加强实现,在方法执行前加强。
AspectJAfterAdvice
对应AspectJ中的@After注解的加强实现,在方法执行后加强。
AspectJAfterReturningAdvice
对应AspectJ中的@AfterReturning注解的加强实现,在方法执行后并获取返回值,能够根据返回值作加强。
AspectJAfterThrowingAdvice
对应AspectJ中的@AfterThrowing注解的加强实现,在方法执行后并获取执行错误信息,能够根据错误信息作加强。
AspectJAroundAdvice
对应AspectJ中的@Around注解的加强实现,在方法执行先后均可以作加强。
实现AOP关键有2个类AspectJAutoProxyRegistrar和AnnotationAwareAspectJAutoProxyCreator。
前面提到Spring经过@EnableAspectJAutoProxy的@Import配置在解析注解时会建立AspectJAutoProxyRegistrar并调用registerBeanDefinitions方法。
看下它的实现
public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); AnnotationAttributes enableAJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class); if (enableAJAutoProxy.getBoolean("proxyTargetClass")) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } }
代码的功能分2部分,第1部分将AnnotationAwareAspectJAutoProxyCreator类型包装成BeanDefinition注册到Spring容器。第2部分将proxyTargetClass的配置设置到此BeanDefinition里。
这里AnnotationAwareAspectJAutoProxyCreator类是实现AOP的核心后面详细说明。
先看下AnnotationAwareAspectJAutoProxyCreator的结构
能够看到AnnotationAwareAspectJAutoProxyCreator实现了BeanPostProcessor接口,这个接口作什么用的呢?
先看下这个接口的定义:
public interface BeanPostProcessor { Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException; Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException; }
在Spring容器中BeanDefinition被建立成bean后会依次调用实现了这个接口的类里postProcessBeforeInitialization和postProcessAfterInitialization,这2个方法做用能够对bean作修改就是能够对bean作代理或对bean作属性修改,而2这个方法先后执行分别对应bean初始化先后:
好了,咱们知道AnnotationAwareAspectJAutoProxyCreator就是利用BeanPostProcessor来作代理。
AnnotationAwareAspectJAutoProxyCreator代理是放在postProcessAfterInitialization方法里处理,因此对代理对象自己的初始化不受影响。
来看下它的实现:
@Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (!this.earlyProxyReferences.contains(cacheKey)) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }
先查看earlyProxyReferences缓存判断是否已经建立代理。(在循环引用状况下会调用getEarlyBeanReference提早建立代理),若是还未建立调用wrapIfNecessary方法去建立代理,咱们看下其实现:
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { if (beanName != null && 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; } 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; }
前2个if先判断是否已经建立再判断是否须要建立代理对象, 若是须要则调用getAdvicesAndAdvisorsForBean方法获取切面Advisor,再根据Advisor调用createProxy来建立代理对下,咱们分两部分来说。
getAdvicesAndAdvisorsForBean方法的实如今AbstractAdvisorAutoProxyCreator类中实现,委托给了findEligibleAdvisors方法去获取,看下它的实现:
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { List<Advisor> candidateAdvisors = findCandidateAdvisors(); List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; }
第一步调用findCandidateAdvisors方法先获取注册到Spring容器中的Advisor,在获取并解析注解了@Aspect的bean中的全部Advisor。
@Override protected List<Advisor> findCandidateAdvisors() { List<Advisor> advisors = super.findCandidateAdvisors(); advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); return advisors; }
this.aspectJAdvisorsBuilder.buildAspectJAdvisors()这块代码就是利用了aspectj来解析注解了@Aspect。
第二步调用findAdvisorsThatCanApply来过滤Advisor,Advisor(切点)包含了Pointcut(切点)和Advice(加强),findAdvisorsThatCanApply方法的过滤就是利用Advisor中Pointcut匹配Class或Method来达到过滤的目的。
第三步调用extendAdvisors方法,extendAdvisors在AnnotationAwareAspectJAutoProxyCreator做用就是在全部的advisors节点最前面插入一个Advisor(有advisors节点前提下),此Advisor比较特殊它的Pointcut是全类型匹配的(匹配全部Class和Method),它主要功能是在于它的Advice(加强),它的Advice实现是ExposeInvocationInterceptor类,看类的名称就知道,对外暴露的类,就是全部Advice调用链的第一环,ExposeInvocationInterceptor做用就是将调用信息存在ThreadLocal实现的上下文信息里,供调用链后续的Advice获取使用,能够看下它实现:
第四步若是存在advisors节点则调用sortAdvisors对其排序,这排序规则是根据Advisor里的order字段排序,固然若是存在第三步所说的特殊Advice它会排在最前面。
回到wrapIfNecessary方法获取到advisors接下去就是建立代理了。
建立代理对象调用的createProxy方法,来看下它的实现:
protected Object createProxy( Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) { ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.copyFrom(this); if (!proxyFactory.isProxyTargetClass()) { if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { evaluateProxyInterfaces(beanClass, proxyFactory); } } Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); for (Advisor advisor : advisors) { proxyFactory.addAdvisor(advisor); } proxyFactory.setTargetSource(targetSource); customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } return proxyFactory.getProxy(getProxyClassLoader()); }
代理对象的建立主要依托于代理工厂ProxyFactory类来建立,看下它的继承关系:
它和AnnotationAwareAspectJAutoProxyCreator都是继承了ProxyConfig类。
createProxy方法第一步先经过ProxyConfig里的copyFrom方法将AnnotationAwareAspectJAutoProxyCreator里的配置拷贝至ProxyFactory。
第二步从新设置proxyTargetClass,Java的Proxy代理能对象的前提是此对象必须实现了接口,这步若是原先proxyTargetClass设置false,须要先判断其是否实现了接口而且其接口非InitializingBean,DisposableBean,Aware,Spring自带接口。
第三步设置Advisors,而且冻结设置使后面不能修改Advisors。
最后调用ProxyFactory里的getProxy方法去代理对象。
ProxyFactory里代理的是有2种:
基于CGLIB来实现
基于Java原生的Proxy实现
主要取决于proxyTargetClass参数。
不管是CGLIB建立代理的CglibAopProxy仍是Java原生的Proxy实现建立JdkDynamicAopProxy都是基于接口AopProxy:
public interface AopProxy { Object getProxy(); Object getProxy(ClassLoader classLoader); }
AopProxy有2个方法,基于默认ClassLoader建立代理和基于用户自定义建立。
以JdkDynamicAopProxy实现为例看下实现。
JdkDynamicAopProxy实现了InvocationHandler,也就是代理方法的调用,会分发到自己。
看下其getProxy方法若是建立代理:
@Override public Object getProxy(ClassLoader classLoader) { if (logger.isDebugEnabled()) { logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource()); } Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }
先获取须要代理的接口,而后标记equals或hashCode方法是是否被覆盖,供调用时用,最后建立代理对象。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { ... try { ... target = targetSource.getTarget(); if (target != null) { targetClass = target.getClass(); } List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); if (chain.isEmpty()) { retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args); } else { invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); retVal = invocation.proceed(); } ... return retVal; } ... }
先获取代理的advice(加强器)数组(这里命名chain),若是advice直接调用被代理对象的方法,不然调用invocation.proceed()方法。invocation.proceed()的调用过程先是链式调用advice,最后执行其被代理对象的方法。看下proceed的实现:
public Object proceed() throws Throwable { if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { return proceed(); } } else { return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }
此方法的advice的链式调用的原理是递归调用:
proceed() -> invoke(this) -> proceed() ->...->invoke(this)->proceed()->invokeJoinpoint()
每作一次代码的加强,currentInterceptorIndex指针加1,直到全部的advice被调用完成,才执行其被代理对象的方法。