阅读代码说明 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
-
spring boot读取
@EnableAspectJAutoProxy注解上@Import(AspectJAutoProxyRegistrar.class)并将AspectJAutoProxyRegistrar解析成bean定义 -
AspectJAutoProxyRegistrar将AnnotationAwareAspectJAutoProxyCreator注册到BeanDefinitionRegistryclass AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { ... //注册创建aop创建器 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); ... } -
在spring bean的生命周期中执行
AnnotationAwareAspectJAutoProxyCreator相应的回调方法来匹配和创建aop代理对象,详情流程点击前往
3.2 激活方式二:AopAutoConfiguration
- spring boot默认情况下会通过spring spi的机制将
AopAutoConfiguration注册到BeanDefinitionRegistry - spring boot 解析出
AopAutoConfiguration内部类上的@EnableAspectJAutoProxy - 执行 方式一的流程
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);
}
}
}
参考文献
- spring boot 2.2.0-RELEASE 源码