java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring AOP动态代理到注解

Spring AOP底层源码深度解析之从动态代理到注解实现的完整架构

作者:alonewolf_99

这篇文章详细介绍了Spring AOP的核心概念、实现方式、配置方法以及高级特性,从动态代理基础到性能优化,全面涵盖了Spring AOP的各个方面,帮助开发者深入理解并有效地应用Spring AOP,感兴趣的朋友跟随小编一起看看吧

一、动态代理基础:Spring AOP的基石

1.1 代理模式的核心思想

代理模式的本质是:为其他对象提供一种代理以控制对这个对象的访问。在Spring AOP中,我们通过代理模式来增强目标对象的方法。

1.2 JDK动态代理与CGLIB对比

1.2.1 CGLIB动态代理示例

public class UserService {
    public void test() {
        System.out.println("test...");
    }
}
// CGLIB动态代理
UserService target = new UserService();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
enhancer.setCallback(new MethodInterceptor() {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, 
                           MethodProxy proxy) throws Throwable {
        System.out.println("before...");
        Object result = proxy.invoke(target, args);
        System.out.println("after...");
        return result;
    }
});
UserService userService = (UserService) enhancer.create();
userService.test();

CGLIB特点

1.2.2 JDK动态代理示例

public interface UserInterface {
    void test();
}
public class UserService implements UserInterface {
    public void test() {
        System.out.println("test...");
    }
}
// JDK动态代理
UserService target = new UserService();
UserInterface proxy = (UserInterface) Proxy.newProxyInstance(
    UserService.class.getClassLoader(),
    new Class[]{UserInterface.class},
    new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) 
                throws Throwable {
            System.out.println("before...");
            Object result = method.invoke(target, args);
            System.out.println("after...");
            return result;
        }
    }
);
proxy.test();

JDK动态代理特点

1.3 Spring的选择策略

Spring通过ProxyFactory统一了两种动态代理技术的使用,并根据以下规则自动选择:

// ProxyFactory选择代理类型的逻辑
if (config.isOptimize() || config.isProxyTargetClass() || 
    hasNoUserSuppliedProxyInterfaces(config)) {
    Class<?> targetClass = config.getTargetClass();
    if (targetClass == null) {
        throw new AopConfigException("TargetSource cannot determine target class");
    }
    // 目标类是接口,使用JDK动态代理
    if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
        return new JdkDynamicAopProxy(config);
    }
    // 否则使用CGLIB
    return new ObjenesisCglibAopProxy(config);
} else {
    // 使用JDK动态代理
    return new JdkDynamicAopProxy(config);
}

选择规则总结

二、Spring AOP核心概念详解

2.1 ProxyFactory:统一的代理工厂

ProxyFactory是Spring提供的统一代理创建工厂,它屏蔽了底层动态代理技术的差异:

UserService target = new UserService();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.addAdvice(new MethodInterceptor() {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("before...");
        Object result = invocation.proceed();
        System.out.println("after...");
        return result;
    }
});
UserInterface userService = (UserInterface) proxyFactory.getProxy();
userService.test();

2.2 Advice:通知的类型

Spring AOP提供了五种类型的通知,对应AspectJ的五个注解:

通知类型对应注解执行时机
Before Advice@Before方法执行前
After Returning Advice@AfterReturning方法正常返回后
After Throwing Advice@AfterThrowing方法抛出异常后
After (Finally) Advice@After方法执行后(finally)
Around Advice@Around方法执行前后(最强大)

Around Advice示例

@Around("execution(* com.example.service.*.*(..))")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
    // 方法执行前逻辑
    System.out.println("Before method: " + joinPoint.getSignature().getName());
    try {
        // 执行目标方法
        Object result = joinPoint.proceed();
        // 方法正常返回后逻辑
        System.out.println("After method returning");
        return result;
    } catch (Exception e) {
        // 方法抛出异常后逻辑
        System.out.println("After method throwing: " + e.getMessage());
        throw e;
    } finally {
        // 方法执行后逻辑(一定会执行)
        System.out.println("After method (finally)");
    }
}

2.3 Advisor:切面 = 切点 + 通知

Advisor是Spring AOP的核心概念,它将Pointcut(切点)和Advice(通知)组合在一起:

UserService target = new UserService();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.addAdvisor(new PointcutAdvisor() {
    @Override
    public Pointcut getPointcut() {
        // 定义切点:只匹配名为"testAbc"的方法
        return new StaticMethodMatcherPointcut() {
            @Override
            public boolean matches(Method method, Class<?> targetClass) {
                return method.getName().equals("testAbc");
            }
        };
    }
    @Override
    public Advice getAdvice() {
        // 定义通知逻辑
        return new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        };
    }
    @Override
    public boolean isPerInstance() {
        return false;
    }
});

三、Spring AOP的三种配置方式

3.1 ProxyFactoryBean:工厂Bean方式

@Configuration
public class AopConfig {
    @Bean
    public MethodInterceptor zhouyuAroundAdvice() {
        return new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        };
    }
    @Bean
    public ProxyFactoryBean userService() {
        UserService userService = new UserService();
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setTarget(userService);
        proxyFactoryBean.setInterceptorNames("zhouyuAroundAdvice");
        return proxyFactoryBean;
    }
}

特点

3.2 BeanNameAutoProxyCreator:按Bean名称匹配

@Bean
public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
    BeanNameAutoProxyCreator creator = new BeanNameAutoProxyCreator();
    // 支持通配符匹配
    creator.setBeanNames("userSe*");
    creator.setInterceptorNames("zhouyuAroundAdvice");
    creator.setProxyTargetClass(true); // 强制使用CGLIB
    return creator;
}

特点

3.3 DefaultAdvisorAutoProxyCreator:自动代理创建器

@Bean
public DefaultPointcutAdvisor defaultPointcutAdvisor() {
    NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
    pointcut.addMethodName("test");
    DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
    advisor.setPointcut(pointcut);
    advisor.setAdvice(new ZhouyuAfterReturningAdvice());
    return advisor;
}
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
    return new DefaultAdvisorAutoProxyCreator();
}

特点

四、注解驱动的Spring AOP

4.1 @EnableAspectJAutoProxy的作用

@EnableAspectJAutoProxy注解是开启Spring AOP注解支持的关键:

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}

该注解的作用是向Spring容器注册一个AnnotationAwareAspectJAutoProxyCreator Bean,这是一个BeanPostProcessor,负责:

4.2 注解使用示例

@Aspect
@Component
public class LoggingAspect {
    @Before("execution(* com.example.service.*.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Before method: " + joinPoint.getSignature().getName());
    }
    @AfterReturning(
        pointcut = "execution(* com.example.service.*.*(..))",
        returning = "result"
    )
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("Method returned: " + result);
    }
    @AfterThrowing(
        pointcut = "execution(* com.example.service.*.*(..))",
        throwing = "error"
    )
    public void logAfterThrowing(JoinPoint joinPoint, Throwable error) {
        System.out.println("Method threw exception: " + error);
    }
    @After("execution(* com.example.service.*.*(..))")
    public void logAfter(JoinPoint joinPoint) {
        System.out.println("After method (finally)");
    }
    @Around("execution(* com.example.service.*.*(..))")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Around before");
        Object result = joinPoint.proceed();
        System.out.println("Around after");
        return result;
    }
}

五、代理对象的创建过程

5.1 JdkDynamicAopProxy创建过程

public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
    public JdkDynamicAopProxy(AdvisedSupport config) {
        // 1. 获取目标类实现的所有接口
        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(config);
        // 2. 额外添加三个接口
        List<Class<?>> allInterfaces = new ArrayList<>(Arrays.asList(proxiedInterfaces));
        allInterfaces.add(SpringProxy.class);
        allInterfaces.add(Advised.class);
        allInterfaces.add(DecoratingProxy.class);
        // 3. 检查接口中的equals和hashCode方法
        findDefinedEqualsAndHashCodeMethods(allInterfaces);
        // 4. 创建代理对象
        this.proxiedInterfaces = allInterfaces.toArray(new Class<?>[0]);
    }
    @Override
    public Object getProxy(@Nullable ClassLoader classLoader) {
        return Proxy.newProxyInstance(
            classLoader, 
            this.proxiedInterfaces, 
            this
        );
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 代理对象的执行逻辑
        // ...
    }
}

5.2 ObjenesisCglibAopProxy创建过程

public class ObjenesisCglibAopProxy extends CglibAopProxy {
    @Override
    public Object getProxy(@Nullable ClassLoader classLoader) {
        // 1. 创建Enhancer对象
        Enhancer enhancer = createEnhancer();
        // 2. 设置父类(目标类)
        enhancer.setSuperclass(config.getTargetClass());
        // 3. 设置接口
        enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(config));
        // 4. 设置回调
        enhancer.setCallback(new DynamicAdvisedInterceptor(this.advised));
        // 5. 创建代理对象
        return enhancer.create();
    }
}

六、代理对象的执行过程

6.1 代理方法执行的核心流程

// 伪代码展示代理对象方法执行过程
public Object invoke(Method method, Object[] args) {
    // 1. 获取所有Advisor
    List<Advisor> advisors = getAdvisors();
    // 2. 筛选与当前方法匹配的Advisor
    List<Advisor> matchedAdvisors = filterAdvisors(advisors, method);
    // 3. 将Advisor转换为MethodInterceptor
    List<MethodInterceptor> interceptors = 
        adaptAdvisorsToMethodInterceptors(matchedAdvisors);
    // 4. 创建MethodInvocation
    MethodInvocation invocation = new ReflectiveMethodInvocation(
        target, method, args, interceptors
    );
    // 5. 执行拦截器链
    return invocation.proceed();
}

6.2 各注解对应的MethodInterceptor执行顺序

注解对应Interceptor执行顺序
@BeforeMethodBeforeAdviceInterceptor先执行通知,后执行目标方法
@AfterReturningAfterReturningAdviceInterceptor先执行目标方法,后执行通知
@AfterThrowingAspectJAfterThrowingAdvice先执行目标方法,异常时执行通知
@AfterAspectJAfterAdvice先执行目标方法,后执行通知(finally)
@AroundAspectJAroundAdvice完全控制执行流程

执行流程示意图

   Around.before

              ↓

          Before

              ↓

     目标方法执行

              ↓

AfterReturning/AfterThrowing

              ↓

           After

              ↓

     Around.after

七、AbstractAdvisorAutoProxyCreator的工作原理

7.1 核心继承体系

BeanPostProcessor
    ↓
AbstractAutoProxyCreator
    ↓
AbstractAdvisorAutoProxyCreator
    ↓
AspectJAwareAdvisorAutoProxyCreator
    ↓
AnnotationAwareAspectJAutoProxyCreator

7.2 关键方法解析

public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {
    @Override
    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        // 1. 检查是否已经是代理对象
        if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
            return bean;
        }
        // 2. 获取所有Advisor
        List<Advisor> advisors = getAdvisors();
        // 3. 查找匹配的Advisor
        List<Advisor> matchedAdvisors = findAdvisorsThatCanApply(advisors, bean.getClass(), beanName);
        // 4. 如果有匹配的Advisor,创建代理对象
        if (!matchedAdvisors.isEmpty()) {
            return createProxy(bean.getClass(), beanName, matchedAdvisors, bean);
        }
        return bean;
    }
    protected List<Advisor> getAdvisors() {
        // 获取所有Advisor类型的Bean
        List<Advisor> advisors = new ArrayList<>();
        String[] advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
            this.beanFactory, Advisor.class, true, false
        );
        for (String name : advisorNames) {
            advisors.add(this.beanFactory.getBean(name, Advisor.class));
        }
        return advisors;
    }
}

7.3 AnnotationAwareAspectJAutoProxyCreator的特殊处理

AnnotationAwareAspectJAutoProxyCreator重写了getAdvisors()方法,增加了对@Aspect注解的解析:

public class AnnotationAwareAspectJAutoProxyCreator 
        extends AspectJAwareAdvisorAutoProxyCreator {
    @Override
    protected List<Advisor> getAdvisors() {
        // 调用父类方法获取已注册的Advisor
        List<Advisor> advisors = super.getAdvisors();
        // 额外解析@Aspect注解的Bean
        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
        return advisors;
    }
}

八、Spring AOP高级特性

8.1 TargetSource:灵活的代理目标源

TargetSource允许我们动态控制被代理对象的获取:

TargetSource ts = new TargetSource() {
    @Override
    public Class<?> getTargetClass() {
        return UserService.class;
    }
    @Override
    public boolean isStatic() {
        return false; // 每次调用都获取新的目标对象
    }
    @Override
    public Object getTarget() {
        // 动态创建或获取目标对象
        return new UserService();
    }
    @Override
    public void releaseTarget(Object target) {
        // 释放目标对象
    }
};
ProxyFactory pf = new ProxyFactory();
pf.setTargetSource(ts);

应用场景:延迟注入(@Lazy)、热替换等

8.2 Introduction:引入新接口

Introduction允许为被代理对象动态添加新的接口实现:

@Aspect
@Component
public class IntroductionAspect {
    @DeclareParents(
        value = "com.example.service.*+",
        defaultImpl = DefaultLockable.class
    )
    public static Lockable mixin;
}
public interface Lockable {
    void lock();
    void unlock();
    boolean isLocked();
}
public class DefaultLockable implements Lockable {
    private boolean locked;
    @Override
    public void lock() {
        this.locked = true;
    }
    @Override
    public void unlock() {
        this.locked = false;
    }
    @Override
    public boolean isLocked() {
        return this.locked;
    }
}

8.3 LoadTimeWeaving:加载时织入

Spring AOP支持在类加载时进行字节码织入:

@Configuration
@EnableLoadTimeWeaving
public class AppConfig {
}
// 或使用XML配置
// <context:load-time-weaver/>

与运行时织入的区别

九、Spring AOP与AspectJ的关系

9.1 两者区别

特性Spring AOPAspectJ
实现方式动态代理(运行时)字节码操作(编译时/加载时)
性能相对较慢非常快
功能有限,仅支持方法级别强大,支持字段、构造器等
依赖仅需Spring需要AspectJ编译器/织入器
使用场景大多数企业应用需要高级AOP功能的场景

9.2 Spring如何整合AspectJ

Spring并没有使用AspectJ的编译器或织入器,而是:

十、性能优化与最佳实践

10.1 性能优化建议

合理选择代理方式

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true) // 强制使用CGLIB
public class AppConfig {
}

精确指定切点

// 不推荐:过于宽泛
@Before("execution(* *.*(..))")
// 推荐:精确匹配
@Before("execution(* com.example.service.UserService.*(..))")

避免在Advice中做耗时操作

@Around("execution(* com.example.service.*.*(..))")
public Object measurePerformance(ProceedingJoinPoint joinPoint) throws Throwable {
    long start = System.currentTimeMillis();
    Object result = joinPoint.proceed();
    long end = System.currentTimeMillis();
    log.info("方法执行时间: {}ms", end - start);
    return result;
}

10.2 常见问题与解决方案

10.2.1 自调用问题

@Service
public class UserService {
    public void methodA() {
        System.out.println("methodA");
        this.methodB(); // 自调用,不会触发AOP
    }
    @Transactional
    public void methodB() {
        System.out.println("methodB");
    }
}
// 解决方案1:从容器中获取代理对象
@Service
public class UserService {
    @Autowired
    private ApplicationContext context;
    public void methodA() {
        System.out.println("methodA");
        context.getBean(UserService.class).methodB();
    }
}
// 解决方案2:使用AspectJ
@Configuration
@EnableAspectJAutoProxy(exposeProxy = true)
public class AppConfig {
}
@Service
public class UserService {
    public void methodA() {
        System.out.println("methodA");
        ((UserService) AopContext.currentProxy()).methodB();
    }
}

10.2.2 循环依赖问题

// 当A和B相互依赖且都需要AOP时可能出现问题
// 解决方案:使用setter注入而非构造器注入
@Service
public class ServiceA {
    private ServiceB serviceB;
    @Autowired
    public void setServiceB(ServiceB serviceB) {
        this.serviceB = serviceB;
    }
}

十一、总结

Spring AOP是一个强大而灵活的AOP实现框架,其核心机制可以总结如下:

Spring AOP的设计体现了以下几个重要原则:

到此这篇关于Spring AOP底层源码深度解析之从动态代理到注解实现的完整架构的文章就介绍到这了,更多相关Spring AOP动态代理到注解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文