Spring AOP底层源码深度解析之从动态代理到注解实现的完整架构
作者:alonewolf_99
一、动态代理基础: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);
}选择规则总结:
optimize为true → CGLIBproxyTargetClass为true → CGLIB- 目标类没有实现接口 → CGLIB
- 目标类是接口或已经是代理类 → JDK动态代理
- 其他情况 → JDK动态代理
二、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;
}
}特点:
- 基于FactoryBean机制
- 可以针对单个Bean进行AOP配置
- 支持通过名称引用已定义的Advice
3.2 BeanNameAutoProxyCreator:按Bean名称匹配
@Bean
public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
BeanNameAutoProxyCreator creator = new BeanNameAutoProxyCreator();
// 支持通配符匹配
creator.setBeanNames("userSe*");
creator.setInterceptorNames("zhouyuAroundAdvice");
creator.setProxyTargetClass(true); // 强制使用CGLIB
return creator;
}特点:
- 批量配置,支持通配符
- 只能根据Bean名称匹配
- 配置简单,但不灵活
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();
}特点:
- 自动扫描所有Advisor
- 根据Pointcut匹配决定是否创建代理
- 最灵活,功能最强大
四、注解驱动的Spring AOP
4.1 @EnableAspectJAutoProxy的作用
@EnableAspectJAutoProxy注解是开启Spring AOP注解支持的关键:
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}该注解的作用是向Spring容器注册一个AnnotationAwareAspectJAutoProxyCreator Bean,这是一个BeanPostProcessor,负责:
- 解析
@Aspect注解的类 - 将
@Before、@After等注解转换为对应的Advisor - 在Bean初始化后创建代理对象
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 | 执行顺序 |
|---|---|---|
| @Before | MethodBeforeAdviceInterceptor | 先执行通知,后执行目标方法 |
| @AfterReturning | AfterReturningAdviceInterceptor | 先执行目标方法,后执行通知 |
| @AfterThrowing | AspectJAfterThrowingAdvice | 先执行目标方法,异常时执行通知 |
| @After | AspectJAfterAdvice | 先执行目标方法,后执行通知(finally) |
| @Around | AspectJAroundAdvice | 完全控制执行流程 |
执行流程示意图:
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 AOP | AspectJ |
|---|---|---|
| 实现方式 | 动态代理(运行时) | 字节码操作(编译时/加载时) |
| 性能 | 相对较慢 | 非常快 |
| 功能 | 有限,仅支持方法级别 | 强大,支持字段、构造器等 |
| 依赖 | 仅需Spring | 需要AspectJ编译器/织入器 |
| 使用场景 | 大多数企业应用 | 需要高级AOP功能的场景 |
9.2 Spring如何整合AspectJ
Spring并没有使用AspectJ的编译器或织入器,而是:
- 复用注解:直接使用AspectJ定义的注解(@Aspect、@Before等)
- 自行解析:Spring自己解析这些注解并转换为内部表示
- 动态代理实现:通过动态代理实现AOP功能
十、性能优化与最佳实践
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基于JDK动态代理和CGLIB两种技术实现
- 统一抽象层:通过ProxyFactory、Advisor、Advice等概念提供统一API
- 注解驱动:支持使用@Aspect、@Before等注解声明式配置AOP
- 自动代理:通过BeanPostProcessor机制自动创建代理对象
- 执行链:通过MethodInterceptor链实现多个通知的顺序执行
Spring AOP的设计体现了以下几个重要原则:
- 开闭原则:通过代理模式实现对目标对象的透明增强
- 单一职责:将横切关注点(日志、事务等)与业务逻辑分离
- 配置优于编码:支持XML、注解等多种配置方式
到此这篇关于Spring AOP底层源码深度解析之从动态代理到注解实现的完整架构的文章就介绍到这了,更多相关Spring AOP动态代理到注解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
