SpringBoot下的Spring——DAY04——动态代理总结、AOP、自定义注解进行拦截、动态获取注解参数、通知方法(内含源代码)
创始人
2024-05-31 13:12:32
0

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包

org.springframework.bootspring-boot-starter-aop       

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 {@Overridepublic void addUser() {System.out.println("完成用户新增");}@Overridepublic 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$$baeada27userService.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$$baeada27userService.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//标记作用@Overridepublic void addUser() {System.out.println("完成用户新增");}@Overridepublic void deleteUser() {System.out.println("完成用户删除操作");}/*** 测试获取返回值的!!!* @return*/@MyAnnotation@Overridepublic 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.$Proxy19userService.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-环绕通知

相关内容

热门资讯

安卓系统用的华为应用,探索智能... 你知道吗?在安卓系统里,华为的应用可是个宝库呢!它们不仅功能强大,而且使用起来超级方便。今天,就让我...
安卓变ios系统魅蓝 你知道吗?最近有个朋友突然告诉我,他要把自己的安卓手机换成iOS系统,而且还是魅蓝品牌的!这可真是让...
幻书启世录安卓系统,安卓世界中... 亲爱的读者们,你是否曾在某个夜晚,被一本神奇的书所吸引,仿佛它拥有着穿越时空的力量?今天,我要带你走...
电脑安装安卓系统进不去,安卓系... 电脑安装安卓系统后竟然进不去,这可真是让人头疼的问题啊!你是不是也遇到了这种情况,心里直呼“怎么办怎...
用键盘切换控制安卓系统,畅享安... 你有没有想过,用键盘来控制你的安卓手机?是的,你没听错,就是那个我们每天敲敲打打的小玩意儿——键盘。...
小米安卓镜像系统在哪,小米安卓... 你有没有想过,你的小米手机里有一个隐藏的宝藏——安卓镜像系统?没错,就是那个可以让你的手机瞬间变身成...
安卓手机下载排班系统,高效排班... 你有没有想过,每天忙碌的工作中,有没有什么好帮手能帮你轻松管理时间呢?今天,就让我来给你介绍一个超级...
桌面组件如何弄安卓系统,桌面组... 亲爱的桌面爱好者们,你是否曾梦想过将安卓系统搬到你的电脑桌面上?想象那些流畅的动画、丰富的应用,还有...
安卓13系统介绍视频,新功能与... 亲爱的读者们,你是否对安卓13系统充满好奇?想要一探究竟,却又苦于没有足够的时间去研究?别担心,今天...
车机安卓7.1系统,功能升级与... 你有没有发现,现在的车机系统越来越智能了?尤其是那些搭载了安卓7.1系统的车机,简直就像是个贴心的智...
安卓系统下如何读pdf,And... 你有没有遇到过这种情况:手机里存了一大堆PDF文件,可是怎么也找不到一个能顺畅阅读的工具?别急,今天...
安卓系统全国通用的吗,畅享智能... 你有没有想过,为什么你的手机里装的是安卓系统呢?安卓系统,这个名字听起来是不是有点神秘?今天,就让我...
假苹果手机8安卓系统,颠覆传统... 你有没有想过,如果苹果手机突然变成了安卓系统,会是怎样的景象呢?想象那熟悉的苹果外观,却运行着安卓的...
安卓12.0系统vivo有吗,... 你有没有听说最近安卓系统又升级啦?没错,就是那个让手机焕然一新的安卓12.0系统!那么,咱们国内的手...
核心芯片和安卓系统,探索核心芯... 你知道吗?在科技的世界里,有一对“黄金搭档”正悄悄改变着我们的生活。他们就是——核心芯片和安卓系统。...
如何调安卓系统屏幕颜色,安卓系... 亲爱的手机控们,你是否曾觉得安卓系统的屏幕颜色不够个性,或者是因为长时间盯着屏幕而感到眼睛疲劳?别担...
旧台式电脑安装安卓系统,轻松安... 你那台旧台式电脑是不是已经服役多年,性能逐渐力不从心,却又不忍心让它退役呢?别急,今天就来教你怎么给...
美国要求关闭安卓系统,科技霸权... 美国要求关闭安卓系统:一场技术革新还是政治博弈?在数字化时代,智能手机已经成为我们生活中不可或缺的一...
安卓系统日记本 你有没有发现,手机里的安卓系统日记本,简直就是记录生活点滴的宝藏库呢?想象每天忙碌的生活中,有没有那...
安卓手机广告最少的系统,探索安... 你有没有发现,用安卓手机的时候,广告总是无处不在,让人烦得要命?不过别急,今天我要给你揭秘一个秘密—...