动态代理:Spring AOP 采用 JDK 动态代理和 CGLIB 动态代理技术来实现 AOP 的功能。对于接口代理,Spring 使用 JDK 动态代理,对于类代理,Spring 使用 CGLIB 动态代理。当一个被代理的对象被调用时,Spring AOP 在目标对象的方法执行前后织入额外的逻辑。
切面(Aspect):切面是 Spring AOP 中的重要概念,它是一个横切关注点的模块化实现。切面由切点和通知组成,其中切点定义了要在哪些方法上应用通知,而通知则定义了在这些方法执行前、执行后或抛出异常时要执行的代码。
连接点(Join point):连接点是应用程序中可以插入切面的点,例如方法调用或异常抛出。在 Spring AOP 中,连接点由方法调用和方法执行时抛出的异常组成。
切入点(Pointcut):切入点是连接点的一个子集,它定义了在哪些连接点上应用通知。在 Spring AOP 中,切入点通常是通过表达式来定义的,例如使用 AspectJ 的切入点表达式语言。
通知(Advice):通知定义了在切点上要执行的逻辑。Spring AOP 支持五种类型的通知:前置通知(Before advice)、后置通知(After returning advice)、环绕通知(Around advice)、异常通知(After throwing advice)和最终通知(After advice)。
织入(Weaving):织入是指将切面应用到目标对象的过程。Spring AOP 支持两种织入方式:编译时织入和运行时织入。编译时织入是在编译时将切面织入目标对象中,而运行时织入是在目标对象被加载时动态地将切面织入到目标对象中。
Spring AOP是基于动态代理机制实现的。在运行时,Spring会通过JDK动态代理或CGLIB动态代理来动态生成代理对象,代理对象通过切面表达式找到需要被代理的目标对象,并在目标对象的方法执行前、执行后或抛出异常时,自动执行切面逻辑。下面是一个简单的示例代码,演示了Spring AOP的基本原理:
// 目标对象
public class UserServiceImpl implements UserService {
@Override
public void addUser(String username, String password) {
System.out.println("添加用户:" + username + ", 密码:" + password);
}
@Override
public void deleteUser(String username) {
System.out.println("删除用户:" + username);
}
}
// 切面
@Aspect
@Component
public class LogAspect {
@Before("execution(* com.example.service.UserServiceImpl.addUser(String, String))")
public void beforeAddUser(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
System.out.println("准备添加用户:" + args[0]);
}
@AfterReturning("execution(* com.example.service.UserServiceImpl.addUser(String, String))")
public void afterAddUser(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
System.out.println("添加用户:" + args[0] + " 成功");
}
}
// 配置文件
@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.example")
public class AppConfig {
}
// 测试代码
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean(UserService.class);
userService.addUser("张三", "123456");
context.close();
}
}
在上面的示例代码中,UserService是一个接口,UserServiceImpl是接口的实现类。LogAspect是一个切面,用来实现日志记录的功能。在LogAspect中,@Before和@AfterReturning注解用来标注切面逻辑的执行时机。在AppConfig中,使用@EnableAspectJAutoProxy注解启用Spring AOP。在Test类中,通过ApplicationContext获取UserService实例,然后调用addUser方法。在运行时,Spring会动态生成代理对象,并在目标对象的addUser方法执行前、执行后自动执行LogAspect中的切面逻辑。
总的来说,Spring AOP 通过动态代理技术和切面、切点、通知等概念的使用,实现了对应用程序的横切关注点进行模块化实现。通过织入的方式,将切面应用到目标对象中,实现了对目标对象的增强。