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系统.数据,数据迁... 你有没有想过,手机系统就像是我们生活中的衣服,有时候换一件新衣服,整个人都焕然一新呢?没错,今天咱们...
安卓系统提示怎么关,轻松关闭功... 手机屏幕上突然弹出一个安卓系统的提示,让你不禁皱起了眉头。别急,别慌,今天就来手把手教你如何轻松关闭...
安卓系统如何刷回flyme系统... 你是不是也和我一样,对安卓手机的Flyme系统情有独钟呢?有时候,因为一些原因,我们可能需要将手机刷...
手机订餐系统源码安卓,基于手机... 你有没有想过,每天忙碌的生活中,点外卖已经成为了一种不可或缺的享受?而这一切的背后,离不开那些默默无...
顾问营销系统安卓版,助力企业高... 你有没有想过,在这个信息爆炸的时代,如何让你的产品在众多竞争者中脱颖而出呢?别急,今天我要给你介绍一...
安卓系统连接雅马哈音箱,打造个... 你有没有想过,家里的安卓手机和雅马哈音箱也能来个甜蜜的“牵手”呢?没错,今天就要来给你揭秘,如何让这...
安卓系统文件日志查看,揭秘系统... 手机里的安卓系统文件日志,听起来是不是有点儿高深莫测?别担心,今天我就要带你一探究竟,揭开这些神秘日...
努比亚升级安卓p系统,畅享智能... 你知道吗?最近手机界可是热闹非凡呢!努比亚这个品牌,竟然悄悄地给他们的手机升级了安卓P系统。这可不是...
仿苹果装安卓系统,揭秘仿苹果装... 你有没有想过,如果你的苹果手机突然变成了安卓系统,那会是怎样的场景呢?想象你那熟悉的iOS界面,突然...
安装安卓13子系统,全新功能与... 你听说了吗?安卓13子系统终于来了!这可是安卓系统的一大革新,让我们的手机体验更加丰富多元。今天,就...
安卓系统内核日志保存,深度洞察... 你有没有想过,当你手机里的安卓系统在默默运行时,它其实就像一个勤劳的小蜜蜂,不停地记录着它的“工作日...
安卓系统可以调用dll,安卓系... 你知道吗?安卓系统竟然能调用DLL文件,这可是个让人眼前一亮的小秘密呢!想象你手中的安卓设备,不仅能...
安卓通讯 录系统代码,基于安卓... 你有没有想过,你的手机里那个默默无闻的通讯录系统,其实背后有着一套复杂的代码在支撑呢?今天,就让我带...
安卓系统版本对应关系,安卓系统... 你有没有发现,每次手机更新系统,那感觉就像给手机换了个新衣裳,焕然一新呢!不过,你知道吗?安卓系统的...
小米note安卓系统4.4.4... 你有没有用过小米Note这款手机呢?那可是我心中的小宝贝,尤其是它的安卓系统4.4.4,简直让我爱不...
安卓系统取代了谁,谁在退居幕后... 你知道吗?在科技的世界里,总有一些“老将”被新一代的“新星”所取代。今天,咱们就来聊聊这个话题:安卓...
安卓系统能否上Facebook... 你有没有想过,你的安卓手机能不能轻松登录Facebook呢?这个问题,估计不少安卓用户都好奇过。今天...
安卓系统费电怎么解决,安卓系统... 手机电量总是不够用,是不是你也觉得安卓系统的费电问题让人头疼呢?别急,今天就来给你支几招,让你的安卓...
鸿蒙怎样还原安卓系统,系统切换... 你有没有想过,鸿蒙系统竟然能还原安卓系统?这听起来是不是有点像魔法一样神奇?没错,今天就要带你一探究...