Spring源码分析之AOP

广告位

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
@Component
public 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);
}
}

增强方法实际执行的顺序图

Spring源码分析之AOP

接下来看看每个增强注解对应的​​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);
}
}

}
本文来自网络,不代表技术学习分享_一航技术立场,转载请注明出处。

作者: 一航技术

上一篇
下一篇
广告位

发表回复

返回顶部