易风网站建设,广州仿站定制模板建站,做旅游的网站有哪些,支付网站建设推广的会计分录一、注解
1、注解定义
注解本质上是一个实现了annotation的特殊接口#xff0c;其具体实现类是Java运行时生成的动态代理类。通过反射获取注解时#xff0c;返回的是Java运行时生成的动态代理对象。
// 定义注解
Target(ElementType.TYPE)
Retention(RetentionPolicy.RUNTIME…一、注解1、注解定义注解本质上是一个实现了annotation的特殊接口其具体实现类是Java运行时生成的动态代理类。通过反射获取注解时返回的是Java运行时生成的动态代理对象。// 定义注解Target(ElementType.TYPE)Retention(RetentionPolicy.RUNTIME)publicinterfaceMyAnnotation{Stringvalue()defaultdefault;intcount()default0;}// 编译后注解本质是一个接口继承自AnnotationpublicinterfaceMyAnnotationextendsjava.lang.annotation.Annotation{Stringvalue();intcount();}2、注解作用域和作用范围2.1 作用域 Retention根据作用域可以分为如下三类源码级只在源码中存在编译后会不会保留Retention(RetentionPolicy.SOURCE)。类文件级别注解保留在.class文件中但运行时不可见Retention(RetentionPolicy.CLASS)。运行时注解保留在.class文件中只有这个作用域可以通过反射在运行时访问Retention(RetentionPolicy.RUNTIME)。2.2 作用范围作用范围有方法、属性、类二、AOP1. 定义切面类切面类需使用Aspect标识并纳入 Spring 容器管理Aspect Component Slf4j public class CacheAspect { }2. 定义切点Pointcut切点用于描述哪些方法/类/连接点需要被拦截。2.1 常见 Pointcut 表达式2.1.1annotation匹配方法上标记了指定注解的连接点// 匹配所有带 CacheAble 注解的方法 Pointcut(annotation(org.example.aop.CacheAble)) public void cacheAbleCut(){}技巧可在 Advice 入参中直接绑定注解对象Around(cacheAbleCut() annotation(cacheAble)) public Object around(ProceedingJoinPoint jp, CacheAble cacheAble) { ... }这样可以直接获取注解属性值无需手动反射。2.1.2execution根据方法签名匹配// 匹配所有公共方法 Pointcut(execution(public * *(..))) public void anyPublicMethod() {} // 匹配所有以 set 开头的方法 Pointcut(execution(* set*(..))) public void anySetMethod() {} // 匹配 com.example.service 包下所有类的所有方法 Pointcut(execution(* com.example.service.*.*(..))) public void serviceMethods() {} // 匹配 UserDao 接口的所有实现方法 Pointcut(execution(* com.example.dao.UserDao.*(..))) public void userDaoMethods() {} // 匹配返回值类型为 User 的方法 Pointcut(execution(com.example.model.User *(..))) public void methodsReturningUser() {}2.1.3within与target匹配类级别注解// 匹配带 Service 注解类中的所有方法 Pointcut(within(org.springframework.stereotype.Service)) public void serviceAnnotationMethods() {} // 匹配目标对象带 Repository 注解的连接点 Pointcut(target(org.springframework.stereotype.Repository)) public void repositoryAnnotationMethods() {}区别within→ 检查声明类是否有注解target→ 检查运行时目标类是否有注解Spring 代理场景可能不同2.1.4 组合切点支持与、||或、!非// 在 service 包中且为公共方法 Pointcut(serviceMethods() anyPublicMethod()) public void servicePublicMethods() {} // service 包 或 dao 包方法 Pointcut(serviceMethods() || daoMethods()) public void serviceOrDaoMethods() {} // 非事务性 service 方法 Pointcut(serviceMethods() !transactionalMethods()) public void serviceNonTransactionalMethods() {}2.2 其他常用匹配方式2.2.1args绑定方法参数Pointcut(execution(* com.example..*(..)) args(userId,..)) public void methodWithUserIdArg(String userId) {}Advice 可直接接收参数Before(methodWithUserIdArg(userId)) public void logUser(String userId) { ... }2.2.2this/targetthis(proxy)绑定代理对象target(obj)绑定真实目标对象Around(this(proxy) target(service)) public Object around(ProceedingJoinPoint jp, Object proxy, MyService service) { ... }3.定义切面在 AOP 中切面逻辑主要通过以下几种Advice来实现通知类型注解作用时机前置通知Before目标方法执行前后置通知After目标方法执行后无论是否异常返回通知AfterReturning目标方法成功返回后异常通知AfterThrowing目标方法抛出异常后环绕通知Around在目标方法前后都可执行并可决定是否执行目标方法 其中ProceedingJoinPoint是JoinPoint的子类由于Around需要执行源方法ProceedingJoinPoint针对Around环绕通知提供了proceed()来调用源方法。3.1 前置通知 BeforeBefore(cacheAbleCut())publicvoidbeforeMethod(JoinPointjoinPoint){log.info(执行前置通知: 方法 {}, 参数 {},joinPoint.getSignature().getName(),Arrays.toString(joinPoint.getArgs()));}3.2 后置通知 AfterAfter(cacheAbleCut())publicvoidafterMethod(JoinPointjoinPoint){log.info(执行后置通知: 方法 {},joinPoint.getSignature().getName());}3.3 返回通知 AfterReturningAfterReturning(pointcutcacheAbleCut(),returningresult)publicvoidafterReturning(JoinPointjoinPoint,Objectresult){log.info(方法 {} 成功返回返回值 {},joinPoint.getSignature().getName(),result);}3.4 异常通知 AfterThrowingAfterThrowing(pointcutcacheAbleCut(),throwingex)publicvoidafterThrowing(JoinPointjoinPoint,Throwableex){log.error(方法 {} 抛出异常: {},joinPoint.getSignature().getName(),ex.getMessage(),ex);}3.5 环绕通知 AroundAround是功能最强的通知可以控制方法执行与否并在执行前后做处理Around(cacheAbleCut())publicObjectaround(ProceedingJoinPointpjp)throwsThrowable{log.info(环绕通知开始 - 方法: {},pjp.getSignature().getName());longstartTimeSystem.currentTimeMillis();// 执行目标方法Objectresultpjp.proceed();longendTimeSystem.currentTimeMillis();log.info(环绕通知结束 - 耗时: {}ms,(endTime-startTime));// 返回的即最终方法执行后返回的结果可以自定义随意返回returnresult;}高级用法绑定注解实例如果希望直接在环绕通知的方法参数中获取到目标方法上的注解对象可以这样写Around(aopPoint() annotation(rateLimiterAccessInterceptor))publicObjectdoRouter(ProceedingJoinPointjp,RateLimiterAccessInterceptorrateLimiterAccessInterceptor)throwsThrowable{log.info(限流检查: key{}, permits{},rateLimiterAccessInterceptor.key(),rateLimiterAccessInterceptor.permits());returnjp.proceed();}说明 annotation(rateLimiterAccessInterceptor)限定切点只匹配带有该注解的方法并且将注解实例注入到参数中。方法参数RateLimiterAccessInterceptor rateLimiterAccessInterceptor直接就是方法上真实存在的注解对象不需要手动反射getMethod()再getAnnotation()。示例目标方法RateLimiterAccessInterceptor(keyuserLogin,permits5)publicvoidlogin(Stringusername){// 登录逻辑}执行时 AOP 会自动把RateLimiterAccessInterceptor注解实例注入到doRouter()的第二个参数中。