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);
}
}
增强方法实际执行的顺序图
接下来看看每个增强注解对应的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);
}
}
}