首页 > 其他分享 >AOP

AOP

时间:2023-08-16 23:35:24浏览次数:30  
标签:double void value result AOP println public

AOP

一、什么是AOP?

Aop的专业术语(来源百度):

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

总结:

AOP是面向切面编程的语言,使自己的业务代码和非业务代码之间进行隔离,并且在不改变业务代码的前提下,可以增加新的非业务代码。

二、为什么使用AOP?

思考:

​ 如果我们在做用户登录和用户登出时,需要把这个记录添加到记录表时,这时,我们该如何处理。如果仅仅只有少量的记录我们或许可以去解决,可是当数量一旦多的话就会很麻烦。这个时候我们可以使用面向切面编程解决。

思维导图:
image


三、AOP的应用场景

1、Authentication 权限
2、Caching 缓存
3、Context passing 内容传递
4、Error handling 错误处理
5、Lazy loading 懒加载
6、Debugging 调试
7、logging,tracing,profiling and monitoring 记录跟踪 优化 校准
8、Performance optimization 性能优化
9、Persistence 持久化
10、Resource pooling 资源池
11、Synchronization 同步
12、Transactions 事务
13、Logging 日志

四、AOP的结构

其实AOP编程很简单,在AOP中程序员只需要关注三个部分:
1、在哪里切入(权限校验等业务操作在哪些业务代码中执行);
2、什么时候切入(切入的时机是在业务代码执行前还是执行后);
3、切入代码后做什么事(权限校验。日志记录等)
image
Asperct:切面
PointCut:切点 :路径表达式 (2)注解
Advice:处理的时机

五、如何使用AOP

以记录日志为例:

public class MathServiceImpl implements MathService{
    @Override
    public double add(double a, double b) {
        double result=a+b;
        System.out.println("这是记录的加法运算"+result);
        return result;
    }

    @Override
    public double sub(double a, double b) {
        double result=a-b;
        System.out.println("这是记录的减法运算"+result);
        return result;
    }

    @Override
    public double mul(double a, double b) {
        double result=a*b;
        System.out.println("这是记录的乘法运算"+result);
        return result;
    }

    @Override
    public double div(double a, double b) {
        double result=a/b;
        System.out.println("这是记录的除法运算"+result);
        return result;
    }
}

发现:在每个操作后,都要记录日志,如果后期日志内容发生改变。需要在每个操作后都进行修改,不利于代码的维护。

5.1 使用AOP解决

(1)引入相关依赖(注意:最好使用JDK8,否则在运行时,可能会报错)

<!--  Spring 依赖  -->
   <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-webmvc</artifactId>
     <version>5.2.15.RELEASE</version>
   </dependency>
   <!--引入SpringAop 依赖-->
   <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-aspects</artifactId>
     <version>5.2.15.RELEASE</version>
   </dependency>
 </dependencies>

(2)创建一个切面类

@Aspect // 标记该类为切面类
@Component // 将该类对象的创建交予spring容器(Brean)来管理
public class MyAspect {
    // Pointcut 切点  将要切点的路径写入当前注解中
   @Pointcut(value = "execution(public double com.deom.dome5.MathServiceImpl.add(double,double))")
    public void mypointcut(){

    }
    @After(value = "mypointcut()")
    public void a(){
        System.out.println("代码执行后");
    }
}

(3)创建一个spring配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
       <!--包扫描-->
   <context:component-scan base-package="com.deom.dome5"/>
        <!--开启Aop切面注解驱动-->
    <aop:aspectj-autoproxy/>
</beans>

(4)测试

public class Text5 {
    public static void main(String[] args) {
        // 加载spring配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring.xml");
        MathService mathService = (MathService) context.getBean("mathServiceImpl");
        mathService.add(20,10);
    }
}

运行结果:
image

5.2 使用通配符,统配类的路径

@Aspect // 标记该类为切面类
@Component // 将该类对象的创建交予spring容器(Brean)来管理
public class MyAspect {
/*
*  通配符: *
*   第一个 * : 表示任意的访问权限修饰符、任意返回类型
*   第二个 * : 表示该包下所有的类。
*   第三个* : 类下的所有方法
*   三个... 可变参数
*   这里的两个 .. : 任意参数
*
*  个人建议:包级别,不推荐使用通配符
* */
    @Pointcut(value = "execution(* com.deom.dome5.*.*(..))")
    public void mypointcut1(){

    }

//    // Pointcut 切点  将要切点的路径写入当前注解中
//   @Pointcut(value = "execution(public double com.deom.dome5.MathServiceImpl.add(double,double))")
//    public void mypointcut(){
//
//    }
    @After(value = "mypointcut1()")
    public void a(){
        System.out.println("代码执行后");
    }
}

5.3 使用注解实现AOP

(1)注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value() default "";
}

(2)ServieImpl

@Service
public class MathServiceImpl implements MathService {
    // 这里使用了自定义注解
    @MyAnnotation
    @Override
    public double add(double a, double b) {
         // int i=10/0  手动开启或关闭异常报错
        double result=a+b;
        System.out.println("这是记录的加法运算"+result);
        return result;
    }

    @Override
    public double sub(double a, double b) {
        double result=a-b;
        System.out.println("这是记录的减法运算"+result);
        return result;
    }

    @Override
    public double mul(double a, double b) {
        double result=a*b;
        System.out.println("这是记录的乘法运算"+result);
        return result;
    }

    @Override
    public double div(double a, double b) {
        double result=a/b;
        System.out.println("这是记录的除法运算"+result);
        return result;
    }
}

(3)修改切面类

@Aspect // 标记该类为切面类
@Component // 将该类对象的创建交予spring容器(Brean)来管理
public class MyAspect {
/*
*  通配符: *
*   第一个 * : 表示任意的访问权限修饰符、任意返回类型
*   第二个 * : 表示该包下所有的类。
*   第三个* : 类下的所有方法
*   三个... 可变参数
*   这里的两个 .. : 任意参数
*
*  个人建议:包级别,不推荐使用通配符
* */
//    @Pointcut(value = "execution(* com.deom.dome5.*.*(..))")
//    public void mypointcut1(){
//
//    }

//    // Pointcut 切点  将要切点的路径写入当前注解中
//   @Pointcut(value = "execution(public double com.deom.dome5.MathServiceImpl.add(double,double))")
//    public void mypointcut(){
//
//    }

// @annotation 调用注解的方法,括号里面写自定义注解的路径
    @Pointcut(value = "@annotation(com.deom.dome5.MyAnnotation)")
    public void mypointcut2(){

    }

    @After(value = "mypointcut2()")
    public void a(){
        System.out.println("代码执行后");
    }
}

(4)测试:

public class Text5 {
    public static void main(String[] args) {
        // 加载spring配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring.xml");
        MathService mathService = (MathService) context.getBean("mathServiceImpl");
        mathService.add(20,10);
    }
}

运行结果:
image

5.4 aop切面通知的类型

(1)四种简单的处理方法
1、Before(前置处理)
2、After (后置处理)
3、AfterReturning (后置返回通知)
4、AfterThrowing (异常处理)

@Aspect // 标记该类为切面类
@Component // 将该类对象的创建交予spring容器(Brean)来管理
public class MyAspect {
/*
*  通配符: *
*   第一个 * : 表示任意的访问权限修饰符、任意返回类型
*   第二个 * : 表示该包下所有的类。
*   第三个* : 类下的所有方法
*   三个... 可变参数
*   这里的两个 .. : 任意参数
*
*  个人建议:包级别,不推荐使用通配符
* */
//    @Pointcut(value = "execution(* com.deom.dome5.*.*(..))")
//    public void mypointcut1(){
//
//    }

//    // Pointcut 切点  将要切点的路径写入当前注解中
//   @Pointcut(value = "execution(public double com.deom.dome5.MathServiceImpl.add(double,double))")
//    public void mypointcut(){
//
//    }

    // @annotation 调用注解的方法,括号里面写自定义注解的路径
    @Pointcut(value = "@annotation(com.deom.dome5.MyAnnotation)")
    public void mypointcut2(){

    }
    // 后置处理 执行完代码后不需要经过返回值Return
    @After(value = "mypointcut2()")
    public void a(){
        System.out.println("Pointcut~~代码执行后,后置通知~~~Pointcut");
    }
    // 前置通知 方法执行前,执行切面的内容  前置通知
    @Before(value = "mypointcut2()")
    public void b(){
        System.out.println("Before~~~~~~~~~~前置通知,方法执行前,执行切面内容~~~~~~~~~~~~~Before");
    }
    // 后置返回通知,触碰到return,如果方法出现异常;这种通知不会被执行
    @AfterReturning(value ="mypointcut2()",returning = "r")// returnning:把执行方法的结果赋给该变量参数r
    public void  c(Object r){ // 参数名必须和returnning的名称保持一致
        System.out.println("AfterReturning~~~后置返回通知,触碰到return~~~AfterReturning");
    }
    // 异常通知:当被切入的方法出现异常时 ,才会执行
    @AfterThrowing(value = "mypointcut2()")
    public void d(){
        System.out.println("AfterThrowing~~异常通知,出现异常时出现~~~AfterThrowing");
    }
}

运行结果:
无异常:
image

有异常:
image

(2)环绕通知

@Aspect // 标记该类为切面类
@Component // 将该类对象的创建交予spring容器(Brean)来管理
public class MyAspect {
/*
*  通配符: *
*   第一个 * : 表示任意的访问权限修饰符、任意返回类型
*   第二个 * : 表示该包下所有的类。
*   第三个* : 类下的所有方法
*   三个... 可变参数
*   这里的两个 .. : 任意参数
*
*  个人建议:包级别,不推荐使用通配符
* */
//    @Pointcut(value = "execution(* com.deom.dome5.*.*(..))")
//    public void mypointcut1(){
//
//    }

//    // Pointcut 切点  将要切点的路径写入当前注解中
//   @Pointcut(value = "execution(public double com.deom.dome5.MathServiceImpl.add(double,double))")
//    public void mypointcut(){
//
//    }

    // @annotation 调用注解的方法,括号里面写自定义注解的路径
    @Pointcut(value = "@annotation(com.deom.dome5.MyAnnotation)")
    public void mypointcut2(){

    }
//    // 后置处理 执行完代码后不需要经过返回值Return
//    @After(value = "mypointcut2()")
//    public void a(){
//        System.out.println("After~~代码执行后,后置通知~~~After");
//    }
//    // 前置通知 方法执行前,执行切面的内容  前置通知
//    @Before(value = "mypointcut2()")
//    public void b(){
//        System.out.println("Before~~~~~~~~~~前置通知,方法执行前,执行切面内容~~~~~~~~~~~~~Before");
//    }
//    // 后置返回通知,触碰到return,如果方法出现异常;这种通知不会被执行
//    @AfterReturning(value ="mypointcut2()",returning = "r")// returnning:把执行方法的结果赋给该变量参数r
//    public void  c(Object r){ // 参数名必须和returnning的名称保持一致
//        System.out.println("AfterReturning~~~后置返回通知,触碰到return~~~AfterReturning");
//    }
//    // 异常通知:当被切入的方法出现异常时 ,才会执行
//    @AfterThrowing(value = "mypointcut2()")
//    public void d(){
//        System.out.println("AfterThrowing~~异常通知,出现异常时出现~~~AfterThrowing");
//    }

   // 环绕通知
    @Around(value = "mypointcut2()")
    // ProceedingJoinPoint:继承了 JoinPoint,是在JoinPoint的基础上暴露出 proceed 这个方法。
    // Proceedingjoinpoint 仅支持环绕通知@Around,而其他的几种切面只需要用到JoinPoint,这也是环绕通知和前置、后置通知方法的一个最大区别。这跟切面类型有关)
    // 环绕通知 = 前置 + 目标方法执行 + 后置通知,proceed方法就是用于启动目标方法的执行。暴露出这个方法,就能支持 aop:around 这种切面
    public Object e(ProceedingJoinPoint joinPoint){ // joinPoint:连接点  执行的方法对象,使用proceed方法启动目标方法的执行
        System.out.println("Around~~前置通知(Before)~~~Around");

        try {
            Object proceed = joinPoint.proceed();// 执行连接点
            System.out.println("Around~~后置通知(After)~~~Around");
            return proceed;
        } catch (Throwable e) {
            // printStackTrace:  在命令行打印异常信息在程序中出错的位置及原因
            e.printStackTrace();
            System.out.println("Around~~异常通知(AfterThrowing)~~~Around");
        } finally {
            System.out.println("都会执行");
        }
        return 0.0;
    }

运行结果:
无异常:
image
有异常:
image

标签:double,void,value,result,AOP,println,public
From: https://www.cnblogs.com/xbf3910/p/17635967.html

相关文章

  • javaSpring之AOP
    1.什么是AOP翻译中文为:面向切面编程,可以让你在业务代码与非业务代码隔离,增加新的非业务代码2.AOP使用场景1.我一直遵循着存在即合理的观念,在各大需求中,有一种需求是每当操作时,就会在数据库记录日志,那么在不更改业务代码的情况下应该怎么做,没错,AOP可以解决2.当然,其也可以做权限......
  • Java中的AOP
    AOP:是面向切面编程SpringAOP的底层是基于动态代理实现的,是在不更改原有类的基础上对目标方法进行增强,所以只有接口才能使用AOP注意:AOP不是Spring独有的,Spring是AOP的核心之一AOP的核心关键词原始对象是target要被增强的方法代理对象是proxy增强后的方法......
  • Net7配置Autofac下IOC中的AOP,以及Autofac的三种生命周期写法
    Net7配置Autofac下IOC中的AOP是分两种,一种是基于接口的,一种是基于实现类的基于接口的好处是简单,但不能有效的控制具体到某个方法。也就是说,只能基于类来做操作,一个类下所有的方法都要接受注册基于实现类的是稍微麻烦一点,生效方法必须改为virtual,但可以实现到具体某个方法的效......
  • 深入解析Spring的IOC与AOP及其在项目中的应用
    推荐阅读「java、python面试题」来自UC网盘app分享,打开手机app,额外获得1T空间https://drive.uc.cn/s/2aeb6c2dcedd4AIGC资料包https://drive.uc.cn/s/6077fc42116d4https://pan.xunlei.com/s/VN_qC7kwpKFgKLto4KgP4Do_A1?pwd=7kbv#https://yv4kfv1n3j.feishu.cn/docx/MRyxdaq......
  • 认识Spring AOP 面向切面编程
    一.什么是SpringAOP关于什么是SpringAOP.当我翻到官方文档的时候也是一惊LetusbeginbydefiningsomecentralAOPconceptsandterminology.ThesetermsarenotSpring-specific…unfortunately,AOPterminologyisnotparticularlyintuitive;however,itwoul......
  • 在 Spring Framework 中实现自定义 AOP 切面
    在SpringFramework中,面向切面编程(AOP)是一种重要的编程范式,它允许我们在应用程序中以模块化的方式处理横切关注点(如日志记录、事务管理等)。本文将深入探讨如何使用SpringFramework实现自定义AOP切面,通过代码示例演示其实际应用。1.概述AOP的核心思想是将横切关注点与主要......
  • Spring AOP详解
    1. AOP编程介绍OOP:面向对象编程,以对象为中心,进行程序的设计和开发。AOP:面向切面编程,以程序中的切面为中心,进行程序的设计和开发。可以把业务功能和非业务功能进行分离。实现AOP编程的方式:1)动态代理模式2)使用Spring的AOP模块3)AspectJ:专业的切面框架切面:程序中,一些通用的功能和方法......
  • java面向切面编程---AOP之环绕通知
    packagecom.xlkh.bigscreen.common.aspect;importcom.alibaba.fastjson.JSON;importcom.fasterxml.jackson.databind.ObjectMapper;importcom.xlkh.bigscreen.common.utils.RedisDeviceUtil;importcom.xlkh.bigscreen.service.bigscreen.BigscreenRedisService;imp......
  • 10、Spring之AOP概述
    10.1、概念AOP(AspectOrientedProgramming)是一种设计思想,是软件设计领域中的面向切面编程AOP是面向对象编程(OOP)的一种补充和完善,OOP是纵向继承机制,AOP是横向抽取机制AOP能通过预编译方式和运行期动态代理方式,实现在不修改源代码的情况下动态地为程序添加统一的附加功能......
  • springboot的AOP整理总结
    aop是spring的两大功能模块之一,功能非常强大,为解耦提供了非常优秀的解决方案。现在就以springboot中aop的使用来了解一下aop。一:使用aop来完成全局请求日志处理pom文件如下:<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmln......