带你走进不一样的spring aop

891 阅读9分钟

阅读代码说明 order:%d 代表代码阅读的顺序

1. 一个简单例子带你走进不一样的spring aop

背景:现在有一个需求通过注解的方式来实现方法执行时间的记录

1.1 自定义注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @Interface TimeRecord{
  
}

1.2 定义Advice

public class TimeRecordMethodInterceptor implements MethodInterceptor{
  public Object invoke(MethodInvocation invocation) throws Throwable{
    	//获取开始时间
    	long startTime = System.currentTimeMillis()
    	invocation.proceed();
    	//获取结束时间
    	long endTime = System.currentTimeMillis()
     	System.out.println(String.format("方法%s执行耗时%d毫秒" , invocation.getMethod().getName , endTime - startTime ))
  }
}

1.3 定义Pointcut

public TimeRecordPointcut implements Pointcut{
  
  @Override
	public ClassFilter getClassFilter() {
    //返回一个永久成立的class匹配器
		return ClassFilter.TRUE;
	}

	@Override
	public MethodMatcher getMethodMatcher() {
		return new MethodMatcher() {
			@Override
			public boolean matches(Method method, Class<?> targetClass) {
        //当方法上有@TimeRecord注解时,则进行拦截
				return method.isAnnotationPresent(TimeRecord.class);
			}

			@Override
			public boolean isRuntime() {
				return false;
			}

			@Override
			public boolean matches(Method method, Class<?> targetClass, Object... args) {
				return false;
			}
		};
	}
}

1.4 定义Advisor

public class TimeRecordAdvisor implements PointcutAdvisor{
  
  	private TimeRecordMethodInterceptor advice = new TimeRecordMethodInterceptor();
  
  	private TimeRecordPointcut pointcut = new TimeRecordPointcut();
  
  	//返回通知的匹配条件
    @Override
    public Pointcut getPointcut() {
      return this.pointcut;
    }
		// 返回通知
    @Override
    public Advice getAdvice() {
      return this.advice ;
    }
		// 默认返回false就好
    @Override
    public boolean isPerInstance() {
      return false;
    }
}

1.5注册Advisor

@Configuration
public class TimeRecordConfiguration{
  
  @Bean
  public PointcutAdvisor timeRecordAdvisor(){
    return new TimeRecordAdvisor();
  }
}

1.6使用

public interface UserService{
  	//获取用户id
  	long getUserId();
}

@Service
public class UserServiceImpl implements UserService{
  
  @TimeRecord
  public long getUserId(){
    try {
      // 休眠1秒
			Thread.sleep(1000);
		}catch (Exception e){
			throw new IllegalStateException(e);
		}
  }
  
}
@SpringBootTest
@RunWith(SpringRunner.class)
public class UserServiceTest{

    @Autowired
    private UserService userService;
    
    @Test
    public void getUserId(){
        userService.getUserId();
    }
}

2. 重新带你和spring aop中的角色来一个邂逅

2.1 Advice(通知)

  • 通知,用于执行拦截代码的地方,其中通知类型有以下几种

    接口名说明
    BeforeAdvice前置通知,用于目标方法执行前
    AfterAdvice后置通知,用于目标方法执行后(其中包括方法返回通知以及方法执行异常通知)
    MethodInterceptor最为特殊的一种通知 ,拥有所有通知类型能力
  • MethodInterceptor(方法拦截器)

    • 执行代码

      public MyMethodInterceptor implements MethodInterceptor{
        
        Object invoke(MethodInvocation invocation) throws Throwable{
          	//拦截操作
          	...
            //执行通知链的下一个通知,或者目标方法  
          	invocation.proceed();
            //拦截操作
            ...
        }
      }
      
    • MethodInvocation(方法调用器)

      • MethodInvocation#proceed :执行通知链的下一个通知,或者目标方法
      • MethodInvocation#getThis : 获取当前被代理的原对象
      • MethodInvocation#getArguments : 获取当前执行方法的入参列表
      • MethodInvocation#getMethod:获取当前被拦截方法的对象

2.2 Pointcut(切点 ,执行通知的前置条件)

  • 两个重要属性类型

    类型说明
    ClassFilter用于目标class匹配,判断被代理的目标class是否满足条件
    MethodMatcher用于目标方法匹配,判断被代理的目标方法是否满足条件
  • ClassFilter

    public interface ClassFilter {
    
    ...
    	// 匹配被代理的目标class 如果符合条件则返回true否则返回false
    	boolean matches(Class<?> clazz);
    ...
    
    }
    
  • MethodMatcher

    public interface MethodMatcher {
    
    	// 匹配被代理的目标方法是否满足条件
    	boolean matches(Method method, Class<?> targetClass);
    
    	// 是否启动实时匹配,当返回true时 则matches(Method, Class<?> , Object... )方法生效 ,默认返回false
    	boolean isRuntime();
    
    	// 根据运行时方法执行的状态进行匹配 其中args参数为被代理目标方法执行时的入参列表
    	boolean matches(Method method, Class<?> targetClass, Object... args);
    
    }
    

2.3 Advisor(通知者,用于提供Advice)

  • 提供了获取通知(Advice)的能力

  • 代码说明

    public interface Advisor {
      ...
      // 获取通知对象(可以是 前置 ,后置,环绕,异常后置等等类型)  
    	Advice getAdvice();
      ...
    }
    

2.4 IntroductionAdvisor

  • 拥有Avisor的能力

  • 并且增加了获取Advice的前置条件

  • 代码说明

    public interface IntroductionAdvisor extends Advisor, IntroductionInfo {
    	
    	ClassFilter getClassFilter();
    
    }
    

2.5 PointcutAdvisor

  • 拥有Avisor的能力

  • 并且增加了获取Advice的前置条件

  • 代码说明

    public interface PointcutAdvisor extends Advisor {
    	// 获取前置条件
    	Pointcut getPointcut();
    }
    

2.6 IntroductionAdvisor与PointcutAdvisor区别

接口名称目标方法匹配目标方法运行时匹配目标类匹配
PointcutAdvisor支持支持支持
IntroductionAdvisor不支持不支持支持

3. spring boot是怎么激活spring aop的呢?

3.1激活方式一:@EnableAspectJAutoProxy

  1. spring boot读取@EnableAspectJAutoProxy注解上@Import(AspectJAutoProxyRegistrar.class)并将AspectJAutoProxyRegistrar解析成bean定义

  2. AspectJAutoProxyRegistrarAnnotationAwareAspectJAutoProxyCreator注册到BeanDefinitionRegistry

    class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
    
    	@Override
    	public void registerBeanDefinitions(
    			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    		...
        //注册创建aop创建器  
    		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
    		...
    }
    
  3. 在spring bean的生命周期中执行AnnotationAwareAspectJAutoProxyCreator相应的回调方法来匹配和创建aop代理对象,详情流程点击前往

3.2 激活方式二:AopAutoConfiguration

  1. spring boot默认情况下会通过spring spi的机制将AopAutoConfiguration注册到BeanDefinitionRegistry
  2. spring boot 解析出AopAutoConfiguration内部类上的@EnableAspectJAutoProxy
  3. 执行 方式一的流程

4. spring aop是怎么创建代理对象的呢?

4.1自动aop代理对象创建器(AbstractAutoProxyCreator的子类)

类名说明
InfrastructureAdvisorAutoProxyCreator通过将Advisor列表进行匹配满足条件的bean并生成代理对象
AnnotationAwareAspectJAutoProxyCreator通过将Advisor列表进行匹配满足条件的bean并生成代理对象,并且提供了处理通过@AspectJ方式注册通知的情况
DefaultAdvisorAutoProxyCreator通过将Advisor列表与beanName前缀满进行匹配满足条件的bean并生成代理对象

4.2 AbstractAutoProxyCreator拥有spring bean哪些生命周期

  • BeanFactoryAware : BeanFactory的回调注入,默认情况下注入的是DefaultListableBeanFactory的实例
  • SmartInstantiationAwareBeanPostProcessor :bean 的后置处理器

4.3 创建代理对象

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
		implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
  
  
  // bean 生命周期回调方法,用于提前实例化对象用于解决循环依赖,主要用于methodFactory回调使用,具体可参考spring 官网ioc部分
  // order:1
  @Override
	public Object getEarlyBeanReference(Object bean, String beanName) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		this.earlyProxyReferences.put(cacheKey, bean);
    // 判断当前bean是否满足被作为aop代理对象的条件,如果满足则创建代理对象
		return wrapIfNecessary(bean, beanName, cacheKey);
	}
  
  
  //bean 生命周期回调方法 ,实例化前置回调
  //order:2
  @Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
		Object cacheKey = getCacheKey(beanClass, beanName);
    
		TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
    // 如果人为指定来TargetSource则使用TargetSource来创建代理对象,否则不做任何处理,默认情况下TargetSource为null
		if (targetSource != null) {
				...
		}
		return null;
	}
  
  //初始化化的后置操作
  //order:3
  @Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
      //由于在getEarlyBeanReference方法中put了earlyProxyReferences,因此一般情况下条件成立
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
        //判断当前bean是否满足被作为aop代理对象的条件,如果满足则创建代理对象,并返回替代原本的bean对象
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}
  
  
  //order:4
 protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		//如果匹配成功则创建代理对象,匹配逻辑会在下一章说明
		if (specificInterceptors != DO_NOT_PROXY) {
			...
      // 创建当前bean的代理对象  
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			...
			return proxy;
		}

		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
}
  
  //order:5
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {

		...
    //代理对象创建工厂,aop核心流程代码就在这个类里面,这个我们后面章节说  
		ProxyFactory proxyFactory = new ProxyFactory();
  	// 将当前对象(ProxyConfig)的配置复制到ProxyFactory中
		proxyFactory.copyFrom(this);
  	//
		if (!proxyFactory.isProxyTargetClass()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}
		//构建Advisor列表
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
  	//将Advisor列表设置到ProxyFactory Advisor具体作用会在后面章节说到
		proxyFactory.addAdvisors(advisors);
  	//设置目标对象,也就是被代理的原对象
		proxyFactory.setTargetSource(targetSource);
  	//一个代理工厂的扩展入口,默认没有做实现
		customizeProxyFactory(proxyFactory);
  	//设置是否允许删除Advisor列表中的元素
		proxyFactory.setFrozen(this.freezeProxy);
		...
		//创建代理对象
		return proxyFactory.getProxy(getProxyClassLoader());
	}

}

4.4 匹配满足以生成aop代理对象的bean

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
		implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
  
  	// order:1
  	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {

     	//通过bean匹配Advisor列表
      Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
      //如果bean匹配到Advisor列表,则创建aop代理对象,否则返回原本bean对象
      if (specificInterceptors != DO_NOT_PROXY) {
        ...
      }

      this.advisedBeans.put(cacheKey, Boolean.FALSE);
      return bean;
	}
}

public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {

	// order:2
	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    //进行依赖查找 从spring ioc容器中获取Advisor类型的bean列表
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
    //通过Advisor列表与beanClass进行匹配,过滤出满足条件的Advisor列表
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}
}

public abstract class AopUtils {
  // order:3
  public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
		// 匹配 Advisor列表中为IntroductionAdvisor类型且满足条件的Advisor
		for (Advisor candidate : candidateAdvisors) {
			if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
				eligibleAdvisors.add(candidate);
			}
		}
		boolean hasIntroductions = !eligibleAdvisors.isEmpty();
    // 匹配Advisor列表中为PointcutAdvisor类型且满足条件的Advisor
		for (Advisor candidate : candidateAdvisors) {
			if (candidate instanceof IntroductionAdvisor) {
				// already processed
				continue;
			}
			if (canApply(candidate, clazz, hasIntroductions)) {
				eligibleAdvisors.add(candidate);
			}
		}
		return eligibleAdvisors;
	}
  
  // order:4
  public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
    // 如果是IntroductionAdvisor类则只进行目标class的匹配
		if (advisor instanceof IntroductionAdvisor) {
			return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
		}
    // 如果为PointcutAdvisor类则进行 目标class 和 目标方面的匹配
		else if (advisor instanceof PointcutAdvisor) {
			PointcutAdvisor pca = (PointcutAdvisor) advisor;
			return canApply(pca.getPointcut(), targetClass, hasIntroductions);
		}
    //如果既不是IntroductionAdvisor也不是PointcutAdvisor返回匹配通过
		else {
			return true;
		}
	}

  // order:5
  public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
		// 进行ClassFilter#matches ,如果匹配失败则返回false
		if (!pc.getClassFilter().matches(targetClass)) {
			return false;
		}
		//获取 PointcutAdvisor#getPointcut#getMethodMatcher 中的 MethodMatcher
		MethodMatcher methodMatcher = pc.getMethodMatcher();
    // 如果方法匹配器为默认匹配器则返回true
		if (methodMatcher == MethodMatcher.TRUE) {
			// No need to iterate the methods if we're matching any method anyway...
			return true;
		}
		...
		for (Class<?> clazz : classes) {
      //获取目标class的所有公开方法
			Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
      //遍历所有方法 如果 methodMatcher 为IntroductionAwareMethodMatcher类型则调用
      // IntroductionAwareMethodMatcher#matches进行匹配,否则调用
      //MethodMatcher#matches 进行匹配 当任何一个方法匹配成功后返回true
			for (Method method : methods) {
				if (introductionAwareMethodMatcher != null ?
						introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
						methodMatcher.matches(method, targetClass)) {
					return true;
				}
			}
		}

		return false;
	}
}

5. spring aop执行流程是否是你想的那样?

说明:以jdk动态代理实现为例进行说明

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
  
//order:1  
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	    
     	...
      // 设置 当前代理对象到AopContext ,在同一个类进行方法调用时,使用AopContext#getCurrentProxy#xxx 进行调用方法可以避免 this调用情况下Aop失效,但是必须要先开启exposeProxy ,可以通过ProxyConfig进行开启
			if (this.advised.exposeProxy) {
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}

			// 通过目标class和目标方法匹配获取满足条件的通知
      // 1.先通过 ClassFilter进行匹配
      // 2.再通过 MethodMatcher进行匹配
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

			//如果没有匹配到通知 则直接调用目标方法
			if (chain.isEmpty()) {
				...
			}
      // 如果匹配到通知
			else {
				//构建方法调用器
				MethodInvocation invocation =
						new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// 进行通知链调用
				retVal = invocation.proceed();
			}
			...
			return retVal;
		

}
  
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
  
  
  //order:2
  public Object proceed() throws Throwable {
		// 如果通知链执行的偏移数等于通知链的最大偏移数,则说明通知链执行完成,则执行目标方法Method#invoke
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}
		//获取当前执行的通知
		Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    // 判断是否为动态方法匹配的通知 ,我们上面说过当MethodMatcher#isRuntime为true的情况下,会在运行时进行动态匹配是否满足执行advice的条件
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			...
      //动态匹配
			if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
        //执行MethodInterceptor#invoke
				return dm.interceptor.invoke(this);
			}
      // 如果动态匹配失败 则执行通知链的下一个通知
			else {
				return proceed();
			}
		}
    // 如果不需要进行动态方法匹配,则直接调用MethodInterceptor#invoke
		else {
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}
}

参考文献

  1. spring boot 2.2.0-RELEASE 源码

第一次写文章,如有哪里写的不对欢迎大家指正