转载

Spring AOP原理分析

引入依赖后,类路径存在 Aspect.class、Advice.class、AnnotatedElement.class 因此自动化配置类AopAutoConfiguration生效。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
复制代码
@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class, AnnotatedElement.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

	@Configuration
	@EnableAspectJAutoProxy(proxyTargetClass = false)
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
			matchIfMissing = false)
	public static class JdkDynamicAutoProxyConfiguration {

	}

	@Configuration
	@EnableAspectJAutoProxy(proxyTargetClass = true)
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
			matchIfMissing = true)
	public static class CglibAutoProxyConfiguration {

	}

}
复制代码

完整的切面定义

@Aspect
@Component
public class LogAspect {

    @Pointcut("execution(public * com.mrglint.springbootdemo.service..*.*(..))")
    private void pointCut(){

    }

    /**
     * 切面作用于 com.mrglint.springbootdemo 下的子包以及子包下的子包,任意类的任意方法
     * @param joinPoint
     */
    @Before("pointCut()")
    public void doBefore(JoinPoint joinPoint) {
        System.out.println("doBefore run...");
    }

    @After("pointCut()")
    public void doAfter(JoinPoint joinpoint) {
        System.out.println("doAfter run...");
    }

    @AfterReturning(value = "pointCut()", returning = "res")
    public void doAfterReturning(JoinPoint joinPoint, Object res) {
        System.out.println("doAfterReturning run, result: " + res);
    }

    @AfterThrowing(value = "pointCut()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
        System.out.println("doAfterThrowing run, exception: " + e);
    }

    @Around("pointCut()")
    public Object doArround(ProceedingJoinPoint proceedingJoinPoint) {
        System.out.println("doArround run on before...");
        Object res = null;
        try {
            res = proceedingJoinPoint.proceed();
            System.out.println("doArround run on after");
        } catch (Throwable throwable) {
            System.out.println("doArround run on throw exception: " + throwable);
            throwable.printStackTrace();
        }
        return res;
    }

}
复制代码

暴露代理类到ThreadLocal

可以通过配置 exposeProxy = true来暴露代理对象到ThreadLocal中,之后在被代理类对象内部可以使用 AopContext.currentProxy() 来获取代理类对象

// 默认为false
@EnableAspectJAutoProxy(exposeProxy = true)
复制代码

创建代理流程

AnnotationAwareAspectJAutoProxyCreator结构

由@EnableAspectJAutoProxy导入的AspectJAutoProxyRegistrar注册到beanfactory中,作为一个BeanPostProcessor存在

Spring AOP原理分析

创建代理时序图

Spring AOP原理分析

调用代理

在了解调用代理的逻辑之前,我们来回顾创建代理对象的方法实现

// JdkDynamicAopProxy.getProxy
@Override
public Object getProxy() {
    return getProxy(ClassUtils.getDefaultClassLoader());
}

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
    if (logger.isTraceEnabled()) {
        logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
    }
    Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    // JDK动态代理,JdkDynamicAopProxy自身作为 InvocationHandler对象
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

复制代码

代理类执行代码

@Override
@Nullable
public Object proceed() throws Throwable {
    // We start with an index of -1 and increment early.
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        // 执行被代理方法
        return invokeJoinpoint();
    }

    // 获取第一个切面逻辑拦截器。一开始为 (-1 + 1) = 0,interceptorsAndDynamicMethodMatchers 中的第一个
    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;
        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 {
            // 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);
    }
}
复制代码
原文  https://juejin.im/post/5efd25cbe51d451dde2e4296
正文到此结束
Loading...