技术原理解析:
1. 切面(Aspect):一个切面由多个通知(Advice)组成,代表了交叉业务逻辑的模块。通知包含了要在目标方法执行前后执行的代码。
2. 通知(Advice):是切面的具体实现,包括前置通知(Before advice)、后置通知(After returning advice)、环绕通知(Around advice)、异常后通知(After throwing advice)和最终通知(After (finally) advice)。每种通知类型决定了代码在何处被执行。
3. 连接点(Join Point):程序执行过程中的任意一个点,如方法的调用、字段的访问等。在Spring AOP中,连接点通常指的是方法执行。
4. 切点(Pointcut):是匹配连接点的谓词,定义了哪些连接点会被通知处理。例如,可以定义一个切点来匹配所有以`execute`开头的方法。
5. 代理(Proxy):Spring AOP通过代理模式实现AOP,有两种代理方式:
- JDK动态代理:如果目标类实现了接口,Spring AOP会选择使用JDK的Proxy类来创建代理对象。
- CGLIB代理:对于没有实现接口的目标类,Spring AOP会使用CGLIB库来生成一个子类作为代理。
6. 织入(Weaving):将切面应用到目标对象的过程。在Spring AOP中,织入是在运行时动态完成的,属于动态织入。
示例代码说明:
@Aspect
@Component
public class LoggingAspect {
@Pointcut("execution(* com.example.service.*.*(..))")
public void anyServiceMethod() {} // 定义切点
@Before("anyServiceMethod()")
public void beforeAdvice(JoinPoint joinPoint) {
// 前置通知,执行方法前的操作
System.out.println("Executing method: " joinPoint.getSignature().getName());
}
@AfterReturning(pointcut = "anyServiceMethod()", returning = "returnValue")
public void afterReturningAdvice(JoinPoint joinPoint, Object returnValue) {
// 后置通知,方法正常返回后执行的操作
System.out.println("Executed method: " joinPoint.getSignature().getName() ", returned: " returnValue);
}
@AfterThrowing(pointcut = "anyServiceMethod()", throwing = "exception")
public void afterThrowingAdvice(JoinPoint joinPoint, Exception exception) {
// 异常后通知,方法抛出异常后执行的操作
System.out.println("Exception thrown in method: " joinPoint.getSignature().getName() ", exception: " exception);
}
@Around("anyServiceMethod()")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
// 环绕通知,可以完全控制方法的执行
System.out.println("Before method execution...");
Object result = pjp.proceed(); // 执行目标方法
System.out.println("After method execution.");
return result;
}
}
在上述代码中,`LoggingAspect`是一个切面,它定义了几个通知方法,分别对应不同类型的切点处理逻辑。`@Pointcut`注解定义了一个切点表达式,匹配了`com.example.service`包下的所有方法。在每个通知方法上标注了对应的切点引用,表明它们将在满足切点条件的方法执行前后进行相应的操作。
Spring AOP自定义注解验证数据
为了实现 Spring AOP 自定义注解来验证数据正确性,首先需要创建一个自定义注解、一个切面以及相应的通知方法来处理带有该注解的方法参数或者方法执行前后的验证逻辑。下面是一个简化的示例: 1. 创建自定义注解
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.METHOD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) public @interface DataValid { // 可以添加注解属性,例如校验规则等 } 2. 创建切面类 (Aspect) import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Aspect @Component public class DataValidationAspect { @Around("@annotation(DataValid)") public Object validateData(ProceedingJoinPoint pjp) throws Throwable { // 获取方法参数 Object[] args = pjp.getArgs(); // 假设我们检查第一个参数是否为非空字符串 if (args[0] instanceof String && ((String) args[0]).isEmpty()) { throw new IllegalArgumentException("数据不能为空"); } // 这里只是一个示例,你可以根据具体业务逻辑增加复杂的验证过程 // ... // 如果验证通过,继续执行原方法 return pjp.proceed(args); } } 3. 使用自定义注解 import org.springframework.stereotype.Service; @Service public class SomeService { @DataValid public void processData(String data) { // 业务处理逻辑... System.out.println("Processing data: " data); } } 在这个例子中,`DataValid` 注解用于标记需要进行数据验证的方法。`DataValidationAspect` 切面会拦截所有带有 `@DataValid` 注解的方法,在其执行前进行数据验证,如果数据不合法则抛出异常,否则执行原方法。