当前位置: 首页 > article >正文

Spring-AOP(面向切面)

文章目录

  • AOP(面向切面)
  • 一、代理
    • 静态代理
      • 代码实现
        • 1、创建一个接口和一个实现类(目标类)
        • 2、创建代理类实现接口,在创建一个此接口的属性,且创建有参构造
        • 3、创建测试类进行测试
    • 动态代理
      • 代码实现
      • 使用Pxoy类去实现动态代理,输出日志
      • 测试动态代理的效果
  • 二、基于的注解AOP实现日志
    • 代码实现加解析
    • 前置准备、导入依赖
    • 一、创建一个接口和实现类代表目标类,可以直接使用上面CalculatorImpl类,在实现类类中标记@Component注解
    • 二、创建bean.xml
    • 三、创建切面类完成日志
    • 测试


AOP(面向切面)

概念:切面就是将代码逻辑做横向切面,相同逻辑的部分分装到一个进行统一管理
作用:1、提高代码的复用性 2、增强代码的维护性

一、代理

概念: 在讲到面向切面之前必不可少的就是需要知道什么是代理代理就是继承一个目标类的代理类,在代理类来完成一些比较繁琐的代码如:输出日志等,当需要使用到核心代码时再去调用目标类的方法,这样子目标类就会变得更加的简洁明了。
简单的来说就是:一个明星(目标类)他只需要负责唱歌、跳舞等核心的事情,而明星的经济人(代理类)就需要告诉明星他需要到哪里进行演出、到哪里进行演讲等这些琐事

静态代理

逻辑:创建一个接口和实现类(目标类),在创建一个代理类也实现此接口,这时代理类就有了目标类的所有方法,此时就可以实现某一个方法在代理类中的方法进行输出日志、调用目标类的方法等操作,测试时就可以直接进行调用代理类即可。

代码实现

这里就拿一个简单的计算机的逻辑来讲解

1、创建一个接口和一个实现类(目标类)

在这里插入图片描述

2、创建代理类实现接口,在创建一个此接口的属性,且创建有参构造

在这里插入图片描述

3、创建测试类进行测试

在这里插入图片描述

此时就相当于完成了近似于代理的操作

动态代理

概念:动态代理就是将目标类中的所有方法都进行统一处理,实现方法就是去使用Poxy类中的方法

代码实现

这里创建目标类这一步就直接调用上面静态代理中的即可

使用Pxoy类去实现动态代理,输出日志

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class dynamicsProxy{

//    目标对象(需要被代理的对象)
    private Object object;
    public dynamicsProxy(Object object) {
        this.object = object;
    }

//    返回代理对象
    public Object getProxy(){
//        加载动态生成代理类的加载器
        ClassLoader classLoader = object.getClass().getClassLoader();
//        获取对象的所有接口
        Class<?>[] interfaces = object.getClass().getInterfaces();
//        设置代理目标对象的过程
        InvocationHandler invocationHandler = new InvocationHandler() {
            //proxy:需要被代理的对象
            //method:需要被重写的类
            //args[]:重写方法中的形参
            @Override
            public Object invoke(Object proxy,
                                 Method method,
                                 Object[] args) throws Throwable {
                //        执行核心代码前的日志
                System.out.println("[动态代理][日志],方法名为:"+method.getName()+"方法的参数"+ Arrays.toString(args));

                Object result = method.invoke(object, args);


                //        执行核心代码后的日志
                System.out.println("[动态代理][日志]结束了,运行结果为:"+result);

                return result;
            }
        };


        return Proxy.newProxyInstance(classLoader,interfaces,invocationHandler);
    }
}

测试动态代理的效果

在这里插入图片描述

二、基于的注解AOP实现日志

概念:注解AOP相对于上面动态和静态代理实现日志便捷了许多,且还添加了许多的功能

代码实现加解析

前置准备、导入依赖

<!--    spring Aop依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>6.0.2</version>
        </dependency>
        <!--    spring Aspects依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>6.0.2</version>
        </dependency>
        <!--    sprint context依赖-->
        <!--    当你引入Spring Context依赖之后,表示将Spring的基础依赖引入了-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.2</version>
        </dependency>

一、创建一个接口和实现类代表目标类,可以直接使用上面CalculatorImpl类,在实现类类中标记@Component注解

在这里插入图片描述

二、创建bean.xml

<?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.spring`在这里插入代码片`framework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--
    基于AOP的实现:
    1、将目标对象和切面交给IOC容器(注解+扫描)
    2、开启AspectJ的自动自动代理,为目标对象自动生成代理
    3、将切面类通过注解@Aspect表示
-->
<!--    将目标对象和切面交给IOC容器(注解+扫描)-->
    <context:component-scan base-package="org.example.annoAop"></context:component-scan>
<!--    开启AspectJ的自动自动代理,为目标对象自动生成代理-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

三、创建切面类完成日志


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

import java.util.Arrays;

@Aspect//切面类
@Component//ioc容器
public class LogAspect {
//    设置切面点和通知的类型
//    通知类型:
//    切入点表达式:execution【固定格式】(public int【权限修饰符,方法返回值(可以写*表示两值任意都可以)】
//    org.example.annoAop【方法所在类的全类名(这里写*表是包名任意,写*..表示报名任意同时报的层次深度任意)】.CalculatorImpl
//    add【方法名】(int,int)【形参列表,..表示任意】
//    )
//    前置通知 @Before(切入点表达式)
    @Before("execution(public int org.example.annoAop.CalculatorImpl.*(..))")
    public void beforeMethod(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("前置通知,方法名为:"+methodName);
    }
//    后置通知 @After(切入点表达式)
    @After("execution(* org.example.annoAop.CalculatorImpl.*(..))")
    public void afterMethod(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        System.out.println("后置通知,方法名为:"+methodName+"形参列表为:"+ Arrays.toString(args));
    }
//    返回通知 @AfterReturning
    @AfterReturning(value = "execution(public int org.example.annoAop.CalculatorImpl.*(..))",returning = "obj")
    public void afterReturning(JoinPoint joinPoint,Object obj){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("返回通知,方法名为:"+methodName+"返回结果:"+obj);
    }
//    异常通知 @AfterThrowing
    @AfterThrowing(value = "execution(public int org.example.annoAop.CalculatorImpl.*(..))",throwing = "e")
    public void afterThrowing(JoinPoint joinPoint,Throwable e){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("异常通知,方法名为:"+methodName+"报错信息:" + e);
    }
//    环绕通知 @Around()
//    概念:环绕通知可以使用try..catch..finally完成以上四种通知
    @Around(value = "pointcut()")
    public Object around(ProceedingJoinPoint pJoinPoint){
        String name = pJoinPoint.getSignature().getName();
        Object[] args = pJoinPoint.getArgs();
        Object result = null;
        try {
            System.out.println("环绕通知:前置效果,方法名为:" + name);
            //执行内部方法
            result = pJoinPoint.proceed();
            System.out.println("环绕通知:返回效果,方法名为:" + name + "返回结果:" + result);
        }catch (Throwable e) {
            e.printStackTrace();
            System.out.println("环绕通知:异常效果,方法名为:"+ name +"报错信息:" + e);
        } finally{
            System.out.println("环绕通知:后置效果,方法名为:" + name + "形参列表:" + Arrays.toString(args));
        }
        return result;
    }

//    重用切入点表达式
    @Pointcut("execution(public int org.example.annoAop.CalculatorImpl.*(..))")
    public void pointcut(){}
}

测试

在这里插入图片描述


详细内容


http://www.kler.cn/a/429415.html

相关文章:

  • [Qt]常用控件介绍-按钮类控件-QPushButton、QRedioButton、QCheckBox、QToolButton控件
  • 微信小程序订阅消息提醒-云函数
  • maven常见知识点
  • 【DB-GPT】开启数据库交互新篇章的技术探索与实践
  • java集合面试题
  • Facebook 隐私风波:互联网时代数据安全警钟
  • 深入理解C#的TCPIP通信机制
  • 深度学习:CPU和GPU算力
  • Python基于OpenCV实现的人脸识别和笑容检测
  • 【Apache Paimon】-- 4 -- Flink 消费 kafka 数据,然后写入 paimon
  • Linux如何安装discuz
  • docker安装Emqx并使用自签名证书开启 SSL/TLS 连接
  • 数据库之连接池Druid
  • ZZCMS2023存在跨站脚本漏洞(CNVD-2024-44822、CVE-2024-44818)
  • sock_poll内核函数
  • No module named ‘_ssl‘ No module named ‘_ctypes‘
  • 如何防范顶级应用程序安全威胁
  • 【大语言模型】LangChain ModelsIO与Models I/O Promopts详解
  • 【CKS最新模拟真题】Dockerfile修改
  • CTF-RE/WEB: python-Hook(钩子)
  • 电子信息工程自动化 基于单片机的居室安全报警系统
  • 为什么 JavaScript 中的回调函数未按顺序执行?
  • Pydantic 动态字段:使用和不使用 `@computed_field` 的对比指南
  • 如何使用 JavaScript 获取页面滚动位置?
  • Java项目实战II基于微信小程序的跑腿系统(开发文档+数据库+源码)
  • Hasura 中间件API go操作示例