AOP动态代理
文章目录
- 一、静态代理
- 二、动态代理底层逻辑
- 三、基于配置文件的动态代理实现
- 四、基于注解的动态代理实现
- 五、@Component和@Ascpect两者结合的意义
- 示例代码
- 总结
一、静态代理
- 实现方式:定义一个代理类,该类实现与被代理类相同的接口,在代理类中持有被代理类的实例,在实现接口方法时,先执行增强逻辑,再调用被代理类对应的方法。
- 测试调用:使用接口类型作为引用,通过“new 代理类(被代理类实例)”的方式创建代理对象,调用接口方法时,会自动执行增强逻辑和被代理类的业务逻辑。
- 优点:实现简单,易于理解和上手。
- 缺点:
- 代理类与被代理类耦合度高,若接口发生变化,代理类和被代理类都需要修改。
- 每个接口都需要对应一个代理类,当存在多个接口时,会产生大量的代理类,增加代码维护成本。
二、动态代理底层逻辑
- 基本步骤:
- 创建被代理类的实例。
- 创建增强逻辑处理器实例(实现InvocationHandler接口),在其invoke方法中定义增强逻辑和对被代理类方法的调用。
- 通过Proxy类的newProxyInstance方法生成代理类实例,该方法的参数分别为:被代理类的类加载器、被代理类实现的接口数组、增强逻辑处理器实例。
- 核心原理:生成的代理类继承自Proxy类,且实现了被代理类所实现的接口。当调用代理类的方法时,会自动触发增强逻辑处理器的invoke方法,在invoke方法中完成增强逻辑的执行和被代理类方法的调用。
三、基于配置文件的动态代理实现
- 配置内容:在配置文件中,通过标签定义被代理类、增强逻辑处理器和代理工厂的实例。
- 对于被代理类和增强逻辑处理器,设置id作为实例名,class指定对应的类全限定名。
- 对于代理工厂(如Spring的ProxyFactoryBean),通过property标签配置相关属性,其中target属性引用被代理类实例,interceptorNames属性(以list形式)指定增强逻辑处理器。
- 组件扫描:在被代理类、增强逻辑处理器等类上添加@Component注解,以便Spring容器能够扫描并管理这些组件。
- 使用方式:通过ApplicationContext加载配置文件,获取代理工厂创建的代理对象,调用接口方法即可触发增强逻辑和业务逻辑。
四、基于注解的动态代理实现
- 切面类定义:在类上添加@Component和@Aspect注解,将该类标识为一个切面组件。
- 增强逻辑定义:在切面类中,使用@Before、@After、@Around等注解标注方法,这些方法即为增强逻辑(通知),注解的value属性指定切入点表达式,用于确定增强逻辑作用的目标方法。
- 代理对象获取:通过ApplicationContext加载配置(通常是通过注解配置开启组件扫描和AOP自动代理),直接从容器中获取被代理类的接口类型实例,该实例实际上是Spring动态生成的代理对象,调用其方法时会自动执行对应的增强逻辑。
- 优点:相比配置文件方式,注解方式更加简洁,减少了配置代码,提高了开发效率。
五、@Component和@Ascpect两者结合的意义
当一个类同时被 @Component
和 @Aspect
标注时,意味着:
- 该类是 Spring 容器管理的 Bean(通过
@Component
); - 该类是一个切面,内部可以定义切入点和通知(通过
@Aspect
),用于实现 AOP 功能。
示例代码
// 同时标注 @Component 和 @Aspect,定义一个切面类
@Component
@Aspect
public class LogAspect {// 定义切入点(拦截 com.example.service 包下所有类的所有方法)@Pointcut("execution(* com.example.service.*.*(..))")public void servicePointcut() {}// 定义前置通知(在目标方法执行前执行)@Before("servicePointcut()")public void beforeMethod(JoinPoint joinPoint) {String methodName = joinPoint.getSignature().getName();System.out.println("方法 " + methodName + " 即将执行...");}
}
- 上述代码中,
@Component
确保LogAspect
被 Spring 实例化; @Aspect
标记它为切面,@Pointcut
和@Before
则定义了切入点和通知逻辑,实现对目标方法的增强。
总结
@Component
:让类成为 Spring 管理的 Bean;@Aspect
:让类成为切面,用于编写 AOP 逻辑;- 两者结合是 Spring 中定义切面类的标准方式,缺一不可(如果只加
@Aspect
,Spring 不会管理该类,AOP 逻辑无法生效)。