Spring AOP源码深入分析

目录
  • 1. 前言
  • 2. 术语
  • 3. 示例
  • 4. @EnableAspectJAutoProxy
  • 5. AbstractAutoProxyCreator
  • 6. 构建Advisor
  • 7. 创建代理对象
  • 8. DynamicAdvisedInterceptor
  • 9. CglibMethodInvocation
  • 10. Advice子类

1. 前言

Spring除了IOC和DI,还有另一个杀手锏功能——Spring AOP。AOP是一种面向切面的编程思想,它的关注点是横向的,不同于OOP的纵向。面向对象编程时,如果我们要给多个类引入同一个行为,唯一的方式就是使用继承,否则就要在这些类里面加入大量重复的代码,如此一来程序将不利于维护。于是,AOP横空出世,它弥补了OOP编程的弊端。Spring内部也有大量特性是通过AOP来实现的,比如我们熟知的数据库事务。

2. 术语

查看源码前,先了解一下AOP的相关术语。

连接点(Joinpoint)

Advice执行的位置,比如:方法前、方法后、发生异常时等等,Spring仅支持方法的连接点。

切点(Pointcut)

连接点的过滤条件,AOP通过切点定位到具体的连接点。

增强/通知(Advice)

应用在连接点的行为,增强的逻辑代码,分为:前置、后置、环绕、异常增强。

增强器(Advisor)

通知器由一个切点(Pointcut)和一个增强(Advice)组成。

切面(Aspect)

由切点(Pointcut)和增强(Advice)组成。

织入(Weaving)

将增强应用到目标连接点的过程,可以静态织入,也可以运行时织入。

目标(Target)

被增强的对象(方法)。

代理(Proxy)

向Target应用Advice之后创建的代理对象。

3. 示例

Spring AOP使用起来非常简单,这里提供一个小示例。

1、定义切面

@Aspect
@Component
public class MyAspectConfig {
    @Pointcut("execution(* com.javap.aop.*.*(..))")
    public void pointCut() {
    }
    /**
     * 每一个增强方法,都会被封装成Advisor对象
     *
     * @see Advisor
     */
    @Before("pointCut()")
    public void before() {
        System.err.println("before");
    }
    @After("pointCut()")
    public void after() {
        System.err.println("after");
    }
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.err.println("Around before");
        Object result = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
        System.err.println("Around after");
        return result;
    }
    @AfterReturning(value = "pointCut()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, String result) throws Throwable {
        System.err.println("afterReturning: " + result);
    }
    @AfterThrowing(value = "pointCut()", throwing = "e")
    public void afterThrowing(Exception e) throws Throwable {
        System.err.println("afterThrowing: " + e.getMessage());
    }
}

2、定义bean,也就是需要被增强的目标对象

@Component
public class Person {
    public String say() {
        System.err.println("say...");
        return "aabbccdd";
    }
    /**
     * final方法,子类无法重写,因此不能被增强
     */
    public final void eat() {
        System.err.println("eat...");
    }
}

3、加上@EnableAspectJAutoProxy注解,就可以启用AOP了。

@Configuration
@ComponentScan("com.javap.aop")
@EnableAspectJAutoProxy
public class AopApplication {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AopApplication.class);
        Person person = context.getBean(Person.class);
        person.say();
        person.eat();
    }
}

控制台输出:

Around before
before
say...
Around after
after
afterReturning: aabbccdd
eat...

4. @EnableAspectJAutoProxy

问题:为什么在启动类上,加上**@EnableAspectJAutoProxy**注解就可以开启AOP呢???

答案当然要在注解本身找了,该注解上有一个@Import注解,引入了AspectJAutoProxyRegistrar类。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
	/**
	 * 是否强制使用类代理模式:CGLIB代理
	 */
	boolean proxyTargetClass() default false;
	/**
	 * 是否暴露代理对象,以通过AopContext获取
	 */
	boolean exposeProxy() default false;
}

AspectJAutoProxyRegistrar类实现了Spring提供的ImportBeanDefinitionRegistrar接口并重写了registerBeanDefinitions()方法,如此一来Spring在启动时,就会触发AspectJAutoProxyRegistrar#registerBeanDefinitions()方法,该方法会向容器内注册一个特别重要的类AnnotationAwareAspectJAutoProxyCreator

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(
            AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        /**
         * 注册AnnotationAwareAspectJAutoProxyCreator类
         */
        AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
        // 获取注解信息
        AnnotationAttributes enableAspectJAutoProxy =
                AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
        if (enableAspectJAutoProxy != null) {
            /**
             * 将注解属性写入到BeanDefinition
             * proxyTargetClass:是否通过CGLIB类代理模式
             * exposeProxy:是否暴露代理类,以通过AopContext获取
             */
            if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
            if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
                AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
            }
        }
    }
}

AnnotationAwareAspectJAutoProxyCreator实现了BeanPostProcessor接口,属于Spring的扩展点之一,Spring在实例化bean实例后,会触发该扩展点,对bean做扩展和增强,也就是返回织入了Advice后的代理对象。

5. AbstractAutoProxyCreator

AnnotationAwareAspectJAutoProxyCreator既然实现了BeanPostProcessor接口,那么必然要重写postProcessAfterInitialization()方法来返回增强后的bean,重写方法在父类AbstractAutoProxyCreator里。

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        // 循环依赖,提前暴露bean时,代理对象可能已经生成
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            // 生成增强后的代理对象,如果有需要
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

Spring会调用wrapIfNecessary()方法来返回增强后的bean。**所有的bean都会被BeanPostProcessor处理,但并不是所有的bean都需要增强,Spring会根据切点表达式判断beanClass是否需要被增强。**这个判断过程是比较耗时的,因为要解析beanClass所有的方法去和切点表达式进行匹配,所以Spring加了一个Map缓存解析过的beanClass。

判断bean是否要增强也很简单,通过getAdvicesAndAdvisorsForBean()方法去解析能应用到beanClass的所有增强器Advisor,如果没有增强器可用于该beanClass,也就不需要增强,直接原样返回bean即可,否则基于Advisor去创建增强后的代理对象。

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        // 已增强
        return bean;
    }
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        // 已经解析过beanClass,且判定为无需增强
        return bean;
    }
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        // 无需增强
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }
    /**
     * 获取beanClass可用的Advisor
     */
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // 基于Advisor,创建代理对象
        Object proxy = createProxy(
                bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }
    // beanClass无可用的Advice,无需增强
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

6. 构建Advisor

bean是否要增强,是通过beanClass是否有可用的Advisor来判断的。那么,Advisor是怎么来的呢?

查找bean可用的Advisor的方法在AbstractAdvisorAutoProxyCreator#findEligibleAdvisors(),先从容器内找出所有的Advisor,也就是我们在@Aspect类里定义的各种增强方法,然后根据切点表达式过滤出可以应用到当前beanClass的Advisor。然后将一个特殊的拦截器ExposeInvocationInterceptor插入到首位,最后将拦截器排个序返回。

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    /**
     * 查找容器内所有的Advisor:@Aspect类里定义的各种增强方法
     */
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    /**
     * 根据切点表达式,过滤出可以应用到beanClass的Advisor
     */
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    /**
     * 将ExposeInvocationInterceptor拦截器插入到第一个
     */
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

构建Advisor的职责交给了BeanFactoryAspectJAdvisorsBuilder类的buildAspectJAdvisors()方法,它首先从容器内找出所有加了@Aspect注解的bean,然后解析bean所有加了@Pointcut@Around@Before@After@AfterReturning@AfterThrowing注解的方法,将它们封装成Advisor对象。

/**
*将bean里面加了指定注解的方法封装成对应的Advice
*@Before -> AspectJMethodBeforeAdvice
* Around -> AspectJAroundAdvice
*@After -> AspectJAfterAdvice
*.......
*/
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);

容器内的Advisor对象并不能都应用到目标bean对象,所以Spring还会调用findAdvisorsThatCanApply()方法过滤出当前beanClass可用的Advisor。

7. 创建代理对象

如果当前bean有可用的Advisor,也就意味着需要对bean做增强,此时会调用createProxy()方法创建增强后的代理对象。

问题:使用JDK代理还是CGLIB代理?

我们可以通过属性proxyTargetClass强制使用CGLIB代理,如果不指定,Spring的规则是:如果beanClass实现了接口,且接口至少有一个自定义方法,那么就用JDK代理,否则用CGLIB代理。

protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {
    // 获取beanClass实现的所有接口
    Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());
    boolean hasReasonableProxyInterface = false;
    /**
     * 遍历接口
     * 1.非配置的回调接口,即Spring内置的接口不算,例如InitializingBean、Aware等接口
     * 2.非内部语言接口,例如GroovyObject
     * 3.接口至少有一个自定义方法
     */
    for (Class<?> ifc : targetInterfaces) {
        if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) &&
                ifc.getMethods().length > 0) {
            hasReasonableProxyInterface = true;
            break;
        }
    }
    if (hasReasonableProxyInterface) {
        // Must allow for introductions; can't just set interfaces to the target's interfaces only.
        for (Class<?> ifc : targetInterfaces) {
            proxyFactory.addInterface(ifc);
        }
    } else {
        // 没有实现有效接口,使用CGLIB代理
        proxyFactory.setProxyTargetClass(true);
    }
}

最终,Spring会通过ProxyFactory去创建代理对象。

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
                             @Nullable Object[] specificInterceptors, TargetSource targetSource) {
    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
        AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    }
    // 基于ProxyFactory创建代理对象
    ProxyFactory proxyFactory = new ProxyFactory();
    // 属性赋值给ProxyFactory
    proxyFactory.copyFrom(this);
    /**
     * 判断使用JDK代理还是CGLIB代理
     * 如果beanClass实现了接口,且接口至少有一个自定义方法,则使用JDK代理
     * 否则CGLIB代理
     */
    if (!proxyFactory.isProxyTargetClass()) {
        if (shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        } else {
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    proxyFactory.addAdvisors(advisors);
    proxyFactory.setTargetSource(targetSource);
    customizeProxyFactory(proxyFactory);
    // 是否冻结,也就是Advisor不可再变更
    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }
    // 创建动态代理  两种方式 JDK CGlib
    return proxyFactory.getProxy(getProxyClassLoader());
}

AopProxy有两种实现,分别是**JdkDynamicAopProxy****CglibAopProxy****,前者使用JDK动态代理的方式将Advice织入bean,后者通过CGLIB生成子类的方式将Advice织入bean。**我们以CGLIB为例,创建代理对象的方法是CglibAopProxy#getProxy()

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
    if (logger.isTraceEnabled()) {
        logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
    }
    try {
        Class<?> rootClass = this.advised.getTargetClass();
        Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

        Class<?> proxySuperClass = rootClass;
        if (ClassUtils.isCglibProxyClass(rootClass)) {
            proxySuperClass = rootClass.getSuperclass();
            Class<?>[] additionalInterfaces = rootClass.getInterfaces();
            for (Class<?> additionalInterface : additionalInterfaces) {
                this.advised.addInterface(additionalInterface);
            }
        }
        // Validate the class, writing log messages as necessary.
        validateClassIfNecessary(proxySuperClass, classLoader);
        // Configure CGLIB Enhancer...
        Enhancer enhancer = createEnhancer();
        if (classLoader != null) {
            enhancer.setClassLoader(classLoader);
            if (classLoader instanceof SmartClassLoader &&
                    ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                enhancer.setUseCache(false);
            }
        }
        enhancer.setSuperclass(proxySuperClass);
        /**
         * 会实现接口
         * @see org.springframework.aop.SpringProxy
         * @see org.springframework.aop.framework.Advised
         */
        enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
        enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
        enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
        /**
         * 获取方法回调,AOP主要看
         * @see DynamicAdvisedInterceptor
         */
        Callback[] callbacks = getCallbacks(rootClass);
        Class<?>[] types = new Class<?>[callbacks.length];
        for (int x = 0; x < types.length; x++) {
            types[x] = callbacks[x].getClass();
        }
        // fixedInterceptorMap only populated at this point, after getCallbacks call above
        enhancer.setCallbackFilter(new ProxyCallbackFilter(
                this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
        enhancer.setCallbackTypes(types);
        // Generate the proxy class and create a proxy instance.
        return createProxyClassAndInstance(enhancer, callbacks);
    } catch (CodeGenerationException | IllegalArgumentException ex) {
        throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
                ": Common causes of this problem include using a final class or a non-visible class",
                ex);
    } catch (Throwable ex) {
        // TargetSource.getTarget() failed
        throw new AopConfigException("Unexpected AOP exception", ex);
    }
}

Spring会通过Enhancer去创建子类对象来增强目标bean,生成的子类默认会实现org.springframework.aop.SpringProxy接口用来标记它是一个Spring生成的代理类。我们重点看给Enhancer对象设置的Callback,因为它会对方法做拦截,也就是说,我们调用子类的增强方法,其实就是在调用Callback#intercept()。Spring考虑的比较全面,会针对mainequalshashCode等方法做处理,针对AOP我们主要看AopInterceptor即可。

/**
* Spring考虑了很多情况,
*比如对main、equals、hashCode方法的拦截
*AOP主要看aopInterceptor
*/
Callback[] mainCallbacks = new Callback[]{
aopInterceptor,ll for normal advice
targetInterceptor,// invoke target without considering advice,if optimized
new SerializableNo0p(),l/ no override for methods mapped to this
targetDispatcher, this.advisedDispatcher,
new EqualsInterceptor(this.advised),
new HashCodeInterceptor(this.advised)
};

aopInterceptor是DynamicAdvisedInterceptor子类对象,用于处理AOP方法调用,也就是说,AOP增强逻辑就在DynamicAdvisedInterceptor#intercept()里。

// Choose an "aop" interceptor (used for AOP calls).
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

8. DynamicAdvisedInterceptor

调用CGLIB增强子类的方法,其实会触发DynamicAdvisedInterceptor#intercept()方法,看看Spring增强的逻辑。

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    Object oldProxy = null;
    boolean setProxyContext = false;
    Object target = null;
    TargetSource targetSource = this.advised.getTargetSource();
    try {
        /**
         * 是否要暴露代理对象,以通过AopContext获取
         * 写入ThreadLocal
         */
        if (this.advised.exposeProxy) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }
        /**
         * 获取目标Bean实例
         * 如果是prototype 此时会创建新的实例
         */
        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);
        /**
         * 获取方法能应用到的Advice,拦截器调用链
         * @see org.springframework.aop.interceptor.ExposeInvocationInterceptor
         * @see org.springframework.aop.aspectj.AspectJAfterThrowingAdvice
         * @see org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor
         * @see org.springframework.aop.aspectj.AspectJAfterAdvice
         * @see org.springframework.aop.aspectj.AspectJAroundAdvice
         * @see org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor
         */
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        Object retVal;
        if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
            /**
             * 没有Advice,直接调用父类方法
             */
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = methodProxy.invoke(target, argsToUse);
        } else {
            retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
        }
        // 处理一下返回结果的类型
        retVal = processReturnType(proxy, target, method, retVal);
        return retVal;
    } finally {
        if (target != null && !targetSource.isStatic()) {
            targetSource.releaseTarget(target);
        }
        if (setProxyContext) {
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}

方法拦截器主要做了三件事:

  • 判断是否要暴露代理对象,如果要则写入ThreadLocal
  • 获取方法能应用到的Advice,构建拦截器调用链
  • 触发拦截器调用链

如果方法没有可用的Advice,也就不需要增强,直接调用父类方法即可。反之方法需要增强,Spring会new一个CglibMethodInvocation对象,触发拦截器调用链。

9. CglibMethodInvocation

CglibMethodInvocation#proceed()方法会触发拦截器调用链,Spring通过一个int变量currentInterceptorIndex来记录当前执行的拦截器索引,通过和总的拦截器数量判断是否调用完所有的拦截器,如果是则通过invokeJoinpoint()方法去调用目标方法,反之则去执行Advice增强。

public Object proceed() throws Throwable {
    /**
     * currentInterceptorIndex 当前执行的拦截器索引
     * interceptorsAndDynamicMethodMatchers.size() 所有拦击器个数
     * 执行完最后一个拦截器,就要执行目标方法了
     */
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        // 最终反射调用目标方法
        return invokeJoinpoint();
    }
	// 触发Advice增强
    Object interceptorOrInterceptionAdvice =
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
        InterceptorAndDynamicMethodMatcher dm =
                (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
        Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
        if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
            return dm.interceptor.invoke(this);
        } else {
            return proceed();
        }
    } else {
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

10. Advice子类

Spring AOP提供了五种Advice增强,分别是通过@Around@Before@After@AfterReturning@AfterThrowing注解标记的方法。这五种Advice分别对应五个Advice子类实现。

1、AspectJAfterThrowingAdvice

先走下一个拦截器,只有在发生异常时,才触发的Advice。

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
    try {
        // 先走下一个拦截器
        return mi.proceed();
    } catch (Throwable ex) {
        if (shouldInvokeOnThrowing(ex)) {
            /**
             * 只有发生异常了,才会执行@AfterThrowing Advice
             */
            invokeAdviceMethod(getJoinPointMatch(), null, ex);
        }
        throw ex;
    }
}

2、AfterReturningAdviceInterceptor

走剩下所有的拦截器,拿到返回结果。正常执行完毕才触发的Advice,如果发生异常则不触发。

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
    // 直接走剩下的拦截器,拿到返回结果
    Object retVal = mi.proceed();
    /**
     * 正常执行完毕,才触发 @AfterReturning Advice
     * 如果期间发生异常,则不触发
     */
    this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
    return retVal;
}

3、AspectJAfterAdvice

先走下一个拦截器,执行完毕再最终调用的Advice,不论是否发生异常。

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
    try {
        /**
         * 先走下一个拦截器,执行完毕再最终调用@After Advice
         */
        return mi.proceed();
    } finally {
        /**
         * 执行@After Advice方法
         * @After Advice一定会被调用,不管是否发生异常,因为在finally
         */
        invokeAdviceMethod(getJoinPointMatch(), null, null);
    }
}

4、AspectJAroundAdvice

直接触发Advice,是否继续调用后续Advice由我们自己决定。

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
    if (!(mi instanceof ProxyMethodInvocation)) {
        throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
    }
    /**
     * 直接触发Advice,是否继续调用后续Advice,由@Around Advice自己决定
     */
    ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
    ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
    JoinPointMatch jpm = getJoinPointMatch(pmi);
    return invokeAdviceMethod(pjp, jpm, null, null);
}

5、MethodBeforeAdviceInterceptor

先触发当前Advice,再调用下一个Advice。

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
    /**
     * 先触发 @Before Advice
     * 再调用下一个Advice
     */
    this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
    return mi.proceed();
}

到此这篇关于Spring AOP源码深入分析的文章就介绍到这了,更多相关Spring AOP内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Spring AOP的概念与实现过程详解

    目录 Aop 实现aop方式一 实现aop方式二 注解实现aop Aop 什么是Aop? AOP就是面向切面编程,通过预编译方式以及运行期间的动态代理技术来实现程序的统一维护功能. 什么是切面,我理解的切面就是两个方法之间,两个对象之间,两个模块之间就是一个切面.假设在两个模块之间需要共同执行一系列操作,并且最后将这一系列操作注入到两个模块之间的指定位置.此时这一系列操作就是切面,注入这些操作的位置称之为切点. 举例:公司员工上班 A员工上班需要在前台进行打卡,同样的B员工…其他员工都需要在前台

  • Spring AOP如何自定义注解实现审计或日志记录(完整代码)

    目录 环境准备 项目结构 自定义审计注解 定义切面类 定义返回值处理基类 定义返回值处理子类 定义功能模块类 定义操作类 定义审计信息实体类 书写mapper文件 开启AOP拦截 注解配置 总结 环境准备 JDK 1.8,Springboot 2.1.3.RELEASE,spring-boot-starter-aop.2.1.4.RELEASE.jar,aspectjrt.1.9.2.jar,aspectjweaver.1.9.2.jar,pom依赖如下: <!-- 添加aspectj -->

  • SpringBoot使用AOP与注解实现请求参数自动填充流程详解

    首先定义一个加在方法上的注解 import java.lang.annotation.*; /** * 开启自动参数填充 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) @Documented @Inherited public @interface AutoParameterFill { /** * 要填充的字段名,不写的话默认下面类的子类中的字段都要填充 * * @see AutoParameterFi

  • Spring AOP实现声明式事务机制源码解析

    目录 一.声明式全局事务 二.源码 三.小结: 一.声明式全局事务 在Seata示例工程中,能看到@GlobalTransactional,如下方法示例: @GlobalTransactional public boolean purchase(long accountId, long stockId, long quantity) { String xid = RootContext.getXID(); LOGGER.info("New Transaction Begins: " +

  • Spring AOP与AspectJ的对比及应用详解

    目录 1 简介 2 Spring AOP vs AspectJ 2.1 织入方式 2.2 Joinpoints 2.3 性能 3 Spring Boot使用AspectJ 3.1 引入依赖 3.2 被AOP的对象 3.3 配置Aspect 3.4 maven插件 3.5 执行及测试 3.6 一些遇到的错误 4 总结 1 简介 AOP,即面向切面编程是很常用的技术,特别是在Java Web开发中.而最流行的AOP框架分别是Spring AOP和AspectJ. 2 Spring AOP vs As

  • Spring AOP统一功能处理示例代码

    目录 1. 什么是Spring AOP? 2. 为什要用 AOP? 3. Spring AOP 应该怎么学习呢? 3.1AOP组成 3.1.1 切面(Aspect) 3.1.2 连接点(Join Point) 3.1.3 切点(Pointcut) 3.1.4 通知(Advice) 3.2 Spring AOP实现 3.2.1 添加 AOP 框架支持 3.2.2 定义切面和切点. 3.2.3 定义相关通知 3.3 Spring AOP 实现原理 3.3.1 动态代理 3.3.2 JDK和CGLIB

  • Spring使用AOP完成统一结果封装实例demo

    目录 Spring使用AOP完成统一结果封装 Demo实现 Spring使用AOP完成统一结果封装 起因:自己写项目的时候忍受不了每个方法都要写一个retrun Result.success();和 retrun Result.error();,同时想到项目运行时异常的统一捕捉处理,于是我就在想有没有一种方法能够快捷有效的实现统一返回结果格式的方法.同时也能够比较方便的设置各种参数方便使用,于是我就想到AOP. Demo实现 引入依赖 <dependency> <groupId>o

  • Spring AOP源码深入分析

    目录 1. 前言 2. 术语 3. 示例 4. @EnableAspectJAutoProxy 5. AbstractAutoProxyCreator 6. 构建Advisor 7. 创建代理对象 8. DynamicAdvisedInterceptor 9. CglibMethodInvocation 10. Advice子类 1. 前言 Spring除了IOC和DI,还有另一个杀手锏功能——Spring AOP.AOP是一种面向切面的编程思想,它的关注点是横向的,不同于OOP的纵向.面向对象

  • Spring Aop 源码增强获取分享

    目录 1 前言 2 spring 增强器 3 总结 1 前言 在前文中,已经讲述了 AOP的后置处理器使用和方法,在本文中继续分享增强信息相关的源码,这里才是 AOP 的核心代码. 2 spring 增强器 之前已经讲述了 spring AbstractApplicationContext.refresh 方法,在以下方法中都会处理会处理 BeanPostProcessor 接口. invokeBeanFactoryPostProcessors registerBeanPostProcessor

  • Java Spring AOP源码解析之事务实现原理

    目录 不用Spring管理事务? 编程式事务管理 使用PlatformTransactionManager 使用TransactionTemplate 声明式事务管理 使用@Transactional注解 源码解析 参考博客 总结 不用Spring管理事务? 让我们先来看一下不用spring管理事务时,各种框架是如何管理事务的 使用JDBC来管理事务 使用Hibernate来管理事务 业务逻辑和事务代码是耦合到一块的,并且和框架的具体api绑定了.当我们换一种框架来实现时,里面对事务控制的代码就

  • Spring IOC源码之bean的注册过程讲解

    目录 BeanDefition加载注册过程 进入obtainFreshBeanFactory方法 ​进入AbstractRefreshableApplicationContext类中的refreshBeanFactory方法 进入AbstractXmlApplicationContext类的loadBeanDefinitions方法 进入doLoadBeanDefinitions方法 Spring IoC--Bean的创建和初始化 Spring介绍 IoC介绍 IoC是什么 IoC能做什么 源码

  • Spring IOC源码剖析_如何整体认知Spring体系结构

    目录 如何整体认知Spring体系结构 一.来自官网的Spring 二.Spring的优缺点 三.一张图理解Spring Framework 4.x 四.详解"七层"宝塔 1. 核心容器(Core Container) 2. 数据访问/集成(Data Access/Integration)层 3. Web层 4. AOP(Aspect Oriented Programming)模块 5. 植入(Instrumentation)模块 6. 消息传输(Messaging) 7. 测试(Te

  • Spring cache源码深度解析

    Spring cache是一个缓存API层,封装了对多种缓存的通用操作,可以借助注解方便地为程序添加缓存功能.常见的注解有@Cacheable.@CachePut.@CacheEvict,有没有想过背后的原理是什么?楼主带着疑问,阅读完Spring cache的源码后,做一个简要总结.先说结论,核心逻辑在CacheAspectSupport类,封装了所有的缓存操作的主体逻辑,下面详细介绍. 题外话:如何阅读开源代码? 有2种方法,可以结合起来使用: 静态代码阅读:查找关键类.方法的usage之处

  • Spring cache源码深度解析

    目录 前言 题外话:如何阅读开源代码? 核心类图 源码分析(带注释解释) 1.解析注解 2.逻辑执行 总结 前言 Spring cache是一个缓存API层,封装了对多种缓存的通用操作,可以借助注解方便地为程序添加缓存功能. 常见的注解有@Cacheable.@CachePut.@CacheEvict,有没有想过背后的原理是什么?楼主带着疑问,阅读完Spring cache的源码后,做一个简要总结. 先说结论,核心逻辑在CacheAspectSupport类,封装了所有的缓存操作的主体逻辑,下面

  • Spring Security源码解析之权限访问控制是如何做到的

    〇.前文回顾 在实战篇<话说Spring Security权限管理(源码详解)>我们学习了Spring Security强大的访问控制能力,只需要进行寥寥几行的配置就能做到权限的控制,本篇来看看它到底是如何做到的. 一.再聊过滤器链 源码篇中反复提到,请求进来需要经过的是一堆过滤器形成的过滤器链,走完过滤器链未抛出异常则可以继续访问后台接口资源,而最后一个过滤器就是来判断请求是否有权限继续访问后台资源,如果没有则会将拒绝访问的异常往上向异常过滤器抛,异常过滤器会对异常进行翻译,然后响应给客户端

  • JDK数组阻塞队列源码深入分析总结

    目录 前言 阻塞队列的功能 数组阻塞队列设计 数组的循环使用 字段设计 构造函数 put函数 take函数 offer函数 add函数 poll函数 总结 前言 在前面一篇文章从零开始自己动手写阻塞队列当中我们仔细介绍了阻塞队列提供给我们的功能,以及他的实现原理,并且基于谈到的内容我们自己实现了一个低配版的数组阻塞队列.在这篇文章当中我们将仔细介绍JDK具体是如何实现数组阻塞队列的. 阻塞队列的功能 而在本篇文章所谈到的阻塞队列当中,是在并发的情况下使用的,上面所谈到的是队列是并发不安全的,但是

  • Java线程池ThreadPoolExecutor源码深入分析

    1.线程池Executors的简单使用 1)创建一个线程的线程池. Executors.newSingleThreadExecutor(); //创建的源码 public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new Linke

随机推荐