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;
    }
}

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在面向切面编程 (AOP) 中,切面是一个横切关注点的抽象。它是应用程序中可能会影响多个类的功能的一部分。例如,日志记录功能就可以作为一个切面来实现,因为它可能会影响应用程序中的多个类。 在 AOP 中,切面是通过 "通知" 来实现的。通知是指在切面的特定连接点 (例如方法调用之前或之后) 执行的功能。例如,在方法调用之前执行的通知就可以用来实现日志记录功能。 总之,切面是 AOP用于抽象横切关注点的概念,并且通过通知来实现。 ### 回答2: 在面向对象编程中,切面(Aspect)是一种用于描述如何跨越多个对象的横切关注点的编程方式。切面提供一种将系统功能模块化的方式,它可以抽象出系统中的关注点,例如日志记录、事务处理、安全性控制等,将这些横切关注点与业务逻辑分开,避免代码的重复和耦合。 切面由切点(Pointcut)和通知(Advice)组成。切点定义了在何处应用通知,通知则定义了在切点处执行的动作。通知可以有不同的类型,包括前置通知(Before Advice)、后置通知(After Advice)、返回通知(After Returning Advice)、异常通知(After Throwing Advice)和环绕通知(Around Advice)。前置通知在切点之前执行,后置通知在切点之后执行,返回通知在切点正常返回后执行,异常通知在切点抛出异常后执行,环绕通知在切点前后执行。 AOP的核心是通过动态代理技术和反射机制实现对切点处的通知动作。在运行时,AOP将切面织入到目标对象中,使得切面的通知动作能够在目标对象的某些特定位置得到执行。此AOP还提供了一些其他的概念和概述,例如连接点(Join Point)、引入(Introduction)和增强(Weaving)等,用于更好地描述和组织切面的关注点。 总而言之,AOP中的切面是一种用于描述跨越多个对象的横切关注点的方式。它能够将系统的关注点模块化,提高代码的重用性和可维护性。切面由切点和通知组成,通过动态代理和反射机制实现对切点处的通知动作。AOP为开发者提供了一种更加灵活和易于维护的编程方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值