spring AOP注解@Aspect的使用以及spring注解失效的场景
AOP思想:
AOP(Aspect Oriented Programming)是一种面向切面的编程思想。面向切面编程是将程序抽象成各个切面,即解剖对象的内部,将那些影响了多个类的公共行为抽取到一个可重用模块里,减少系统的重复代码,降低模块间的耦合度,增强代码的可操作性和可维护性。AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理、增强处理。
AOP的使用场景:
权限认证、日志、事务处理、增强处理
@Aspect的使用以及基本概念:
1.切面类 @Aspect: 定义切面类,加上@Aspect、@Component注解
@Aspect
@Component
//设置注解执行的顺序
@Order(2)
public class AnnotationAspectTest
2.切点 @Pointcut
/**
* 定义切点,切点为对应controller
*/
@Pointcut("execution(public * com.example.zcs.Aop.controller.*.*(..))")
public void aopPointCut(){
}
注:execution表达式第一个*表示匹配任意的方法返回值,第二个*表示所有controller包下的类,第三个*表示所有方法,第一个..表示任意参数个数。
3.Advice,在切入点上执行的增强处理,主要有五个注解:
@Before 在切点方法之前执行
@After 在切点方法之后执行
@AfterReturning 切点方法返回后执行
@AfterThrowing 切点方法抛异常执行
@Around 属于环绕增强,能控制切点执行前,执行后
4.JoinPoint :方法中的参数JoinPoint为连接点对象,它可以获取当前切入的方法的参数、代理类等信息,因此可以记录一些信息,验证一些信息等;
5.使用&&、||、!、三种运算符来组合切点表达式,表示与或非的关系;
6.@annotation(annotationType) 匹配指定注解为切入点的方法;
具体代码实现:
1.AopController,用于校验aop是否生效:
@Controller
@RequestMapping("aop")
public class AopController {
@RequestMapping("test")
@ResponseBody
public String aopTest(User user) {
// System.out.println(user);
System.out.println("aop测试");
return "success";
}
@TestAnnotation(flag = false)
@RequestMapping("aopAnnotationTest")
@ResponseBody
public String aopAnnotationTest(User user) {
// System.out.println(user);
System.out.println("aopAnnotationTest");
return "success";
}
}
2.AspectTest,具体的切面类,用于添加横切逻辑,切点使用execution表达式进行匹配
@Aspect
@Component
//设置注解执行的顺序
@Order(1)
public class AspectTest {
/**
* 定义切点,切点为对应controller
*/
@Pointcut("execution(public * com.example.zcs.Aop.controller.*.*(..))")
public void aopPointCut(){
}
@Before("aopPointCut()")
public void testbefor(JoinPoint joinPoint) {
illegalParam(joinPoint);
System.out.println("执行方法之前执行。。。。。");
}
@After("aopPointCut()")
public void testAfter(JoinPoint joinPoint) {
//illegalParam(joinPoint);
System.out.println("执行方法之后执行。。。。。");
}
/**
*获取请求参数
* @param joinPoint
* @return
*/
private static void illegalParam(JoinPoint joinPoint) {
if(joinPoint == null){
return;
}
boolean flag = false;
try{
// 参数值
Object[] args = joinPoint.getArgs();
if (args != null) {
for (Object o : args) {
System.out.println(o);
}
}
}catch(Exception e){
}
}
}
3.AnnotationAspectTest类,具体的切面类,用于添加横切逻辑,切点指定注解
@Aspect
@Component
//设置注解执行的顺序
@Order(2)
public class AnnotationAspectTest {
/**
* 定义切点,切点为添加了注解的方法
*/
@Pointcut("@annotation(com.example.zcs.Aop.annotation.TestAnnotation)")
public void aopPointCut(){
}
@Around("aopPointCut()")
public Object Around(ProceedingJoinPoint point) throws Throwable {
System.out.println("AnnotationAspectTest Around start ");
//获取注解和注解的值
TestAnnotation annotation = getAnnotation(point);
if (annotation != null) {
boolean flag = annotation.flag();
System.out.println("注解flags的值:" + flag);
}
//获取参数
Object[] args = point.getArgs();
for (Object arg : args) {
System.out.println("arg ==>" + arg);
}
//去调用被拦截的方法
Object proceed = point.proceed();
return proceed;
}
//获取注解
public TestAnnotation getAnnotation(ProceedingJoinPoint point) {
Signature signature = point.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null){
return method.getAnnotation(TestAnnotation.class);
}
return null;
}
}
4.注解类TestAnnotation
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TestAnnotation {
boolean flag() default true;
}
下面说下spring注解会失效的一些场景
1.Spring的AOP只能拦截由Spring容器管理的Bean对象。如果您使用了非受Spring管理的对象,则AOP将无法对其进行拦截。注解也不会生效。
2.如果一个Bean内部的方法直接调用同一个Bean内部的另一个方法,AOP将无法拦截这个内部方法调用。因为AOP是基于代理的,只有通过代理对象才能触发AOP拦截。(@Transactional事务注解也是同理)
3.私有方法调用,Spring的AOP只能拦截public方法。
4.静态方法
Spring的AOP只能拦截非静态方法。如果您尝试拦截静态方法,AOP将无法生效。
5.final方法
AOP无法拦截final方法。final方法是不可重写的,因此AOP无法生成代理对象来拦截这些方法。直接在对象内部调用方法:如果您直接在对象内部调用方法而不通过代理对象,AOP将无法拦截。因此,建议始终通过代理对象调用方法以确保AOP的生效
6.异步方法
对于使用Spring的异步特性(如@Async注解)的方法,AOP拦截器可能无法正常工作。这是因为异步方法在运行时会创建新的线程或使用线程池,AOP拦截器无法跟踪到这些新线程中的方法调用。
更多推荐
所有评论(0)