AOP是什么
面向切面的步调操持(Aspect-oriented programming,AOP,又译作面向方面的步调操持、剖面导向步调操持),是盘算机科学中的一种步调操持头脑,旨在将横切关注点与业务主体举行进一步分离,以提高步调代码的模块化程度。通过在现有代码根本上增长额外的关照(Advice)机制,能够对被声明为“切点(Pointcut)”的代码块举行同一管理与装饰。
怎么在Spring里利用AOP
在Spring里,AOP通过EnableAspectJAutoProxy注解开启。默认环境下,Spring会通过AopAutoConfiguration自动引入这个注解
@Configuration(proxyBeanMethods = false)@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)public class AopAutoConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnClass(Advice.class) static class AspectJAutoProxyingConfiguration { @Configuration(proxyBeanMethods = false) @EnableAspectJAutoProxy(proxyTargetClass = false) @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false") static class JdkDynamicAutoProxyConfiguration { } @Configuration(proxyBeanMethods = false) @EnableAspectJAutoProxy(proxyTargetClass = true) @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true) static class CglibAutoProxyConfiguration { } }}可以看到,假如我们不自动设置spring.aop.auto=false。那么Spring默认会启用AOP。接下来,我们可以通过在类上标注Aspect即可利用AOP
package org.example.aspect;@Aspect@Componentpublic class SampleAspect { @Pointcut("execution(* org.example.xxx.*.*(..))") private void executionPointcut() { } @After(value = "executionPointcut()") public void doAfter() { }}源码分析
1. AOP初始化
1.1 初始化AspectJAutoProxyRegistrar
EnableAspectJAutoProxy通过Import注解引入了AspectJAutoProxyRegistrar
@Import(AspectJAutoProxyRegistrar.class)public @interface EnableAspectJAutoProxy {}AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar,Spring在初始化AopAutoConfiguration时把全部通过Import注解引入的ImportBeanDefinitionRegistrar实现类拿出来举行初始化,并调用其registerBeanDefinitions函数
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);}1.2 初始化AnnotationAwareAspectJAutoProxyCreator
AspectJAutoProxyRegistrar 则在registerBeanDefinitions注册了一个AnnotationAwareAspectJAutoProxyCreator的BeanDefinition
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary( BeanDefinitionRegistry registry, @Nullable Object source) { return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source); }AnnotationAwareAspectJAutoProxyCreator实现了BeanPostProcessor,Spring会在初始化平凡Bean之前初始化全部BeanPostProcessor。
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext { public void refresh() throws BeansException, IllegalStateException { // 初始化BeanProcessor来拦截Bean的创建 registerBeanPostProcessors(beanFactory); // 初始化全部剩下的非懒加载的Bean,好比我们写的Service finishBeanFactoryInitialization(beanFactory); }}1.3 初始化切面方法跟切点
另外,AnnotationAwareAspectJAutoProxyCreator实现了InstantiationAwareBeanPostProcessor,Spring 会在Bean创建时调用其postProcessBeforeInstantiation方法对Bean举行处置处罚。
在第一次调用该方法时,AnnotationAwareAspectJAutoProxyCreator会初始化切面
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware { @Override public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) { Object cacheKey = getCacheKey(beanClass, beanName); if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) { //判定当前BeanName对应的Bean是否应该被署理 //并将判定效果生存下来,克制后续的后处置处罚方法重复盘算 //在第一次判定时,会在shouldSkip里扫描全部Bean举行切面初始化 if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return null; } } //假如为AbstractAutoProxyCreator注入了自界说的TargetSourceCreator //则通过TargetSourceCreator创建的Bean都被被AOP署理 //TargetSourceCreator默以为空 TargetSource targetSource = getCustomTargetSource(beanClass, beanName); if (targetSource != null) { if (StringUtils.hasLength(beanName)) { 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; }}切面初始化
public class BeanFactoryAspectJAdvisorsBuilder { public List<Advisor> buildAspectJAdvisors() { List<String> aspectNames = this.aspectBeanNames; //假如还未举行初始化 if (aspectNames == null) { synchronized (this) { aspectNames = this.aspectBeanNames; if (aspectNames == null) { List<Advisor> advisors = new ArrayList<>(); aspectNames = new ArrayList<>(); //拿到容器里全部的beanName String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Object.class, true, false); for (String beanName : beanNames) { Class<?> beanType = this.beanFactory.getType(beanName, false); //判定类上是否标注Aspect,以及判定该class是否已经被代码式的Aspectj处置处罚过 if (this.advisorFactory.isAspect(beanType)) { aspectNames.add(beanName); AspectMetadata amd = new AspectMetadata(beanType, beanName); MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName); //从类中拿到全部带有Before、Around等注解的方法, //将这些方法包装成MethodInterceptor放入Advisor,MethodInterceptor#invoke为增强方法的调用入口 //将Advisor排好次序构成List返回 List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory); this.advisorsCache.put(beanName, classAdvisors); advisors.addAll(classAdvisors); } } this.aspectBeanNames = aspectNames; return advisors; } } } }}Advisor排序
public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable { private static final Comparator<Method> adviceMethodComparator; static { Comparator<Method> adviceKindComparator = new ConvertingComparator<>( //按照注解次序设置方法对应的advisor的次序 //在AspectJAfterAdvice里,会先将哀求继承向拦截器链后传播, //对增强方法的调用是在背面的finnaly块里。以是这里的After次序纵然在AfterReturning前面也没关系 //另外,由于在finnly块里触发,以是纵然后续的调用抛出了未捕捉的非常,After指定的增强方法也会被实行 new InstanceComparator<>( Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class), (Converter<Method, Annotation>) method -> { //假如方法上没有标注上面的几个注解,则返回null,null会排在末了 AspectJAnnotation<?> ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method); return (ann != null ? ann.getAnnotation() : null); }); Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName); adviceMethodComparator = adviceKindComparator.thenComparing(methodNameComparator); }}判定method是否属于切面方法
public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable { public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrderInAspect, String aspectName) { //获取切点信息,假如candidateAdviceMethod不是切面方法,则返回null AspectJExpressionPointcut expressionPointcut = getPointcut( candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass()); if (expressionPointcut == null) { return null; } return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod, this, aspectInstanceFactory, declarationOrderInAspect, aspectName); } private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) { //在方法上查找Aspectj的干系注解(Around、After等) AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); if (aspectJAnnotation == null) { return null; } ... }}2. 天生署理对象
AbstractAutoProxyCreator实现了BeanPostProcessor,在创建Bean时,Spring会调用AbstractAutoProxyCreator#postProcessAfterInitialization对Bean举行处置处罚
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware { @Override public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (this.earlyProxyReferences.remove(cacheKey) != bean) { //对bean举行包装,返回署理bean return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { //假如bean有TargetSourceCreator创建,分析已经被署理过了,直接返回 if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { return bean; } //拿出缓存的检测的效果举行判定 if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } //开端判定bean是否可以被署理 if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } //根据切点Point的表达式得到符合当前bean的全部advisor //假如当前bean不在切点的指向中,则返回DO_NOT_PROXY Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); //创建署理对象,将全部advisor包装成DynamicAdvisedInterceptor, //其intercept方法为全部增强方法的同一入口,这个类来自Spring 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; }}选择署理对象的创建方式
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { @Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (!NativeDetector.inNativeImage() && (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) { Class<?> targetClass = config.getTargetClass(); //假如targetClass是接口范例大概是通过Proxy.getProxyClass天生的大概类名里包罗$$Lambda //则利用JDK动态署理 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) { return new JdkDynamicAopProxy(config); } //利用cglib,ASM修改字节码的方式生产署理类 return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } }}3. 访问署理对象
DispatcherServlet 找到对应的实例跟方法后通过反射举行调用(前面Spring Mvc博文里已分析过),此时会遍历署理对象上的全部MethodInterceptor,
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable { public Object proceed() throws Throwable { //假如拦截器遍历完了,则调用目标方法 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } //遍历全部增强器MethodInterceptor, //遍历方式是在MethodInterceptor里调用MethodInvocation#proceed //每次进入该方法,都会使currentInterceptorIndex增长1,从而告竣遍历 Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); //调用MethodInterceptor#invoke return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); }}增强方法实际实行的次序图
接下来看看每个增强注解对应的MethodInterceptor处置处罚类是怎么举行哀求处置处罚与转达的
1. AspectJAroundAdvice
public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor, Serializable { @Override @Nullable public Object invoke(MethodInvocation mi) throws Throwable { ... ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi; ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi); JoinPointMatch jpm = getJoinPointMatch(pmi); //调用Around对应的增强方法,并将mi传如增强方法 //mi持有了全部的拦截/增强器信息,通过Joinpoint#proceed实现哀求的转达 //以是,around增强方法里必要注意吸收Joinpont的实例并调用其proceed方法 return invokeAdviceMethod(pjp, jpm, null, null); }}2. MethodBeforeAdviceInterceptor
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable { private final MethodBeforeAdvice advice; public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) { Assert.notNull(advice, "Advice must not be null"); this.advice = advice; } @Override @Nullable public Object invoke(MethodInvocation mi) throws Throwable { //调用before增强方法 this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis()); //向后转达 return mi.proceed(); }}3. AspectJAfterAdvice
public class AspectJAfterAdvice extends AbstractAspectJAdvice implements MethodInterceptor, AfterAdvice, Serializable { public AspectJAfterAdvice( Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) { super(aspectJBeforeAdviceMethod, pointcut, aif); } @Override @Nullable public Object invoke(MethodInvocation mi) throws Throwable { try { //先向后转达 return mi.proceed(); } finally { //实行After方法 invokeAdviceMethod(getJoinPointMatch(), null, null); } }}4. AfterReturningAdviceInterceptor
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable { private final AfterReturningAdvice advice; public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) { Assert.notNull(advice, "Advice must not be null"); this.advice = advice; } @Override @Nullable public Object invoke(MethodInvocation mi) throws Throwable { //向后转达 Object retVal = mi.proceed(); //调用AfterReturning方法 this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis()); return retVal; }}5. AspectJAfterThrowingAdvice
public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice implements MethodInterceptor, AfterAdvice, Serializable { public AspectJAfterThrowingAdvice( Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) { super(aspectJBeforeAdviceMethod, pointcut, aif); } @Override @Nullable public Object invoke(MethodInvocation mi) throws Throwable { try { //向后转达 return mi.proceed(); } catch (Throwable ex) { //判定增强器上界说的非常范例是否匹配 if (shouldInvokeOnThrowing(ex)) { //调用AfterThrowing方法 invokeAdviceMethod(getJoinPointMatch(), null, ex); } throw ex; } } /** * In AspectJ semantics, after throwing advice that specifies a throwing clause * is only invoked if the thrown exception is a subtype of the given throwing type. */ private boolean shouldInvokeOnThrowing(Throwable ex) { return getDiscoveredThrowingType().isAssignableFrom(ex.getClass()); }}6. ExposeInvocationInterceptor
public final class ExposeInvocationInterceptor implements MethodInterceptor, PriorityOrdered, Serializable { private static final ThreadLocal<MethodInvocation> invocation = new NamedThreadLocal<>("Current AOP method invocation"); @Override @Nullable public Object invoke(MethodInvocation mi) throws Throwable { MethodInvocation oldInvocation = invocation.get(); //将MethodInvocation绑定到当火线程的当地变量里, //从而实如今其他地方访问MethodInvocation //但不发起如许做,由于AOP对于被署理对象来说应该是无感知的,不应该产生这种依赖 invocation.set(mi); try { return mi.proceed(); } finally { invocation.set(oldInvocation); } }} |