spring boot in the use of AOP

A, AOP unification process requests log

Also on AOP

1, AOP is a programming paradigm

2, regardless of the language, a programming idea

  • Aspect-oriented (AOP) Aspect Oriented Programming
  • Object Oriented (OOP) Object Oriented Programming
  • Process for the (POP) Procedure Oriented Programming

 

AOP talk

1, the object-oriented process-oriented

2, to see the world from another angle, another position deal with the problem 

3, the generic logic from the business logic

 

Second, the process

Understand, in fact, the log system For ease of use, can be used to understand the thinking of the next log4j.

 

Third, the practical application of Aop

1, ready to work

Aop added in the pom dependency, specific examples are as follows:

      <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
            <version>2.2.2.RELEASE</version>
        </dependency>

2, log output

For example, we in the actual project, expect every step of our operation have log output, so how do we do it, or use the source code of the previous student information to demonstrate.

First create a cut, and here in the spring aop fact the same can be said to be easier, and specific examples of code is as follows:

package com.rongrong.springboot.demo.aspect;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

/**
 * @author rongrong
 * @version 1.0
 * @description:
 * @date 2020/1/6 21:50
 */
@Aspect
@Component
public class HttpAspect {

    @Before("execution(public * com.rongrong.springboot.demo.controller.StudentController.*(..))")
    public void log(){
        System.out.println("I performed !!" ); 
    } 
}

Then start the project, under the inquiry call interface, the console output might look like print, prove successful

3, the log output code optimization

There before, certainly there will be after, when there is the log output that is called, the call is also finished output, one to facilitate their debugging, and secondly to easily view the error, then how to write after it? I guess the average student definitely do it.

package com.rongrong.springboot.demo.aspect;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

/**
 * @author rongrong
 * @version 1.0
 * @description:
 * @date 2020/1/6 21:50
 */
@Aspect
@Component
public class HttpAspect {

    @Before("execution(public * com.rongrong.springboot.demo.controller.StudentController.*(..))")
    public void log(){
        System.out.println("我执行了!!");
    }

    @After("execution(public * com.rongrong.springboot.demo.controller.StudentController.*(..))")
    public void afterlog(){
        System.out.println("我执行了!!");
    }
}

这样写一点毛病也没有,但是。。。。。。。。。。。。。。。。。。。。哇哈哈哈哈哈哈,你肯定会说,我肯定不这样写,可以不承认,但有些同学肯定是这样干的。

写代码的原则,尽量少写重复代码,为啥呢?维护成本高呀,再就是让人觉得你的代码很low逼,看到这你肯定不会那么干了吧,哈哈哈哈哈。

好了玩笑开完了,我们可以这样,声明个切点,再切点里维护想要的切面,具体代码示例如下:

package com.rongrong.springboot.demo.aspect;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

/**
 * @author rongrong
 * @version 1.0
 * @description:
 * @date 2020/1/6 21:50
 */
@Aspect
@Component
public class HttpAspect {

    @Pointcut("execution(public * com.rongrong.springboot.demo.controller.StudentController.*(..))")
    public void log(){
    }
    
    @Before("log()")
    public void doBefore(){
        System.out.println("我执行了!!");
    }
    
    @After("log()")
    public void doAfter(){
        System.out.println("我执行了!!");
    }
}

4、Self4j的使用

改了下,发现似乎还是有点low,都用spring boot框架了,咋还能用System.out.println()输出呢,那么怎么优化呢?

现在仅仅满足了,控制台输出内容,但是如果我想要的日志不是这样的,最基本的得上面一样吧,有日期、端口、方法名之类的,即项目启动时控制台这样的日志才好看些吧,使用spring boot框架自带日志self4j即可解决,具体代码示例如下:

package com.rongrong.springboot.demo.aspect;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

/**
 * @author rongrong
 * @version 1.0
 * @description:
 * @date 2020/1/6 21:50
 */
@Aspect
@Component
public class HttpAspect {

   /**
     * 使用self4j,此日志为spring boot自带的日志框架
     */
    private final static Logger logger= LoggerFactory.getLogger(HttpAspect.class);

    @Pointcut("execution(public * com.rongrong.springboot.demo.controller.StudentController.*(..))")
    public void log(){
    }
    
    @Before("log()")
    public void doBefore(){
        logger.info("我执行了!!");
    }
    
    @After("log()")
    public void doAfter(){
        logger.info("我执行了!!");
    }
}

启动项目后,如下图所示,证明我们成功了

5、请求参数及响应信息控制台输出

这似乎看起来好了很多,但是实际工作时候,为了方便调试需要把我们请求接口及请求后返回的响应信息,在控制台输出,方便我们调试定位问题,下面我们来进行演示如何从控制台输出这些信息。

5.1、输出请求参数信息

使用RequestContextHolder来获得请求参数相关属性,这里需要强转成ServletRequestAttributes对象,Joinpoint这个参数非必须,是在获取“类方法”、“类名”、“方法参数”的时候会用到,如果用不到的话就不需要了。

具体示例代码如下所示:

package com.rongrong.springboot.demo.aspect;

import org.aspectj.lang.JoinPoint;
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.jws.Oneway;
import javax.servlet.http.HttpServletRequest;

/**
 * @author rongrong
 * @version 1.0
 * @description:
 * @date 2020/1/6 21:50
 */
@Aspect
@Component
public class HttpAspect {

    /**
     * 使用self4j,此日志为spring boot自带的日志框架
     */
    private final static Logger logger= LoggerFactory.getLogger(HttpAspect.class);

    /**
     *此处为了简化代码,提高维护性,还是需要提炼下的
    @Before("execution(public * com.rongrong.springboot.demo.controller.StudentController.*(..))")
    public void log(){
        System.out.println("我执行了!!");
    }
     */

    @Pointcut("execution(public * com.rongrong.springboot.demo.controller.StudentController.*(..))")
    public void log(){
    }

    /**
     * 在接口执行操作时输出相关参数
     */
    @Before("log()")
    public void doBefore(JoinPoint joinPoint){
        //使用RequestContextHolder来获得请求属性,这里需要强转成ServletRequestAttributes对象
        ServletRequestAttributes servletRequestAttributes= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        //获取请求url
        String url = servletRequestAttributes.getRequest().getRequestURI();
        //获取请求IP
        String addr = servletRequestAttributes.getRequest().getRemoteAddr();
        //获取请求方法
        String method = servletRequestAttributes.getRequest().getMethod();
        //获取类名
        String pCName = joinPoint.getSignature().getDeclaringTypeName();
        //获取类方法
        String cName = joinPoint.getSignature().getName();
        //这里要说明下 logger.info("url={}",url),url为{}自动填充部分
        //url
        logger.info("url= {}",url);
        //ip
        logger.info("ip= {}",addr);
        //method
        logger.info("method= {}",method);
        //args
        //获取请求参数
        logger.info("args= {}",joinPoint.getArgs());
        //类名和类方法
        logger.info("类名和类方法= {}",pCName+"."+cName);
    }

    @After("log()")
    public void doAfter(){
        logger.info("doAfter :我执行了!!");
    }

}

重新启动项目,我们调用下查询所有学生接口,控制台显示如下信息,证明日志成功!

5.2、输出响应信息

接下来我们再来输出响应结果信息,使用注解@AfterReturning,获取返回相应信息,具体示例代码如下:

package com.rongrong.springboot.demo.aspect;

import org.aspectj.lang.JoinPoint;
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.jws.Oneway;
import javax.servlet.http.HttpServletRequest;

/**
 * @author rongrong
 * @version 1.0
 * @description:
 * @date 2020/1/6 21:50
 */
@Aspect
@Component
public class HttpAspect {

    /**
     * 使用self4j,此日志为spring boot自带的日志框架
     */
    private final static Logger logger= LoggerFactory.getLogger(HttpAspect.class);

    /**
     *此处为了简化代码,提高维护性,还是需要提炼下的
    @Before("execution(public * com.rongrong.springboot.demo.controller.StudentController.*(..))")
    public void log(){
        System.out.println("我执行了!!");
    }
     */

    @Pointcut("execution(public * com.rongrong.springboot.demo.controller.StudentController.*(..))")
    public void log(){
    }

    /**
     * 在接口执行操作时输出相关参数
     */
    @Before("log()")
    public void doBefore(JoinPoint joinPoint){
        //使用RequestContextHolder来获得请求属性,这里需要强转成ServletRequestAttributes对象
        ServletRequestAttributes servletRequestAttributes= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        //获取请求url
        String url = servletRequestAttributes.getRequest().getRequestURI();
        //获取请求IP
        String addr = servletRequestAttributes.getRequest().getRemoteAddr();
        //获取请求方法
        String method = servletRequestAttributes.getRequest().getMethod();
        //获取类名
        String pCName = joinPoint.getSignature().getDeclaringTypeName();
        //获取类方法
        String cName = joinPoint.getSignature().getName();
        //这里要说明下 logger.info("url={}",url),url为{}自动填充部分
        //url
        logger.info("url= {}",url);
        //ip
        logger.info("ip= {}",addr);
        //method
        logger.info("method= {}",method);
        //args
        //获取请求参数
        logger.info("args= {}",joinPoint.getArgs());
        //类名和类方法
        logger.info("类名和类方法= {}",pCName+"."+cName);
    }

    @After("log()")
    public void doAfter(){
        logger.info("doAfter :我执行了!!");
    }

    /**
     * 使用@AfterReturning,获取返回相应信息
     */
    @AfterReturning(returning = "object",pointcut="log()")
    public void doAfterReturning(Object object){
        logger.info("返回信息 :{}",object.toString());
    }
}

再次重新启动项目,我们调用下查询所有学生接口,控制台显示如下信息,证明日志成功!

到此,spring boot中Aop的使用分享完毕,有兴趣的同学可以自行尝试哦。

Guess you like

Origin www.cnblogs.com/longronglang/p/12158841.html