旧事重提--使用AOP实现自定义注解

本文介绍了如何通过定义一个自定义注解`DataSourceFilter`,结合Spring AOP在执行方法前后动态切换数据源。在切入点`execution(*com.demo.service.impl.*.*(..))`匹配的方法中,如果类或方法带有该注解,就会调用`DataSourceFilterService`来切换数据源。需要注意的是,AOP不会对类内部调用和私有方法生效。

定义一个根据条件进行数据源切换的自定义注解。

一、 定义注解类

就这样子:
在这里插入图片描述
类可自定义参数,类似于:
在这里插入图片描述

二、 AOP实现注解功能

@Aspect
@Order(-1)
@Component
public class DataSourceFilterAspect {

    @Resource
    private DataSourceFilterService dataSourceFilterService;

	/**
     * 设置切入点
     */
    @Pointcut("execution(* com.demo.service.impl.*.*(..))")
    public void pointCut(){}

    /**
     * 执行方法前更换数据源
     */
    @Before("pointCut()")
    public void doBefore(JoinPoint point) throws IOException {

        // 通过切入点获取目标类和方法
        Class<?> target = point.getTarget().getClass();
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();

        // 注解出现在类上或方法上时,对非私有成员生效
        if ((target.isAnnotationPresent(DataSourceFilter.class))
                || (method != null && method.isAnnotationPresent(DataSourceFilter.class)) ) {

            // 自定义数据源切换方法
            dataSourceFilterService.setDataSource();

        }
    }

}

ps:AOP对类内部调用及私有方法不生效

<think>我们考了站内引用中的多个例子,特别是引用[1]和引用[3]中关于自定义注解AOP切面的实现。下面将详细说明在Spring Boot中如何通过AOP实现自定义注解的功能。 步骤分为: 1. 创建自定义注解 2. 创建切面类(使用@Aspect和@Component) 3. 在切面类中定义切入点(使用自定义注解)和通知(如@Before, @Around等) 4. 在需要的地方使用自定义注解 下面以记录方法日志为例,逐步实现: 第一步:创建自定义注解 我们可以定义一个注解,用于标记需要增强的方法。 ```java import java.lang.annotation.*; @Target(ElementType.METHOD) // 该注解只能应用在方法上 @Retention(RetentionPolicy.RUNTIME) // 在运行时保留,这样AOP代理才能读取到 @Documented public @interface Loggable { // 可以定义一些属性,比如日志描述信息 String value() default ""; } ``` 第二步:创建切面类 在切面类中,我们将定义通知(Advice)和切入点(Pointcut),切入点将使用我们自定义注解。 ```java import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; @Aspect @Component public class LoggingAspect { // 定义切入点:所有被@Loggable注解的方法 @Pointcut("@annotation(com.example.annotation.Loggable)") public void loggableMethod() {} // 前置通知:在目标方法执行前执行 @Before("loggableMethod()") public void logBefore(JoinPoint joinPoint) { // 这里可以获取方法名、数等信息 String methodName = joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); System.out.println("方法 " + methodName + " 开始执行,数: " + Arrays.toString(args)); } } ``` 第三步:在需要的方法上使用自定义注解 例如,我们在一个Service的方法上使用@Loggable注解。 ```java @Service public class UserService { @Loggable("这是一个获取用户信息的方法") public User getUserById(Long id) { // 业务逻辑 return new User(id, "张三"); } } ``` 这样,当调用getUserById方法时,切面中的前置通知就会执行,打印日志。 扩展:我们还可以使用环绕通知(@Around)来实现更复杂的逻辑,比如记录方法执行时间。 ```java 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 PerformanceAspect { @Around("@annotation(com.example.annotation.Loggable)") public Object logPerformance(ProceedingJoinPoint joinPoint) throws Throwable { long startTime = System.currentTimeMillis(); Object result = joinPoint.proceed(); // 执行目标方法 long endTime = System.currentTimeMillis(); System.out.println("方法 " + joinPoint.getSignature().getName() + " 执行耗时: " + (endTime - startTime) + "ms"); return result; } } ``` 注意事项: 1. 确保Spring Boot项目已经添加了AOP依赖(spring-boot-starter-aop)。 2. 自定义注解的路径在切面类中要写正确。 3. 切面类需要被Spring管理(使用@Component),同时使用@Aspect注解。 通过以上步骤,我们就实现了在Spring Boot使用AOP自定义注解来增强方法的功能。 考引用: [1]中提到了自定义注解AOP使用,我们考了其注解定义和切面类结构[^1]。 [3]中提到了切面类的基本结构[^3]。</think>### Spring Boot 通过 AOP 实现自定义注解功能 在 Spring Boot使用 AOP 实现自定义注解功能需要以下步骤,考了站内多个实现案例[^1][^3][^4]: --- #### 1. 添加 AOP 依赖 ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> ``` --- #### 2. 创建自定义注解 定义注解类并指定作用范围: ```java import java.lang.annotation.*; @Target(ElementType.METHOD) // 作用于方法级别 @Retention(RetentionPolicy.RUNTIME) // 运行时保留 @Documented public @interface CustomLog { String value() default ""; // 可配置的注解属性 LogType type() default LogType.OPERATION; // 枚举类型属性 } ``` 定义日志类型枚举: ```java public enum LogType { OPERATION, SECURITY, PERFORMANCE } ``` --- #### 3. 创建切面类 实现注解的横切逻辑: ```java import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; @Aspect @Component public class LogAspect { // 定义切入点:所有被@CustomLog注解的方法 @Pointcut("@annotation(com.example.annotation.CustomLog)") public void logPointcut() {} // 环绕通知(最常用) @Around("logPointcut()") public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { // 1. 获取方法信息 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); CustomLog annotation = method.getAnnotation(CustomLog.class); // 2. 前置处理(记录开始时间等) long startTime = System.currentTimeMillis(); System.out.println("【" + annotation.type() + "日志】方法开始: " + method.getName()); try { // 3. 执行目标方法 Object result = joinPoint.proceed(); // 4. 后置处理(记录结果) long duration = System.currentTimeMillis() - startTime; System.out.println("方法执行完成,耗时: " + duration + "ms"); return result; } catch (Exception e) { // 5. 异常处理 System.err.println("方法执行异常: " + e.getMessage()); throw e; } } // 前置通知(可选) @Before("logPointcut()") public void logBefore(JoinPoint joinPoint) { // 记录方法数等 Object[] args = joinPoint.getArgs(); System.out.println("方法数: " + Arrays.toString(args)); } } ``` --- #### 4. 使用自定义注解 在业务方法上添加注解: ```java @Service public class UserService { @CustomLog(type = LogType.OPERATION, value = "用户查询") public User getUserById(Long id) { // 业务逻辑 } @CustomLog(type = LogType.SECURITY) public void updatePassword(String newPassword) { // 密码更新逻辑 } } ``` --- #### 5. 高级功能实现 ##### 敏感字段加解密(考[^2]) ```java @Aspect @Component public class EncryptionAspect { @Around("@annotation(SensitiveData)") public Object encryptData(ProceedingJoinPoint pjp) throws Throwable { Object result = pjp.proceed(); if (result instanceof User) { User user = (User) result; user.setPassword(encrypt(user.getPassword())); // 加密处理 } return result; } } ``` ##### 操作日志入库(考[^4]) ```java @Around("@annotation(OperateLog)") public Object recordOperation(ProceedingJoinPoint pjp) throws Throwable { OperateLog logAnnotation = getAnnotation(pjp); LogEntity log = new LogEntity(); log.setOperationType(logAnnotation.value()); try { Object result = pjp.proceed(); log.setStatus("SUCCESS"); return result; } catch (Exception e) { log.setStatus("FAILED"); throw e; } finally { logService.save(log); // 保存到数据库 } } ``` --- #### 关键注意事项 1. **注解属性访问**:通过 `method.getAnnotation()` 获取注解配置 2. **方法信息获取**: ```java MethodSignature signature = (MethodSignature) joinPoint.getSignature(); String methodName = signature.getName(); Class<?> targetClass = joinPoint.getTarget().getClass(); ``` 3. **代理限制**:AOP 对 private 方法和内部调用无效 4. **执行顺序**:使用 `@Order` 注解控制多个切面的执行顺序 5. **性能优化**:避免在切面中执行耗时操作,特别是高频方法 > 完整实现Spring Boot 操作日志管理[^4] 和敏感字段加解密[^2] 的案例实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大迪吃小迪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值