AOP除了日志记录外,还可以用于缓存管理、权限控制、性能控制、异常处理

AOP的用途

除了日志记录外,AOP还可以用于以下情况:

缓存管理:通过AOP,可以将缓存逻辑从业务逻辑中分离出来,实现缓存的统一管理和更高效的数据读取。例如,使用AOP实现缓存切面,可以在方法执行前检查缓存中是否有数据,如果有,则直接从缓存中读取数据并返回,否则执行方法并将结果存入缓存中。

权限控制:通过AOP,可以将权限控制逻辑从业务逻辑中分离出来,实现统一的权限管理和更好的安全性。例如,使用AOP实现权限控制切面,可以在方法执行前检查用户的权限,如果有权限,则允许执行方法,否则拒绝执行。

性能监控:通过AOP,可以实现统一的性能监控和更好的性能优化。例如,使用AOP实现性能监控切面,可以在方法执行前记录当前时间戳,并在方法执行后计算方法执行时间,并将结果输出到日志中,从而帮助开发人员识别慢速代码并进行优化。

异常处理:通过AOP,可以将异常处理逻辑从业务逻辑中分离出来,实现统一的异常处理和更好的代码健壮性。例如,使用AOP实现异常处理切面,可以在方法执行过程中检查异常并进行相应的处理,例如将异常信息记录到日志中、发送邮件通知等。

缓存的例子

// 定义缓存注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Cached {
    String value();
}
// 定义缓存切面
@Aspect
@Component
public class CacheAspect {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Around("@annotation(cached)")
    public Object cache(ProceedingJoinPoint joinPoint, Cached cached) throws Throwable {
        String key = cached.value();
        Object result = redisTemplate.opsForValue().get(key);
        if (result != null) {
            return result;
        }
        result = joinPoint.proceed();
        redisTemplate.opsForValue().set(key, result);
        return result;
    }
}


// 使用缓存注解
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Cached("userCache")
    @Override
    public User getUserById(int id) {
        return userDao.getUserById(id);
    }
}

在这个例子中,我们定义了一个@Cached注解,用于标记需要缓存的方法。然后,我们实现了一个缓存切面,使用@Around注解将切面应用到@Cached注解标记的方法上。在缓存切面中,我们首先检查缓存中是否存在该数据,如果存在,则直接从缓存中读取并返回,否则执行该方法并将结果存入缓存中。最后,我们在UserServiceImpl类的getUserById方法上使用@Cached注解标记该方法需要缓存。

这个例子中使用了Redis作为缓存存储,当然也可以使用其他缓存方案,例如Ehcache、Memcached等。

性能控制的例子

添加依赖

在pom.xml文件中添加以下依赖:

    <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-core</artifactId>
        </dependency>
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-registry-prometheus</artifactId>
        </dependency>

上述依赖中包含Micrometer核心库和Prometheus度量系统的集成库。

定义一个切面类,使用@Aspect注解表示这是一个切面,使用@Component注解将其注册为Spring Bean。

配置Micrometer

然后,在你的Spring Boot应用程序中,你可以添加以下配置类来创建MeterRegistry bean:

@Configuration
public class MetricsConfig {

    @Bean
    public MeterRegistry meterRegistry() {
        return new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
    }
}

这个配置类使用PrometheusMeterRegistry来创建一个MeterRegistry bean,并使用默认的PrometheusConfig配置。当你运行你的应用程序时,你应该可以看到指标被收集并发布到Prometheus中了。

在application.yml文件中添加Micrometer相关配置:

management:
  metrics:
    tags:
      app: myapp
  export:
    prometheus:
      enabled: true

这里配置了app标签,用于标识应用程序,以及启用了Prometheus导出器。

定义切面

package com.wg.myAspect;

import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.time.Duration;

/**
 *
 * @author lst
 * @date 2023/4/18 10:54
 * @return null
 */
@Aspect
@Component
public class PerformanceAspect {

    private static final Logger logger = LoggerFactory.getLogger(PerformanceAspect.class);

    private final Timer timer;

    public PerformanceAspect(MeterRegistry registry) {
        this.timer = registry.timer("app.service.method.execution.time");
    }

    //    @Around("execution(* com.wg.controller..*.*(..))")
    @Around("execution(* com.wg.controller.UserController.*(..))")
    public Object monitor(ProceedingJoinPoint joinPoint) throws Throwable {
        Timer.Sample sample = Timer.start();
        Object result = joinPoint.proceed();
        long durationNanos = sample.stop(this.timer);
        Duration duration = Duration.ofNanos(durationNanos);
        long durationSeconds = duration.toSeconds();
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        logger.info("Method {} in class {} took {} seconds to execute", methodName, className, durationSeconds);
        return result;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值