Spring Boot 之AOP 日志组件

来源:互联网 发布:b2b商城源码 编辑:程序博客网 时间:2024/06/03 18:08

AOP 面向切面编程

一、相关概念

Aspect:切面

PointCut:切点

Advisor:通知

共有五种通知:

Before:前置通知   

After:后置通知

Around:环绕通知(功能最强大)

AfterReturing:返回通知  (没有异常的时候回执行)

AfterThrowing:异常通知 (有异常的时候回执行)

二、应用

新建Spring boot 项目 pom.xml文件引入  spring-boot-starter-aop ,spring-boot-starter-web依赖

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">   <modelVersion>4.0.0</modelVersion>   <groupId>com.example.beanValidation</groupId>   <artifactId>demo</artifactId>   <version>0.0.1-SNAPSHOT</version>   <packaging>jar</packaging>   <name>demo</name>   <description>Demo project for Spring Boot</description>   <parent>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter-parent</artifactId>      <version>1.5.7.RELEASE</version>      <relativePath/> <!-- lookup parent from repository -->   </parent>   <properties>      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>      <java.version>1.8</java.version>   </properties>   <dependencies>      <dependency>         <groupId>org.springframework.boot</groupId>         <artifactId>spring-boot-starter-web</artifactId>      </dependency>      <dependency>         <groupId>org.springframework.boot</groupId>         <artifactId>spring-boot-starter-aop</artifactId>      </dependency>      <dependency>         <groupId>org.springframework.boot</groupId>         <artifactId>spring-boot-starter-test</artifactId>         <scope>test</scope>      </dependency>   </dependencies>   <build>      <plugins>         <plugin>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-maven-plugin</artifactId>         </plugin>      </plugins>   </build>   </project>

创建一个切面WebLogAspect

package com.example.beanvalidation.aop;import com.example.beanvalidation.exception.WrapException;import com.fasterxml.jackson.databind.ObjectMapper;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.*;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;import java.util.Arrays;/** * Created by sai.luo on 2017-9-19. */@Component@Aspectpublic class WebLogAspect {    private static final Logger log = LoggerFactory.getLogger(WebLogAspect.class);    private static  final ObjectMapper objectMapper = new ObjectMapper();    /**     * 定义切点     */    @Pointcut("execution(* com.example.beanvalidation.controller..*.*(..))")    public void webLog(){}    /**     * 定义前置通知     */    @Before("webLog()")    public void before(JoinPoint joinPoint){        log.info("前置通知执行");        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();        //记录日志        String className = joinPoint.getTarget().getClass().getName();        String methodName = joinPoint.getSignature().getName();        log.info("请求方法:"+className+"."+methodName);        log.info("请求参数:"+ Arrays.asList(joinPoint.getArgs()[0]));        log.info("IP:"+request.getRemoteAddr());    }    /**     * 返回通知 不管是抛异常还是正常都是会执行     */    @After("webLog()")    public void after(){        log.info("后置通知执行");    }    /**     * 定义环绕通知 方法签名有返回类型     */    @Around("webLog()")    public Object  around(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{        log.info("环绕通知开始");        // 实际开发中需要定义一个返回类,包装返回结果。        /**         * public class ResponseResult{         *   int code ;         *   String message ;         *   T result ;         *         *   // get set methods         *   // constructor         *   }         */        try {            Object proceed = proceedingJoinPoint.proceed();            log.info("返回正常结果:"+objectMapper.writeValueAsString(proceed));            return proceed;        }catch (WrapException ex){           log.error("出现异常:"+ex.getMessage());        }        log.info("环绕通知结束");        return null;    }    /**     * 异常通知 不建议使用异常通知,因为会使用系统输出打印日志,消耗系统资源,建议在环绕通知中 捕获不同异常,进行处理     */    @AfterThrowing(pointcut = "webLog()",throwing = "ex")    public void afterThrowing(Throwable ex){        log.info("异常通知");        log.error("error: "+ex.getMessage());    }    /**     * 正常返回通知     */    @AfterReturning(pointcut = "webLog()",returning = "result")    public void afterReturning(Object result)throws Exception{        log.info("正常返回通知");        log.info(objectMapper.writeValueAsString(result));    }}

如果切面类WenLogAspect不在main启动类所在的包或者子包中,则需要手动注入到spring 容器中,才能生效


参考文献:https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#aop-enable-aspectj-xml


代码地址:https://github.com/luosai001/beanValidationAndSpringAOP




原创粉丝点击