avatar

Spring注解驱动开发-AOP

什么是AOP,请看我之前写的手写一个AOP的实现

AOP场景演示

使用Spring的AOP功能演示一个案例,来说明一下Spring中AOP的使用
AOP:底层实现就是动态代理,指的是在程序运行期间动态的将某段代码切入到指定位置运行的编程方式
使用步骤
1、导入aop模块

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>

2、创建一个业务逻辑的类

public class MathCalculator {
public int div(int i,int j)
{
return i/j;
}
}

在业务逻辑运行的时候,将日志打印,方法之前、运行方法结束、方法出现异常我们都希望将日志打印出来。
3、定义一个日志切面类,日志切面类里面的方法需要动态感知MathCalculator.div运行到哪里,进行执行

public class LogAspects {
public void logStart()
{
System.out.println("触发运行。。。参数列表是:{}");
}
public void logEnd()
{
System.out.println("除法结束");
}
public void logReturn()
{
System.out.println("出发正常返回。。。运行结果:{}");
}
public void logException()
{
System.out.println("除法异常。。。异常信息:{}");
}
}

通知方式:

  • 前置通知(@Before):logStart(),在目标方法(div)运行之前运行
  • 后置通知(@After):logEnd(),在目标方法(div)运行之后运行,无论方法是正常结束还是异常结束
  • 返回通知(@AfterReturning):logReturn(),在目标方法(div)正常返回之后运行
  • 异常通知(@AfterThrowing):logException(),在目标方法(div)出现异常以后运行
  • 环绕通知(@Around):动态代理,手动推进目标方法的运行(joinPoint.procced())

4、给切面类的目标方法标注何时何地运行,(标注通知注解),并且可以获取到参数信息,以及返回值信息

@Aspect
public class LogAspects {
//抽取公共的切点表达式
//1、本类引用
//2、其他切面引用
@Pointcut("execution(public int com.zenshin.aop.MathCalculator.*(..))")//这种写法参照Spring的官方文档
public void pointcut(){};

//Before在目标方法之前切入,切入点表达式(指定在哪个方法切入)
@Before("pointcut()")
public void logStart(JoinPoint joinPoint)
{
Object[] args = joinPoint.getArgs();
String arg = "";
for (Object o:args) {
arg+=o.toString()+',';
}
System.out.println(joinPoint.getSignature().getName()+"触发运行。。。参数列表是:{"+arg+"}");
}
@After("pointcut()")
public void logEnd(JoinPoint joinPoint)
{
System.out.println(joinPoint.getSignature().getName()+"除法结束");
}
@AfterReturning(value = "pointcut()",returning = "result")
public void logReturn(Object result)
{
System.out.println("触发正常返回。。。运行结果:{"+result+"}");
}
@AfterThrowing(value = "pointcut()",throwing = "ex")
public void logException(JoinPoint joinPoint,Exception ex)
{
System.out.println(joinPoint.getSignature().getName()+"除法异常。。。异常信息:{"+ex+"}");
}
}
  • JoinPoint必须放在参数表的第一位,否则会报错

5、将切面类和目标逻辑类(目标方法)都加入到容器中;

@Configuration
public class MainConfigOfAOP {
@Bean
public MathCalculator mathCalculator()
{
return new MathCalculator();
}
@Bean
public LogAspects logAspects()
{
return new LogAspects();
}
}

6、必须告诉spring,哪个类是切面类——给切面类加一个注解(@Aspect)

@Aspect
public class LogAspects {
...
}

7、开启基于注解的AOP功能,在配置类上面标注一个注解@EnableAspectJAutoProxy

@EnableAspectJAutoProxy
@Configuration
public class MainConfigOfAOP {
...
}
<!--基于xml可以这样写,开启自动代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

8、编写测试方法,看一下切面能否成功

@Test
public void test01()
{
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAOP.class);
MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class);//这个类不用自己去new,要从容器中获取。
mathCalculator.div(1,2);
}
//得到的结果
/**
div触发运行。。。参数列表是:{1,1,}
div除法结束
触发正常返回。。。运行结果:{1}
*/

AOP原理

@EnableAspectJAutoProxy

进入该注解的实现

@Import(AspectJAutoProxyRegistrar.class) //导入了一个组件
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}

AspectJAutoProxyRegistrar是一个实现了ImportBeanDefinitionRegistrar接口的类,ImportBeanDefinitionRegistrar作用是给容器中导入组件,在IOC章节介绍过

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAwareAspectJAutoProxyCreator
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); //注册一个internalAutoProxyCreator类
//后面这个是根据属性去做一些操作
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}

}

AspectJAutoProxyRegistrar利用ImportBeanDefinitionRegistrar给容器中注册了一个bean:org.springframework.aop.config.internalAutoProxyCreator = AnnotationAwareAspectJAutoProxyCreator 这个类的意思是注解模式自动的切面代理创建器。这个是主要实现的类

AnnotationAwareAspectJAutoProxyCreator分析

这是该类的继承关系,该类的上层父类AbstractAutoProxyCreator实现了SmartInstantiationAwareBeanPostProcessor接口和BeanFactoryAware接口
SmartInstantiationAwareBeanPostProcessor:是一个后置处理器,在bean初始化完成前后做一些事情
BeanFactoryAware:用于自动注入bean工厂。获取bean用的。

接下来我门要看一看AbstractAutoProxyCreator类在初始化bean前后做了什么操作以及在获取bean工厂是怎么获取的,我们一步一步的进行分析

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
//实现BeanFactoryAware,将BeanFactoryAware注入进来
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
...
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
Object cacheKey = getCacheKey(beanClass, beanName);

if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
if (beanName != null) {
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
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;
}
...
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
}

那么我们再来看AbstractAdvisorAutoProxyCreator

public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {
//重写了setBeanFactory方法
@Override
public void setBeanFactory(BeanFactory beanFactory) {
super.setBeanFactory(beanFactory);
if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
throw new IllegalArgumentException(
"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
}
initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
}

protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
}
}

AspectJAwareAdvisorAutoProxyCreator没有重写方法,我们直接看AnnotationAwareAspectJAutoProxyCreator

public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
//重写了initBeanFactory方法。
@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.initBeanFactory(beanFactory);
if (this.aspectJAdvisorFactory == null) {
this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
}
this.aspectJAdvisorsBuilder =
new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}
}

我们将这个初始化AOP的代码关系看明白以后,我们看看创建的步骤
1、我们首先创建了一个IOC容器
2、注册配置类,调用refresh()刷新容器
3、在refresh()方法中有一个方法为registerBeanPostProcessors(beanFactory);注册bean的后置处理器,方便拦击bean的创建

  • 获取IOC容器已经定义了BeanPostProcessor接口的类
  • 给容器中加入一些别的BeanPostProcessor
  • 优先注册实现了PriorityOrdered接口的BeanPostProcessor
  • 再给容器中注册实现了Ordered接口的BeanPostProcessor
  • 最后注册没有实现优先级接口的BeanPostProcessor
  • 注册BeanPostProcessor实际上是创建对象,然后保存到容器中,创建出org.springframework.aop.config.internalAutoProxyCreator[AnnotationAwareAspectJAutoProxyCreator]
    • 创建bean实例
    • populateBean给bean的各种属性赋值
    • initializeBean:初始化bean
      • invokeAwareMethods():处理Aware接口的方法回调,这里的处理是BeanNameAwareBeanClassLoaderAwareBeanFactoryAware这三个,其余的是在后置处理器处理的
      • applyBeanPostProcessorsBeforeInitialization()应用后置处理器的PostProcessorsBeforeInitialization()方法
      • invokeInitMethods()执行初始化方法
      • applyBeanPostProcessorsAfterInitialization()执行后置处理器的PostProcessorsAfterInitialization()方法
    • AnnotationAwareAspectJAutoProxyCreator创建成功,并且在invokeAwareMethods()方法中调用了AnnotationAwareAspectJAutoProxyCreator.initBeanFactory()方法
  • BeanPostProcessor注册到BeanFactory

这样我们的AnnotationAwareAspectJAutoProxyCreator就加入到了IOC容器中,因为AnnotationAwareAspectJAutoProxyCreator也是一个后置处理器,会拦截bean的初始化过程,那么我们来看一看他到底在初始化的时候做了些什么
首先我们要注意一点,AnnotationAwareAspectJAutoProxyCreator的父类实现的是InstantiationAwareBeanPostProcessor的后置处理器
我们还是从创建容器开始,创建容器后有refresh()方法,其中有一个方法是finishBeanFactoryInitialization(beanFactory);创建剩余的bean,什么叫剩余的bean呢,就是在此之前已经创建了很特殊的bean,如后置处理器等,我们从这里开始分析AnnotationAwareAspectJAutoProxyCreator做了什么
1、finishBeanFactoryInitialization(beanFactory):创建单实例bean,这里的创建是创建除去上面创建后置处理器的bean剩下的bean

  • 遍历获取容器中左右的bean,依次创建对象getBean(beanName)
  • 在创建bean之前会去缓存中检查是否已经创建了相应的bean,如果创建了那么就包装一下返回,没有创建才会去创建,创建好的bean都会被缓存起来。
  • createBean(beanName, mbd, args)才是真正的创建bean
    • 创建bean之前,调用resolveBeforeInstantiation(beanName, mbdToUse),这句话有一个注释Give BeanPostProcessors a chance to return a proxy instead of the target bean instance,注释的意思是说给beanpostprocessor一个机会来返回代理而不是目标bean实例,在这里来创建一个代理对象实现AOP。其中最主要的两个方法
      • bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);拿到所有后置处理器,如果是实现了InstantiationAwareBeanPostProcessor的后置处理器,就执行postProcessBeforeInstantiation方法,所以实现了InstantiationAwareBeanPostProcessor的类。都会在创建bean之前对bean的创建做一个拦截从而能影响bean的创建。
      • bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);这是初始化后的后置处理器方法,因为上面如果创建代理成功,那么就已经初始化过了,所以需要在这里调用after拦截。
    • 如果不能返回代理对象,那就调用doCreateBean(beanName, mbdToUse, args)创建bean

分析一下如何创建的代理

之前说到,在创建bean之前,会调用resolveBeforeInstantiation()方法,这个方法会调用InstantiationAwareBeanPostProcessor接口的postProcessBeforeInstantiation()方法去尝试创建代理,那么这个postProcessBeforeInstantiation()方法是如何执行的呢?就要用到最上面我们分析的AbstractAutoProxyCreator中的postProcessBeforeInstantiation()方法了。接下来我们就来分析这个方法的实现,到底是如何创建代理对象的。
1、判断当前bean是否在adviceBeans中,adviceBeans里面包含了所有需要增强的bean,也就是需要代理的bean
2、isInfrastructureClass(beanClass)判断当前bean是否是基础类型的Advice、Pointcut、Advisor、AopInfrastructureBean或者是不是切面(看bean是不是有@Aspect注解)
3、shouldSkip(beanClass, beanName) 是否需要跳过,

  • 获取候选的增强器(切面里面的通知方法)
  • 获取完成后,判断是否是AspectJPointcutAdvisor类型的增强器
  • 如果不是这种类型的返回false

4、当上面都不成立的时候,下面的判断方法是为只有设置了目标源TargetSource才能来创建的,我们没有任何的TargetSourcecustom所有后面的也不会生效,所以这个创建bean不是在Before进行创建的,这里spring是直接返回null。
5、调用MathCalculator的初始化器将对象创建出来。
6、然后调用AbstractAutoProxyCreatorpostProcessAfterInitialization()方法,对初始化完的bean进行包装。

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) { //看一下是不是已经代理过了,如果没有那么去进行代理
return wrapIfNecessary(bean, beanName, cacheKey);//
}
}
return bean;
}
  • wrapIfNecessary(bean, beanName, cacheKey):如果有需要的话进行包装

    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
    return bean;
    }
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
    return bean;
    }
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
    }
    // Create proxy if we have advice.
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);//获取当前bean的通知方法和增强器
    if (specificInterceptors != DO_NOT_PROXY) {
    this.advisedBeans.put(cacheKey, Boolean.TRUE);
    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;
    }
  • getAdvicesAndAdvisorsForBean()

    • 获取当前bean的所有增强器(通知方法)
    • 找到能在当前bean使用的增强器(找哪些通知方法是需要切入当前bean的方法),就是根据我们在切面类上标注的注解来解析是否匹配。
    • 给增强器排序,因为增强器是有先后顺序的
  • 通过上述方法获取到了bean能用的增强器封装成Object[] specificInterceptors,保存当前bean到advisedBeans表示被增强处理了

  • 如果当前bean需要增强,创建当前bean的代理对象createProxy()

    protected Object createProxy(
    Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
    AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    }
    ProxyFactory proxyFactory = new ProxyFactory();//创建一个代理工厂
    proxyFactory.copyFrom(this);
    if (!proxyFactory.isProxyTargetClass()) {
    if (shouldProxyTargetClass(beanClass, beanName)) {
    proxyFactory.setProxyTargetClass(true);
    }
    else {
    evaluateProxyInterfaces(beanClass, proxyFactory);
    }
    }
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);//拿到所有当前bean能用的增强器
    proxyFactory.addAdvisors(advisors);
    proxyFactory.setTargetSource(targetSource);
    customizeProxyFactory(proxyFactory);
    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
    proxyFactory.setPreFiltered(true);
    }
    return proxyFactory.getProxy(getProxyClassLoader());
    }
    • 创建一个代理工厂
    • 获取当前bean能用的所有增强器,并加入到代理工厂中
    • proxyFactory.getProxy(getProxyClassLoader())用代理工厂创建对象
  • 我们看看spring是怎么帮我们创建代理的

    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
    Class<?> targetClass = config.getTargetClass();
    if (targetClass == null) {
    throw new AopConfigException("TargetSource cannot determine target class: " +
    "Either an interface or a target is required for proxy creation.");
    }
    if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
    return new JdkDynamicAopProxy(config);
    }
    return new ObjenesisCglibAopProxy(config);
    }
    else {
    return new JdkDynamicAopProxy(config);
    }
    }
    • 有两种创建代理对象的方法,一种是JdkDynamicAopProxyJDK代理,一种是ObjenesisCglibAopProxyCglib代理
    • 这两种代理方式可以参考我写的[java代理模式]、[Cglib使用教程]结合源码看一下。
  • 到此为止我们就得到了一个被增强(代理)的类,以后从容器中获取的类都是代理类,不再是原来new出来的类了,这样我们调用方法就可以调用切面了。

AOP执行流程

代理对象的创建流程上文已经分析过了,那么创建好以后它是如何执行的呢?

@Test
public void test01()
{
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAOP.class);
MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class);
mathCalculator.div(1,1);
}

首先我们来看一下这个测试方法,这个测试方法的mathCalculator类是从容器中拿的,从容器中拿出来以后就是已经被代理过的对象了,这个对象中保存了很多的详细信息(比如增强器、目标对象等等)
当运行div方法的时候,代理类就会将这个方法代理到CglibAopProxy类中的静态内部类DynamicAdvisedInterceptorintercept()方法中,因为DynamicAdvisedInterceptor实现了MethodInterceptor,参考Cglib动态代理,所有的方法都会走这个intercept()进行拦截,在这里面我们可以做很多事情对原本的div方法做增强,也就是所说的切面。

@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Class<?> targetClass = null;
Object target = null;
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null. Get as late as possible to minimize the time we
// "own" the target, in case it comes from a pool...
target = getTarget();
if (target != null) {
targetClass = target.getClass();
}
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse); //该方法就是执行真正的div方法
}
else {
// We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null) {
releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}

1、根据ProxyFactory对象获取目标方法的拦截器链List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

  • 如果获取的拦截器链是空的,那么就执行methodProxy.invoke(target, argsToUse),直接运行目标方法,
  • 如果有拦截器链,把要执行的目标对象,目标方法,拦截器链等信息传入创建一个CglibMethodInvocation对象,然后调用proceed()方法,

2、从上面可以看出,执行方法的时候主要有两步,获取拦截器链,包装CglibMethodInvocation对象,下面来一个一个的看

  • 我们来探究一下getInterceptorsAndDynamicInterceptionAdvice方法是做了什么

    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
    MethodCacheKey cacheKey = new MethodCacheKey(method);
    List<Object> cached = this.methodCache.get(cacheKey);
    if (cached == null) {
    cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
    this, method, targetClass);
    this.methodCache.put(cacheKey, cached);
    }
    return cached;
    }

    最主要的方法就是this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice()这里才是获取拦截器链的方法,其余的都是加入到缓存中。

  • 获取拦截器链的步骤

    @Override
    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
    Advised config, Method method, Class<?> targetClass) {
    // This is somewhat tricky... We have to process introductions first,
    // but we need to preserve order in the ultimate list.
    List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
    Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
    boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
    for (Advisor advisor : config.getAdvisors()) {
    if (advisor instanceof PointcutAdvisor) {
    // Add it conditionally.
    PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
    if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
    if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
    if (mm.isRuntime()) {
    // Creating a new object instance in the getInterceptors() method
    // isn't a problem as we normally cache created chains.
    for (MethodInterceptor interceptor : interceptors) {
    interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
    }
    }
    else {
    interceptorList.addAll(Arrays.asList(interceptors));
    }
    }
    }
    }
    else if (advisor instanceof IntroductionAdvisor) {
    IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
    if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
    Interceptor[] interceptors = registry.getInterceptors(advisor);
    interceptorList.addAll(Arrays.asList(interceptors));
    }
    }
    else {
    Interceptor[] interceptors = registry.getInterceptors(advisor);
    interceptorList.addAll(Arrays.asList(interceptors));
    }
    }
    return interceptorList;
    }

    1) List<Object> interceptorList首先创建一个list用来装拦截器链,长度为我们设置的拦截器方法和一个默认的方法;
    2)遍历所有的增强器,将所有的增强器包装为Interceptor:registry.getInterceptors(advisor)
    3) 如果我们的增强器是一个PointcutAdvisor,那么就将增强器转成MethodInterceptor,如果是MethodIntercepter直接加入集合中,如果不是,使用AdvisorAdapter将增强器转换成MethodInterceptor转换完后加入到MethodInterceptor数组中
    4)最终返回一个interceptorList,这就是一个拦截器链。
    5)将拦截器链包装成一个CglibMethodInvocation对象,然后调用proceed(),执行拦截器链
    6) 拦截器链:每一个通知方法又被包装为方法拦截器,利用MethodIntercepter机制封装成一个list,作为一条链去执行。

  • 拦截器链执行(proceed()执行过程)

    @Override
    public Object proceed() throws Throwable {
    // We start with an index of -1 and increment early.
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
    return invokeJoinpoint();
    }
    Object interceptorOrInterceptionAdvice =
    this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
    // Evaluate dynamic method matcher here: static part will already have
    // been evaluated and found to match.
    InterceptorAndDynamicMethodMatcher dm =
    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
    if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
    return dm.interceptor.invoke(this);
    }
    else {
    // Dynamic matching failed.
    // Skip this interceptor and invoke the next in the chain.
    return proceed();
    }
    }
    else {
    // It's an interceptor, so we just invoke it: The pointcut will have
    // been evaluated statically before this object was constructed.
    return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
    }

    我们来一点一点得分析,这是如何执行得

    • this.currentInterceptorIndex是-1,this.interceptorsAndDynamicMethodMatchers存的是拦截器链中增强器的个数,因为这个方法是一个递归,所以当增强器全部都已经完成就返回invokeJoinpoint(),invokeJoinpoint()是用来执行目标函数的目标方法的。
    • 链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再执行。
    • 拦截器链的机制能保证通知方法与目标方法的执行顺序。

总结

  • @EnableAspectJAutoProxy会开启AOP功能,给容器中注册一个组件AnnotationAwareAspectJAutoProxyCreator,
  • AnnotationAwareAspectJAutoProxyCreator是一个后置处理器,会在bean创建初始化完成以后,将bean包装一个代理注册到容器中。
  • 容器的创建流程
    • registerBeanPostProcessors(beanFactory);注册后置处理器
    • finishBeanFactoryInitialization(beanFactory);常见剩余的单实例bean
      • 创建业务逻辑组件和切面组件
      • AnnotationAwareAspectJAutoProxyCreator拦截组件创建过程
      • 组件创建完成以后,判断组件是否需要增强,如果要增强就把切面得通知方法包装成增强器(Advisor),给业务逻辑组件创建一个代理对象(Cglib)
  • 执行目标方法
    • 代理对象执行目标方法
    • CglibAopProxy.intercept()拦截
      • 得到目标方法得拦截器链(增强器包装成拦截器)
      • 利用拦截器得链式机制,一此进入每一个拦截器进行执行
      • 效果:正常执行->前置通知-》目标方法-》后置通知-》返回通知;
        出现异常->前置通知-》目标方法-》后置通知-》异常通知;
文章作者: zenshin
文章链接: https://zlh.giserhub.com/2020/05/03/spring/aop/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 zenshin's blog
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论