AOP是什么?如何使用AOP?

目录

 

一.什么是AOP?

二.为什么使用AOP?

三.如何使用AOP?


一.什么是AOP?

(1)概述:就是在程序运行的时候,能够动态的将代码切入到类的指定方法,指定位置的编程思想就是面向切面编程。

(2)概念: 

  1.         Aspect      :       切面,切入系统的切面,比如事务管理是一个切面,日志分析也是一个切面。
  2.         Join point  :       连接点,也就是可以横向切入的位置。
  3.         Advice       :      通知,切面在某个连接点执行的操作(分为Before advice ,After returning advice,After throwing     advice,After(finally) advice,Around advice)
  4.         PointCut    :      切点,符合切点表达式的连接点,也就是真正被切入的地方
  •         BeforeAdvice:指的是前置增强,指的是在被增强的方法前执行。
  •         After returning advice: 指的是在被增强的方法执行完返回结果的时候执行
  •         After throwing advice: 指的是增强的方法报异常的时候执行。
  •         After(finally) advice: 指的是最终一定会执行的。
  •         Around advice:可以通过一个在joinpoint执行前后做一些事情的机会,可以决定什么时候,怎么样去执行joinpoint,甚至可以决定是否真的执行joinpoint的方法调用,只执行一次,并不是在joinpoint执行前后各调用一次pointcut,而是在  pointcut中把 joinpoint给around起来,可以通过Around advice 返回一些共享的参数值。

(3)AOP的实现原理

AOP分为静态AOP和动态AOP。

静态AOP是指AspectJ实现的AOP,他是将切面代码直接编译到Java类文件中。

动态AOP是指将切面代码进行动态织入实现的AOP。

Spring的AOP为动态AOP,实现的技术为: JDK提供的动态代理技术 和 CGLIB(动态字节码增强技术) 。尽管实现技术不一样,但 都是基于代理模式 , 都是生成一个代理对象 。

(4) 什么是JDK提供的动态代理技术?

内容引自:https://blog.csdn.net/qq_41357573/article/details/88040292

动态代理的意义在于生成一个 占位(代理对象),用来代理真实的对象,从而控制真实对象的访问。
代理对象的作用就是:在真实对象访问之前或者之后加入对应的 逻辑,或者根据其他规则控制是否使用真实对象。

JDK动态代理是JDK自带的功能,是java.lang.reflect.*包提供的方式,他必须借助一个接口才能提供代理对象。

JDK动态代理技术的实现步骤:

  1. 创建接口
  2. 创建接口的实现类:此类的实例对象是真实对象
  3. 创建代理类:此类必须实现InvocationHandler接口
  4. 测试

 

二.为什么使用AOP?

举个例子,我要做一个操作日志的拦截功能,需要记录用户添加和编辑的数据,如果只是一个模块,我们可以在这个模板的添加编辑方法中加入日志操作的代码。每增加一个模块我们我们就要往相应的模块中添加代码,但是如果模块过多的时候,缺点就出来了。代码重用性低,开发效率低,因而这个时候我们就可以用到AOP。

三.如何使用AOP?

功能:我现在要通过AOP来拦截所有的已save方法开头的方法

  • (1) 新建一个SpringBoot项目

  可以参考我的另外一篇博客。https://blog.csdn.net/tangthh123/article/details/104125485

  • (2)引入jar包 
<!--引入AOP依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  • (3)整个项目路径如下:

  • (4) 编写切入类,定义切入点,在切入类中编写公共代码。
package com.example.demo.aop;


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


/**
 * 功能描述: 保存用户操作日志
 *
 * @Author: tanghh18
 * @Date: 2020/2/2 12:34
 */
@Aspect
@Component
public class LogAspect {


    /**
     * 1.添加业务逻辑方法切入点
     */
    @Pointcut("execution(* com.example.demo.service.*.save*(..))")
    public void insertServiceCall() {
    }

    /**
     * 2.方法调用前触发
     */
    @Before(value = "insertServiceCall()")
    public void doBefore(JoinPoint joinPoint) {
        System.out.println("222----" + "方法之前调用-----" + "@Before");
    }

    /**
     * 3.方法执行后调用
     *
     * @param joinPoint
     * @param rtv
     * @throws Throwable
     */
    @AfterReturning(value = "insertServiceCall()", argNames = "joinPoint,rtv", returning = "rtv")
    public void insertServiceCallCalls(JoinPoint joinPoint, Object rtv) throws Throwable {
        System.out.println("333-----方法返回结果后调用" + "------@AfterReturning");
    }

    /**
     * 4.方法执行前后调用
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around(value = "insertServiceCall()")
    public Object doBeforeAdvice(ProceedingJoinPoint joinPoint) throws Throwable {//  通过JoinPoint 获取通知的签名信息,如目标方法名,目标方法参数信息等
        //获取目标方法的参数信息
        Object[] args = joinPoint.getArgs();
        System.out.println("444-----方法执行前后调用" + "------@Around");
        Object result = joinPoint.proceed(args);
        return result;
    }

    /**
     * 5.方法执行后调用(不区分成功或异常)
     **/
    @After(value = "insertServiceCall()")
    public void after() {
        System.out.println("555-----方法执行后调用" + "------@After");
    }

    /**
     * 6. 方法抛出异常后执行 记录异常
     **/
    @AfterThrowing(value = "insertServiceCall()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
        System.out.println("666-----方法抛出异常后执行" + "------@AfterThrowing");
    }
}
  • (5)编写一个简单的业务逻辑类
package com.example.demo.service;

/**
 * @Author tanghh
 * @Date 2020/2/2 12:36
 */
public interface DemoService {

    void saveUserInfo();
}
package com.example.demo.service.impl;

import com.example.demo.service.DemoService;
import org.springframework.stereotype.Service;

/**
 * @Author tanghh
 * @Date 2020/2/2 12:36
 */
@Service
public class DemoServiceImpl implements DemoService {

    @Override
    public void saveUserInfo() {

    }
}
  • (6) 编写一个简单的控制层。
package com.example.demo.controller;

import com.example.demo.service.DemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author tanghh
 * @Date 2020/2/2 12:54
 */
@RestController
public class DemoController {

    @Autowired
    private DemoService demoService;

    @GetMapping(value = "/testApi")
    public void testApi() {
        demoService.saveUserInfo();
    }
}
  • (7) 在浏览器上访问如下:

  • (8) 访问这个接口,返回结果如下,以上对一个方法的简单拦截。

 

发布了46 篇原创文章 · 获赞 42 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/tangthh123/article/details/104141389
今日推荐