SpringBoot下的Spring——DAY04——动态代理总结、AOP、自定义注解进行拦截、动态获取注解参数、通知方法(内含源代码)

news2024/11/14 22:50:58

SpringBoot下的Spring——DAY04——动态代理总结、AOP、自定义注解进行拦截、动态获取注解参数、通知方法(内含源代码)

源代码下载链接地址:https://download.csdn.net/download/weixin_46411355/87549575

目录

  • SpringBoot下的Spring——DAY04——动态代理总结、AOP、自定义注解进行拦截、动态获取注解参数、通知方法(内含源代码)
  • `源代码下载链接地址:`[https://download.csdn.net/download/weixin_46411355/87549575](https://download.csdn.net/download/weixin_46411355/87549575)
  • 1.动态代理总结
    • 1.1 JDK动态代理特点
    • 1.2 CGlib动态代理
      • 1.2.1 CGLib特点说明
    • 1.3 动态代理的作用
  • 2 Spring中的AOP
    • 2.1 AOP介绍
    • 2.2 AOP中专业术语(难点)
    • 2.3 AOP 入门案例
      • 2.3.1 创建一个SpringBoot的module
      • 2.3.1 导入jar包
      • 2.3.2 项目工程结构
      • 2.3.3 配置类
      • 2.3.4 Service层
        • 2.3.4.1 接口
        • 2.3.4.2 实现类
      • 2.3.5 切入点表达式
      • 2.3.6 定义切面类
      • 2.3.7 让AOP生效
      • 2.3.8 编辑测试类
    • 2.4 AOP形象化的比喻
    • 2.5 关于切入点表达式解析
      • 2.5.1 bean标签写法
      • 2.5.2 within表达式
      • 2.5.3 execution表达式
    • 2.6 按照自定义注解进行拦截
      • 2.6.1 自定义注解
      • 2.6.2 切入点表达式写法
      • 2.6.3 在service层实现类UserServiceImpl的addUser()方法上添加自定义的注解
    • 2.7 动态获取注解参数
      • 2.7.1 自定义注解
      • 2.7.2 使用注解
      • 2.8.3 需求
      • 2.8.4 编辑切面类
    • 2.8 通知方法
      • 2.8.1 关于通知方法解析
      • 2.8.2 前置通知案例
      • 2.8.3 后置通知案例
        • 2.8.3.1 添加接口方法
          • 1.编辑接口
          • 2.编辑实现类
        • 2.8.3.2 编辑AOP切面类SpringAOP
        • 2.8.3.3 编辑测试案例
        • 2.8.3.4 测试效果
      • 2.8.4 异常通知案例
        • 2.8.4.1 让service层实现类代码报错
        • 2.8.4.2 异常通知案例
        • 2.8.4.3 测试结果
  • 常用注解

1.动态代理总结

1.1 JDK动态代理特点

  1. 类型名称: class com.sun.proxy.$Proxy9
  2. 要求: 要求被代理者,必须是接口或者是实现类.
  3. JDK代理是java原生提供的API 无需导包.
  4. JDK动态代理在框架的源码中经常使用.
  5. 代理类和被代理类继承相同的接口,所以两者为兄弟关系

1.2 CGlib动态代理

1.2.1 CGLib特点说明

历史原因: JDK动态代理要求必须"有接口",但是某些类它没有接口,则无法使用JDK代理生成代理对象. 所以为了填补知识的空缺,则引入cglib代理.

问题说明: cglib动态代理 要求有无接口都可以创建代理对象. 问题? 如何保证和被代理者"相同"
答案(特点): 要求cglib动态代理继承被代理者.代理对象是被代理者的子类.

代理类和被代理类(目标类)两者是父子关系,代理对象是目标类的子类。

1.3 动态代理的作用

说明1: 一般我们将业务层中的耦合性高的代码,采用动态代理的方式进行解耦.使得程序更加具有扩展性. (业务逻辑的解耦)
说明2: Spring专门针对动态代理的规则.封装了一套API 起名 AOP

2 Spring中的AOP

2.1 AOP介绍

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

总结: Spring中的AOP 利用代理对象在不修改源代码的条件下,对方法进行扩展.

2.2 AOP中专业术语(难点)

1).连接点: 用户可以被扩展的方法
2).切入点: 用户实际扩展的方法
3).通知: 扩展方法的具体实现
4).切面: 将通知应用到切入点的过程

2.3 AOP 入门案例

2.3.1 创建一个SpringBoot的module

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

2.3.1 导入jar包

<!--引入AOPjar包文件-->
        <dependency>
  	          <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>       

2.3.2 项目工程结构

在这里插入图片描述

2.3.3 配置类

SpringConfig.java

package com.jt.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@ComponentScan("com.jt")
@Configuration
public class SpringConfig {

}

2.3.4 Service层

2.3.4.1 接口

package com.jt.service;

public interface UserService {
    void addUser();
    void deleteUser();
}

2.3.4.2 实现类

package com.jt.service;

import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {

    @Override
    public void addUser() {
        System.out.println("完成用户新增");
    }

    @Override
    public void deleteUser() {
        System.out.println("完成用户删除操作");
    }
}

2.3.5 切入点表达式

切入点表达式

  • bean(“对象的Id”) 每次拦截,只拦截1个
  • within(“包名.类名”)
  • execution(返回值类型 包名.类名.方法名(参数列表))
  • @annotation(注解的路径)

2.3.6 定义切面类

package com.jt;

import com.jt.config.SpringConfig;
import com.jt.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestSpring_AOP {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
        UserService userService = applicationContext.getBean(UserService.class);
        //如果是实现类对象,则方法没有被扩展
        //如果是代理对象,则方法被扩展 aop有效的
        System.out.println(userService.getClass());//class com.jt.service.UserServiceImpl$$EnhancerBySpringCGLIB$$baeada27
        userService.addUser();
    }
}

2.3.7 让AOP生效

说明: 编辑配置类,添加@EnableAspectJAutoProxy,让AOP机制有效
在这里插入图片描述

package com.jt.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@ComponentScan("com.jt")
@Configuration
@EnableAspectJAutoProxy//让spring中的AOP生效
public class SpringConfig {

}


2.3.8 编辑测试类

package com.jt;

import com.jt.config.SpringConfig;
import com.jt.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestSpring_AOP {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
        //理论值:根据接口获取实现类对象 但是与切入点表达式匹配,为了后续扩展方便,为其创建代理对象
        UserService userService = applicationContext.getBean(UserService.class);
        //如果是实现类对象,则方法没有被扩展
        //如果是代理对象,则方法被扩展 aop有效的(是代理对象)
        /*getClass()是Object中的方法,不拦截*/
        System.out.println(userService.getClass());//class com.jt.service.UserServiceImpl$$EnhancerBySpringCGLIB$$baeada27
        userService.addUser();
    }
}


2.4 AOP形象化的比喻

说明: AOP是一种抽象的一种概念,看不见/摸不着.所以需要大家对概念有自己的认知.
在这里插入图片描述

2.5 关于切入点表达式解析

2.5.1 bean标签写法

@Pointcut(“bean(userServiceImpl)”) 只匹配ID为userServiceImpl的对象

2.5.2 within表达式

@Pointcut(“within(com.jt.service.*)”) 匹配xx.xx.service下的所有对象

2.5.3 execution表达式

@Pointcut("execution(* com.jt.service..*.*(..))")
拦截返回值类型任意 xx.xx.service包下所有子孙包的所有类的任意方法
@Pointcut("execution(* com.jt.service..*.add*(..))")
拦截返回值类型任意 xx.xx.service包下所有子孙包的所有类.以add开头的方法

在这里插入图片描述

2.6 按照自定义注解进行拦截

2.6.1 自定义注解

package com.jt.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)             //注解对方法有效
@Retention(RetentionPolicy.RUNTIME)     //运行期有效
public @interface MyAnnotation {//注解起标记作用


}

2.6.2 切入点表达式写法

在这里插入图片描述

@Pointcut("@annotation(com.jt.anno.MyAnnotation)")
    public void pointCutMethod(){

    }

2.6.3 在service层实现类UserServiceImpl的addUser()方法上添加自定义的注解

在这里插入图片描述
测试类运行
在这里插入图片描述

2.7 动态获取注解参数

2.7.1 自定义注解

package com.jt.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Find {
    int id() default 0;
}

2.7.2 使用注解

在service层的实现类UserServiceImp的addUser()方法上面添加自定义注解@Find(id=101)
在这里插入图片描述

2.8.3 需求

利用前置通知,打印注解中的id值!!!

2.8.4 编辑切面类

/**
     * 知识点:
     * 如果切入点表达式只对当前通知有效,则可以按照如下方式编辑
     * 要求:动态的拦截Find注解,并且要获取Find注解中的参数Id
     * 难点:动态获取注解的对象!!
     * 代码解释:
     *      1.@annoattion(find) 拦截find变量名称对应类型的注解
     *      2.当匹配该注解后,将注解对象当做参数传递给find
     *      优势:可以一步到位获取注解的内容,避免了反射的代码
     */
    @Before("@annotation(find)")
    public void before2(Find find){
        System.out.println("ID的值为:"+find.id());
    }

2.8 通知方法

2.8.1 关于通知方法解析

1.前置通知 在目标方法执行之前执行.
2.后置通知 在目标方法执行之后执行.
3.异常通知 在目标方法执行之后抛出异常时执行.
4.最终通知 都要执行的通知
说明: 上述的四大通知一般用于记录程序的运行状态.只做记录.
5.环绕通知 在目标方法执行前后都要执行的通知

2.8.2 前置通知案例

切面类
SpringAOP.java

 /**
     * 定义通知方法:
     *  1.前置通知 在目标方法执行之前执行
     *  2.后置通知 在目标方法执行之后执行
     *  3.异常通知 在目标方法执行之后抛出异常时执行
     *  4.最终通知 都要执行的通知
     *  5.环绕通知 在目标方法执行前后都要执行的通知
     *
     *记录程序的状态
     * 1.目标对象的class/类路径 com.jt.xx.xxx.UserServiceImpl
     * 2.目标对象的方法名
     * 3.目标对象的方法的参数信息
     * 4.获取目标对象方法的返回值
     * 5.获取目标对象执行报错的异常信息
     */
    @Before("pointCutMethod()")
    public void before(JoinPoint joinPoint){
        //1.获取目标对象的类型
        Class<?> targetClass = joinPoint.getTarget().getClass();
        //2.获取目标对象的路径
        String path = joinPoint.getSignature().getDeclaringTypeName();
        //3.获取目标对象的方法名称
        String methodName = joinPoint.getSignature().getName();
        //4.获取方法的参数
        Object[] args = joinPoint.getArgs();

        System.out.println("类型" + targetClass);
        System.out.println("类的路径:" + path);
        System.out.println("方法名:" + methodName);
        System.out.println("参数:" + Arrays.toString(args));
    }

运行结果
在这里插入图片描述

2.8.3 后置通知案例

2.8.3.1 添加接口方法

1.编辑接口

在这里插入图片描述

package com.jt.service;

public interface UserService {
    void addUser();
    void deleteUser();
    int findCount();//查询总数
}


2.编辑实现类

在这里插入图片描述

package com.jt.service;

import com.jt.anno.Find;
import com.jt.anno.MyAnnotation;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {

    @Find(id = 101)
    @MyAnnotation//标记作用
    @Override
    public void addUser() {
        System.out.println("完成用户新增");
    }

    @Override
    public void deleteUser() {
        System.out.println("完成用户删除操作");
    }


    /**
     * 测试获取返回值的!!!
     * @return
     */
    @MyAnnotation
    @Override
    public int findCount() {
        return 1000;
    }
}

2.8.3.2 编辑AOP切面类SpringAOP

在这里插入图片描述

//注意事项:如果多个参数,joinPoint必须位于第一位!!!
    @AfterReturning(value="pointCutMethod()",returning = "result")
    public void afterReturn(JoinPoint joinPoint,Object result){
        //如果需要获取当前的方法信息,则可以通过joinPoint获取
//        System.out.println("我是后置通知");
        System.out.println("我是后置通知,获取方法的返回值"+result);
    }

2.8.3.3 编辑测试案例

package com.jt;

import com.jt.config.SpringConfig;
import com.jt.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestSpring_AOP02 {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
        //理论值:根据接口获取实现类对象 但是与切入点表达式匹配,为了后续扩展方便,为其创建代理对象
        UserService userService = applicationContext.getBean(UserService.class);
        //如果是实现类对象,则方法没有被扩展
        //如果是代理对象,则方法被扩展 aop有效的(是代理对象)
        /*getClass()是Object中的方法,不拦截*/
        System.out.println(userService.getClass());//class com.sun.proxy.$Proxy19
        userService.addUser();
        userService.findCount();//测试代返回值的方法
    }
}

2.8.3.4 测试效果

在这里插入图片描述

2.8.4 异常通知案例

2.8.4.1 让service层实现类代码报错

在这里插入图片描述

2.8.4.2 异常通知案例

throwing:获取异常信息,之后进行传递

 //后置通知与异常通知是互斥的,只能有一个
    @AfterThrowing(value = "pointCutMethod()",throwing = "exception")
    public void afterThrow(JoinPoint joinPoint,Exception exception){
        //打印异常
        //exception.printStackTrace();
        System.out.println("我是异常通知:"+exception.getMessage());
    }

2.8.4.3 测试结果

在这里插入图片描述

常用注解

@Configuration 标识当前类是配置类
@ComponentScan 包扫描注解 扫描注解
@Bean 标识该方法的返回值交给Spring容器管理
@Scope 控制多例和单例
@Lazy 懒加载
@PostConstruct 初始化方法
@PreDestroy 销毁方法
@Component 将当前类未来的对象交给容器管理
@Autowired 按照类型进行注入
@Qualifier 按照名称进行注入
@Repository 标识持久层注解
@Service 标识Service层
@Controller 标识Controller层
@Value 为属性赋值 @Value(“${key}”)
@PropertySource 加载指定路径的配置文件properties
@Aspect 标识当前类是一个切面类
@Pointcut 用于定义切入点表达式 表达式写法4种
@EnableAspectJAutoProxy 让AOP的注解有效果
@Before AOP-前置通知
@AfterReturning AOP-后置通知
@AfterThrowing AOP-异常通知
@After AOP-最终通知
@Around AOP-环绕通知

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/399754.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【点云学习】多时相激光雷达点云

多时相雷达数据&#xff08;multi-tempral LiDAR data&#xff09; 1 一种多时相激光雷达数据建筑物变化检测方法-汪承义&#xff08;2013&#xff09; 背景&#xff1a;空间分辨率的提高引入了“类内可分性”增加与“类间可分性”降低&#xff1b;遮挡与阴影的存在使问题变得…

pytorch权值初始化和损失函数

pytorch权值初始化和损失函数 权值初始化 梯度消失与爆炸 针对上面这个两个隐藏层的神经网络&#xff0c;我们求w2的梯度 可以发现&#xff0c;w2的梯度与H1&#xff08;上一层网络的输出&#xff09;有很大的关系&#xff0c;当h1趋近于0时&#xff0c;w2的梯度也趋近于0&am…

swoole的强大之处,你可能只是略知一二!

首先 swoole 是 php 的一个扩展程序swoole 是一个为 php 用 c 和 c 编写的基于事件的高性能异步 & 协程并行网络通信引擎swoole 是一个多进程模型的框架&#xff0c;当启动一个进程 swoole 应用时&#xff0c;一共会创建 2nm 个进程&#xff0c;n 为 worker 进程数&#xf…

maven将jar文件上传至本地仓库及私服

maven官方仓库有些依赖并不存在&#xff0c;现在项目都是maven直接获取jar&#xff0c;当maven获取不到时&#xff0c;需要我们把jar上传至maven仓库。已 ImpalaJDBC41.jar 文件为例&#xff0c;如&#xff1a;希望上传后&#xff0c;设置的依赖为&#xff1a;<dependency&g…

数字化工厂装配线生产管理看板系统

电力企业业务复杂&#xff0c;组织结构复杂&#xff0c;不同的业务数据&#xff0c;管理要求也不尽相同。生产管理看板系统针对制造企业的生产应用而开发&#xff0c;能够帮助企业建立一个规范准确即时的生产数据库。企业现状&#xff1a;1、计划不清晰&#xff1a;生产计划不能…

python程序设计基础 实验四

⭐python实验专栏&#xff0c;欢迎订阅与关注&#xff01; ★观前提示&#xff1a;本篇内容为python程序设计实验&#xff0c;代码内容经测试没有问题&#xff0c;但是可能会不符合每个人实验的要求&#xff0c;因此以下内容建议仅做思路参考。 一、实验目的 &#xff08;1&am…

2.webpack loader

webpack默认只能处理 以 .js 为后缀名的文件&#xff0c;其他的文件需要用loader&#xff0c;比如 css-loader 可以打包处理.css相关的文件less-loader 可以打包处理 .less相关的文件babel-loader 可以打包处理webpack无法处理的高级JS语法 目录 1 css-loader 1.1 安装 1…

[学习笔记] 2. 数据结构

数据结构视频地址&#xff1a;https://www.bilibili.com/video/BV1uA411N7c5 数据结构是指相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成。简单来说&#xff0c;数据结构就是设计数据以何种方式组织并存储在计算机中。 比如:列表、集合与字…

“小霞”黄绮珊绮望三十巡回演唱会将于3月18日杭州大剧院震撼开唱!

•中年成名 四十余载静待盛放 歌手黄绮珊&#xff0c;1991年正式进入歌坛&#xff0c;至今已满三十周年。黄绮珊前半生的歌手之路好像并不是那么顺畅。虽然一直有着华语乐坛的顶尖歌唱实力&#xff0c;但在45岁之前&#xff0c;黄绮珊一直处于“歌红人不红”的状态。不少人听过…

postgresql 自动备份 bat实现

postgres数据据备分,用cmd命令有些烦,写了个bat实现 BAT脚本中常用的注释命令有rem、@rem和:: rem、@rem和::用法都很简单,直接在命令后加上要注释的语句即可。例如下图,语言前加了rem,运行BAT时就会自动忽略这个句子。需要注释多行时,每行前面都要加上rem、@rem和::。…

Kalman Filter in SLAM (3) ——Extended Kalman Filter (EKF, 扩展卡尔曼滤波)

文章目录1. 线性系统的 Kalman Filter 回顾2. Extended Kalman Filter 之 DR_CAN讲解笔记2.1. 非线性系统2.2. 非线性系统线性化2.2.1. 状态方程f(xk)f(x_k)f(xk​)在上一次的最优估计状态x^k−1\hat{x}_{k-1}x^k−1​处线性化2.2.2. 观测方程h(xk)h(x_k)h(xk​)在这一次的预测…

企业知识管理应该怎么做?

企业知识管理是指企业利用各种信息技术手段&#xff0c;对企业内部的知识进行收集、整理、分析和传递&#xff0c;以提高企业的知识水平和竞争力。企业知识管理涉及到企业内部的各种知识&#xff0c;包括技术知识、专业知识、经验知识、市场知识等。 企业知识管理的方式可以分为…

DETR目标检测算法学习记录

引言 无论是One Stage中的YOLO还是Two-Stage中的Faster-RCNN&#xff0c;其虽然都在目标检测领域有着一席之地&#xff0c;但无一例外都是基于Anchor的模型算法&#xff0c;这就导致其在输出结果时不可避免的进行一些如非极大值抑制等操作来进一步选择最优解&#xff0c;这会带…

uniCloud基础使用

获取openID云函数use strict; exports.main async (event, context) > {//event为客户端上传的参数console.log(event : , event)// jscode2session 微信小程序登录接口&#xff0c;获取openidconst {code} event;// 云函数中如需要请求其他http服务&#xff0c;则使用uni…

Day912.多环境配置隔离 -SpringBoot与K8s云原生微服务实践

多环境配置隔离 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于多环境配置隔离的内容。 多环境支持&#xff0c;是现在互联网开发研发和交付的主流基本需求。通过规范多环境配置可以规范开发流程&#xff0c;并同时提示项目的开发质量和效率等。 一个公司应该规范…

网络使用情况监控

您的网络是否经常成为网络紧张或带宽瓶颈的牺牲品&#xff1f;瓶颈并不一定意味着带宽不足&#xff1b;它们可能是由占用带宽到严重网络威胁等任何因素造成的。密切监控您的网络并分析带宽使用情况和网络流量对于找到问题的根源非常重要。NetFlow Analyzer是最先进的网络使用情…

Simulink自动化-Matlab脚本自动创建Runnable及mapping

文章目录前言设计Excel模板编写matlab脚本自动添加Function到Simulink模型自动mapping Function与Runnable总结前言 在之前的一篇文章中&#xff0c;介绍了Autosar S/R接口的自动创建及mapping,传送门&#xff1a;Simulink自动化-Matlab脚本自动生成Autosar RTE S/R接口及mapp…

mujoco安装及urdf转xml方法记录

参考 mujoco210及mujoco-py安装 下载适用于Linux或 OSX的 MuJoCo 2.1 版二进制文件 。 将mujoco210的下载的目录解压到~/.mujoco/mujoco210路径下. 注意&#xff1a;如果要为包指定非标准位置&#xff0c;请使用环境变量MUJOCO_PY_MUJOCO_PATH。 验证是否安装成功&#xff08…

springcloud3 fegin服务超时的配置和日志级别的配置2

一 fegin的概述 1.1 fegin的默认超时时间 默认fegin客户端只等待1秒钟&#xff0c;超过1秒钟&#xff0c;直接会返回错误。 1.2 架构图 1.2.1 说明 1.2.2 启动操作 1.先启动9001,9002 eureka 2.启动9003 服务提供者 3.启动9006消费者 1.3 情况验证 1.3.1 正常默认情…