SpringBoot,实现AOP通过注解,对指定方法进行记录入参出参和异常,并打包

需求

能够记录请求的参数,请求的返回值,请求出现的异常。
Log日志工具任意。

实现思路

需要的依赖

打包选项

<packaging>jar</packaging>
		<dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.4</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.26</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>

类上需要的注解

@Aspect
@Configuration
public class LoggerAspect {
......................
}

切入点

这里使用annotation的方式,对所有打上注解的方法进行拦截。
Log 注解

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

切入点

@Pointcut("@annotation(annotation.Log)")
    public void logCut(){}

入参记录

首先使用@Before注解,将进入方法前的参数进行拦截并记录

@Before("logCut()")
    public void logRequest(JoinPoint joinPoint){
        System.out.println("记录中");
        logger.info("记录开始------------------------------------------------------");
        for (Object arg:joinPoint.getArgs()) {
            logger.info("请求参数为:"+arg.toString());
        }
        logger.info("请求的方法为:"+joinPoint.getSignature().getName());
        logger.info("请求记录完成");
    }

出参记录

其中@AfterReturning中“ returning ” 参数指定命名为 “result”,这样就能在下面方法的参数中添加result形参。

@AfterReturning(value = "logCut()",returning = "result")
    public void logResponse(JoinPoint joinPoint,Object result){
        logger.info(joinPoint.getSignature().getName()+" 执行完毕");
        logger.info("执行结果为:"+result);
    }

异常记录

这里的BaseException是我自定义的异常,不影响理解。

@AfterThrowing(value = "logCut()",throwing = "e")
    public void logException(JoinPoint joinPoint, Exception e){
        logger.error(joinPoint.getSignature().getName()+" 方法执行异常");
        //如果是定义的异常体系,则打出异常码
        if (e instanceof BaseException){
            BaseException exception = (BaseException) e;
            logger.error("异常为: "+e.getMessage()+" 异常码为:  "+((BaseException) e).getErrorCode()+"  异常堆栈打印:"+e.getStackTrace());
        }
        logger.error("异常为: "+e.getMessage()+"    "+e.getStackTrace());
    }

打包

使用mvn install进行打包并放置在本地maven仓库
IDEA则可以使用右侧窗口的Maven工具,执行install即可
在这里插入图片描述
执行完成后在本地maven库中会出现对应的jar包
在这里插入图片描述

打包出来的jar包引用方式

在你的项目里之间导入即可

<dependency>
   <groupId>com.example</groupId>
    <artifactId>boss-bes-common-logging</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

然后ExternalLibraries中就有对应的jar包了。

日志功能的测试

注意!!

对于新手来说,容易搞混@ComponentScan()和SpringBootApplication(scanBasePackages={})

@SpringBootApplication和@ComponentScan

进入@SpringBootApplication源码可以看到,@SpringBootApplication实际上是集成了@EnableAutoConfiguration,@ComponentScan。所以,不要使用了@ComponentScan又使用@SpringBootApplication(scanBasePackage={})。

public @interface SpringBootApplication {
    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    Class<?>[] exclude() default {};

    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    String[] excludeName() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackages"
    )
    String[] scanBasePackages() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackageClasses"
    )
    Class<?>[] scanBasePackageClasses() default {};
}

回到正题,启动类上应该加上@EnableAspectJAutoProxy,如果没有则无法使用切面。
@EnableAspectJAutoProxy源码,其中第一个参数是指定动态代理的方式,默认为false
即使用JDKProxy进行动态代理,如果设置为true则使用CgLib进行动态代理。关于动态代
理内容见:
第二个参数为控制代理的暴露方式,解决内部调用不能使用代理的场景,默认为false.

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

	/**
     * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
     * to standard Java interface-based proxies. The default is {@code false}.
     */
    boolean proxyTargetClass() default false;

	/**
     * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
     * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
     * Off by default, i.e. no guarantees that {@code AopContext} access will work.
     * @since 4.3.1
     */
    boolean exposeProxy() default false;
}

这里在启动类上加了@RestController,这是为了便于测试。
@RestContoller源码,不难看出,@RestController = @Controller + @ResponseBody

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
    @AliasFor(
        annotation = Controller.class
    )
    String value() default "";
}

正式开始测试
在hello方法上打上我定义的注解@Log
同时scanBasePackage指定jar中Log所在的包名,不然无法扫到这个Aspect

@EnableAspectJAutoProxy
@SpringBootApplication(scanBasePackages = {"logexample"})
@RestController
public class DemoApplication {
 	@Log
    @RequestMapping("/hello")
    public String hello(@RequestParam Integer id){
        if (id==1){
            throw new BusinessException(EnumException.SERVICE_INVALID_STATUS);
        }
        return id+"dd";
    }
}

测试工具为PostMan
测试结果为:
在这里插入图片描述
在这里插入图片描述
记录异常
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值