springboot配置AOP切面编程

AOP简介:

面向切面编程(Aspect-Oriented Programming, AOP),它是在面向对象基础上的一种编程方法,但它并不能代替面向对象编程,开始前想大家考虑一个场景:公司有一个人力资源部系统目前已经上线,但是系统运行不稳定,有时运行的很慢,为了检测到底是那个环节出了问题,开发人员想要监控每一个方法的执行时间,再根据这些执行时间判断问题出在哪里。当问题解决了,再把这些监控移除掉。这个时候可以使用AOP,下面看看示例。在AOP中一些常见概念需要了解。

Joinpoint(连接点):类里面可以被增强的方法即为连接点,比如想修改你那个方法的功能,那么这个方法介绍一个连接点

Pointcut(切入点):对Joinpoint进行拦截的定义即为切入点,比如拦截所有以insert开始的方法,这个定义即为切入点

Advice(通知):拦截到Joinpoint之后所要做的事情就是通知,比如上文说到的打印日志监控,通知分为前置通知,后置通知,异常通知,最终通知和环绕通知。

Aspect(切面):Pointcut和Advice的结合

Target(目标对象):要增强的类称为Target

springboot中配置AOP

1.添加依赖

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

2.在com.example.demo.server包下创建UserService类,代码如下:(那个包下其实随便的)

package com.example.demo.server;
import org.springframework.stereotype.Service;
@Service
public class UserService {
    public String getUserById(Integer id){
        System.out.println("get...."+id);
        return "user";
    }
    public void deleteUserById(Integer id){
        System.out.println("delete...."+id);
    }
}

3.创建切面类,建议在config包下创建

package com.example.demo.config;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
/**
 * @Aspect注解表明这是一个切面类
 */
@Aspect
public class LogAspect {
    /**
     *     定义pc1方法使用了@Pointcut注解,这是一个切入点.
     *     execution中的参数
     *     第一个*表示方法返回任意值
     *     第二个*表示service包下的任意类
     *     第三个*表示类中的任意方法
     *     括号中的两个点表示方法参数任意,
     *     下面这个表示service包下的所有类中的所有方法
     */
    @Pointcut("execution(* com.example.demo.server.*.*(..))")
    public void pc1(){ }

    /**
     * @Before前置通知
     * 定义方法使用了@Before表示这个是一个前置通知
     * 在方法执行之前执行
     * @param jp  通过JoinPoint参数可以获取目标方法的方法名修饰符等信息
     */
    @Before(value = "pc1()")
    public void before(JoinPoint jp){
        String name = jp.getSignature().getName();
        System.out.println(name+"方法开始了");
    }

    /**
     * @After后置通知
     * 在方法执行结束后无异常通知
     * @param jp 通过JoinPoint参数可以获取目标方法的方法名修饰符等信息
     */
    @After(value = "pc1()")
    public void After(JoinPoint jp){
        String name = jp.getSignature().getName();
        System.out.println(name+"方法结束了");
    }

    /**
     *  @AfterReturningf返回通知
     *  该方法可以获取方法的返回值,@AfterReturning注解的returning参数指定返回值的变量名
     *  对应方法的参数
     * @param jp 通过JoinPoint参数可以获取目标方法的方法名修饰符等信息
     * @param result 注意:方法参数中定义了result的类型为Object,表示目标方法返回值可以是
     *  任意类型,若result定义为Long,则该方法只处理目标方法返回值Long的情况
     */
    @AfterReturning(value = "pc1()",returning = "result")
    public void AfterReturning(JoinPoint jp,Object result){
        String name = jp.getSignature().getName();
        System.out.println(name+"方法返回值是:"+result);
    }

    /**
     * @AfterThrowing异常通知
     * 在方法发生异常的时候被调用
     * @param jp  通过JoinPoint参数可以获取目标方法的方法名修饰符等信息
     * @param e  异常类型被设置为Exception表示受益异常都会进入该方法中执行,若设置为                    
       ArithmeticException则只目标抛出
     *           ArithmeticException异常进入该方法
     */
    @AfterThrowing(value = "pc1()",throwing = "e")
    public void AfterThrowing(JoinPoint jp,Exception e){
        String name = jp.getSignature().getName();
        System.out.println(name+"方法抛出异常:"+ e );
    }

    /**
     * @Around 环绕通知
     * 环绕通知是所有通知最强大的通知,可以实现前置通知,后置通知,异常通知,返回通知的功能
     * 目标方法进入环绕通知后,通过调用ProceedingJoinPoint对象的proceed方法使用目标方法继续执
     * 行,开发者可以在此修改目标方法的执行参数,返回值等,并且可以在此处理目标方法的异常
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("pc1()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
        return pjp.proceed();
    }

}

4.配置完成,最后创建Controller类,提供两个接口,

package com.example.demo.controller;
import com.example.demo.server.UserService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RestController
public class LogAspectController {

    @Resource
    UserService userService;
    @GetMapping("/getLog1")
    public String getUserById(){
        return userService.getUserById(1);
    }

    @GetMapping("/getLog2")
    public void getUserById2(){
         userService.deleteUserById(2);
    }
}

5.启动项目访问localhost:8080/getLog1localhost:8080/getLog2

大家发现在方法执行前后切面编程已经出现效果了

猜你喜欢

转载自blog.csdn.net/qq_41426326/article/details/89146860
今日推荐