Spring AOP的应用场景

打印接口输入输出日志

定义计算服务类CalculatorService

package com.spring.study.aop.service;

public class CalculatorService {
    public int div(int a, int b) {
        return a / b;
    }
}

定义LogAspect拦截类,并添加@Aspect注解


@Aspect
public class LogAspect {
    @Pointcut("execution(public * com.spring.study.aop.aspect.service..*.*(..))")
    public void pointCut() {

    }

    @Before("pointCut()")
    public void logStart(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        Object target =  joinPoint.getTarget();
        Object[] args = joinPoint.getArgs();

        System.out.println(target.getClass().getName() + "#" + methodName + " request args : " + Arrays.asList(args));
    }

    @After("pointCut()")
    public void logEnd(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        Object target =  joinPoint.getTarget();
        long end = System.currentTimeMillis();
    }

    @AfterReturning(pointcut = "pointCut()", returning = "result")
    public void logReturn(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();
        Object target =  joinPoint.getTarget();
        System.out.println(target.getClass().getName() + "#" + methodName + " result =  " + result);
    }

    @AfterThrowing(pointcut = "pointCut()", throwing = "exception")
    public void logException(Exception exception) {
        System.out.println("log logException ex =  " + exception);
    }

    @Around("pointCut()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("logAround start !!!");
        Object result = joinPoint.proceed();

        System.out.println("logAround end !!!");

        return result;
    }
}

定义配置类AppConfig,并添加@EnableAspectJAutoProxy注解,用于开启AOP代理自动配置。

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {

    @Bean
    public LogAspect logAspect(){
        return new LogAspect();
    }

    @Bean
    public CalculatorService calculatorService(){
        return new CalculatorService();
    }
}

编写启动的测试类AppMain,从容器中获取CalculatorService,并执行方法div

public class AppMain {
    public static void main(String[] args){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        CalculatorService calculatorService = context.getBean(CalculatorService.class);
        calculatorService.div(4,2);
        context.close();
    }
}

运行AppMain类,打印的测试结果如下

logAround start !!!
com.spring.study.aop.aspect.service.CalculatorService#div request args : [4, 2]
logAround end !!!
com.spring.study.aop.aspect.service.CalculatorService#div result =  2

使用注解监控接口性能

定义一个监控注解类Monitor

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface Monitor {
}

编写监控切面类MonitorAspect,拦截添加@Monitor注解的方法,如下

@Aspect
public class MonitorAspect {
    @Pointcut("@annotation(com.spring.study.aop.monitor.annotation.Monitor)")
    public void pointCut() {
    }

    @Around("pointCut()")
    public Object monitorAround(ProceedingJoinPoint joinPoint) {
        long startTime = System.currentTimeMillis();
        Object target = joinPoint.getTarget();
        String methodName = joinPoint.getSignature().getName();
        Object result = null;

        try {
            result = joinPoint.proceed();
        } catch (Throwable e) {
            throw new RuntimeException(e.getMessage());
        } finally {
            System.out.println(target.getClass().getName() + "#" + methodName + " cost time = " + (System.currentTimeMillis() - startTime) + "ms .");
        }

        return result;
    }
}

定义一个OrderService类,并在方法createOrder上添加@Monitor注解

public class OrderService {

    @Monitor
    public void createOrder(){
        try {
            Thread.sleep(3000);
        }catch (Exception e){

        }
    }
}

定义系统配置类AppConfig,并添加@EnableAspectJAutoProxy注解,用于开启AOP代理自动配置。

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {

    @Bean
    public MonitorAspect monitorAspect(){
        MonitorAspect monitorAspect = new MonitorAspect();

        return monitorAspect;
    }

    @Bean
    public OrderService orderService(){
        return new OrderService();
    }
}

编写启动测试类

public class AppMain {
    public static void main(String[] args){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        context.getBean(OrderService.class).createOrder();

        context.close();
    }
}

打印运行结果如下:

com.spring.study.aop.monitor.annotation.service.OrderService#createOrder cost time = 3015ms .

自定义性能监控的组件

我们的目标是创建一个monitor的监控项目,可以在其他项目中方便的使用。引入monitor.jar 和 在方法上添加注解,就可以达到打印接口日志和监控接口性能。

首先我们创建一个monitor的项目,POM文件如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.demo.monitor</groupId>
    <artifactId>monitor</artifactId>
    <packaging>jar</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>monitor</name>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
        </dependency>
    </dependencies>
 </project>

项目的目录结构如图
在这里插入图片描述
在工程中创建@Log注解 和 LogMethodInterceptor方法拦截器

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface Log {
}

定义方法拦截器类LogMethodInterceptor

public class LogMethodInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Object target = invocation.getThis();
        String methodName = invocation.getMethod().getName();
        Object result = null;
        String prefix = target.getClass() + "#" + methodName ;
        long startTime = System.currentTimeMillis();

        try{
            System.out.println(prefix + ".request=" + Arrays.asList(invocation.getArguments()));
            result = invocation.proceed();
        }catch (Exception ex){

        }finally {
            System.out.println(prefix + ".result=[" + result.toString() +"] cost time : " + (System.currentTimeMillis() - startTime) + "ms");
        }

        return result;
    }
}

定义日志管理的配置类LogManagementConfiguration,用于创建通知,切入点 和拦截器。

@Configuration
public class LogManagementConfiguration {
    @Bean
    public DefaultPointcutAdvisor logAdvisor() {
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        advisor.setAdvice(logMethodInterceptor());
        advisor.setPointcut(new StaticMethodMatcherPointcut() {
            @Override
            public boolean matches(Method method, Class<?> aClass) {
                return AnnotationUtils.findAnnotation(method, Log.class) != null;
            }
        });

        return advisor;
    }

    @Bean
    public LogMethodInterceptor logMethodInterceptor() {
        LogMethodInterceptor interceptor = new LogMethodInterceptor();

        return interceptor;
    }
}

如何自动创建LogManagementConfiguration实例呢,我们定义一个LogManagementConfigurationSelector类,让它实现ImportSelector接口的selectImports方法,返回LogManagementConfiguration对象的类名。

public class LogManagementConfigurationSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{LogManagementConfiguration.class.getName()};
    }
}

我们模仿@EnableTransactionManagement注解的定义,创建一个EnableLogManagement注解,添加@Import(LogManagementConfigurationSelector.class)

@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(LogManagementConfigurationSelector.class)
public @interface EnableLogManagement {
}

好了,我们的准备工作已经做完了,那么怎么在项目中使用呢?很简单我们只需引入maven的坐标,并在需要监控的方法上添加 @Monitor注解就可以 了。

 <dependency>
            <groupId>com.demo.monitor</groupId>
            <artifactId>monitor</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

定义AppConfig配置类,在配置类中添加@EnableLogManagement注解

@Configuration
@EnableLogManagement
@EnableAspectJAutoProxy
public class AppConfig {
    @Bean
    public OrderService orderService(){
        return new OrderService();
    }
}

编写启动测试类,用于测试我们开发的组件

public class AppMain {
    public static void main(String[] args){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        context.getBean(OrderService.class).createOrder("yyp",200);

        context.close();
    }
}

打印的运行日志如下:

class com.spring.study.aop.log.OrderService#createOrder.request=[yyp, 200]
class com.spring.study.aop.log.OrderService#createOrder.result=[OK] cost time : 12ms
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值