Spring学习(四)反射、AOP、JUnit

news/2024/4/29 20:59:09/文章来源:https://blog.csdn.net/bollks/article/details/137450962

文章目录

  • Java反射
    • 回顾
  • AOP
    • 代理模式
    • AOP概念及术语
      • 概述
      • 术语
      • 作用
    • 基于注解的AOP
      • 步骤
      • 依赖
      • 配置文件
      • 切入点表达式语法
      • 切面类
      • 重用切入点表达式
      • 切面的优先级
    • 基于XML的AOP
  • 单元测试JUnit
    • 引入依赖
    • JUnit5

Java反射

Spring框架的IoC基于java反射机制实现,反射是指在运行状态中,对任意类都能知道其所有属性和方法;对任何对象都能调用其所有方法和属性。即程序在运行时能够获取自身信息。
剖析一个类则需获取到该类的class对象,使用到java.lang.classjava.lang.relectAPI,Class对象是反射的根源。

回顾

  1. 首先创建类和测试类
package com.jobs.reflect;public class Car {private String name;private String color;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}public Car(String name, String color) {this.name = name;this.color = color;}public Car() {}private void drive(){System.out.println("drive");}
}
  1. 获取Class对象的多种方法
public class CarTest {public carTest1() throws Exception {//1 类名.classClass aClass1 = Car.class;//2 对象.getClass()Class aClass2 = new Car().getClass();//3 Class.forName("全路径")Class aClass3 = Class.forName("com.jobs.reflect.Car");}
}
  1. 获取构造方法
public void carTest02() throws Exception{//获取所有构造//getConstructors()获取public//getDeclaredConstructors()获取所有(public、private)Class aclass = Car.class;Constructor[] constructors = aclass.getConstructors();for (Constructor c :constructors) {System.out.println(c.getName() + " " + c.getParameterCount());}//指定有参构造创建对象//publicConstructor c1 = aclass.getConstructor(String.class, String.class);Car car1 = (Car) c1.newInstance("小米","blue");//privateConstructor c2 = aclass.getDeclaredConstructor(String.class, String.class);//必须先允许访问才可更改c2.setAccessible(true);Car car2 = (Car) c2.newInstance("保时捷","red");
}
  1. 获取属性及向属性赋值
@Test
public void carTest03() throws Exception {Class aclass = Car.class;Car car = (Car) aclass.getDeclaredConstructor().newInstance();//获取所有属性//getFields() ---- public//getDeclaredFields() ---- 所有Field[] fields = aclass.getFields();Field[] fieldss = aclass.getDeclaredFields();for (Field field :fieldss) {if (field.getName().equals("name")) {//必须先允许访问才可更改field.setAccessible(true);field.set(car, "xiaomi");}if (field.getName().equals("color")) {field.setAccessible(true);field.set(car, "blue");}System.out.println(car);}
}
  1. 获取方法
public void carTest04() throws Exception {Car car = new Car("xiaomi", "blue");Class aclass = car.getClass();//getMethods() ---- pulic//getDeclaredMethods() --- allMethod[] methods = aclass.getMethods();for (Method m :methods) {if (m.getName().equals("toString")) {String invoke = (String) m.invoke(car);System.out.println(invoke);}}Method[] methodss = aclass.getDeclaredMethods();for (Method m :methodss) {if (m.getName().equals("drive")) {//先许可m.setAccessible(true);m.invoke(car);}}
}

AOP

代理模式

  1. 属于结构型模式的设计模式,作用为通过一个代理类,使得在调用目标方法时,不再直接对目标方法进行调用,而是通过代理类进行间接调用。让不属于目标方法核心逻辑的内容从中剥离,达成解耦。
  2. 调用目标方法时先调用代理对象的方法,减少对目标方法的调用和打扰,同时让附加功能能够集中在一起,便于统一维护。
    在这里插入图片描述
    在这里插入图片描述

代理:将非核心逻辑剥离后,封装这些非核心逻辑的类、对象、方法
目标:被代理”套用了“非核心逻辑代码的类、对象、方法

  1. 静态代理
    创建代理类,在代理类中创建目标对象,非核心逻辑代码外调用目标方法;
    虽然实现了解耦,但代码已经固定,因此不具备灵活性;
public class CalculatorStaticProxy implements Calculator{//传入目标对象private Calculator calculator;public CalculatorStaticProxy(Calculator calculator){this.calculator = calculator;}@Overridepublic int add(int a, int b){System.out.println("[日志]");//调用目标方法int result = calculator.add(a, b);System.out.println("[日志]");return result;
}
  1. 动态代理
    将非核心逻辑功能集中到代理类中,将来有任何此功能需求,都能通过该代理类实现。
    在这里插入图片描述
代理类
public class ProxyFactory {//目标对象private Object target;public ProxyFactory(Object target){this.target = target;}//返回代理对象public Object getProxy(){/** Proxy.newProxyInstance()有三个参数* 1 ClassLoader:加载动态生成代理类的加载器* 2 Class[] interfaces:目录对象实现的所有接口的class类型数组* 3 InvocationHandler:设置代理对象实现目标对象方法的过程* *///1 ClassLoaderClassLoader classLoader = target.getClass().getClassLoader();//2 Class[] interfacesClass<?>[] interfaces = target.getClass().getInterfaces();//3 InvocationHandlerInvocationHandler invocationHandler = new InvocationHandler(){//1 proxy:代理对象//2 method:需要重写目标对象的方法//3 args:method方法所需参数@Overridepublic Object invoke(Object proxy,Method method,Object[] args) throws Throwable {//方法调用前System.out.println("[动态代理日志] "+method.getName()+", 参数" + Arrays.toString(args));//调用目标方法Object result = method.invoke(target, args);//方法调用后System.out.println("[动态代理日志] "+method.getName()+", 结果" + result);return result;}};return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);}
}
测试
public class CalculatorTest {public static void main(String[] args) {ProxyFactory proxyFactory = new ProxyFactory(new CalculatorImpl());Calculator proxy = (Calculator) proxyFactory.getProxy();proxy.add(1, 2);}
}
输出结果
[动态代理日志] add, 参数[1, 2]
[动态代理日志] add, 结果3

AOP概念及术语

概述

AOP(aspect oriented programming)是一种设计思想,面向切面编程,以预编译和运行期动态代理方式实现。在不修改源代码的情况下,给程序动态统一添加额外功能的一种技术。
利用AOP对业务逻辑各部分进行隔离,从而降低耦合,提高程序可重用性,提高开发效率。

术语

  1. 横切关注点
    分散在各模块中解决同一问题,可抽取出来的同一类非核心业务;
    此概念不是语法层面,而是根据附加功能逻辑层面需要;
  2. 通知(增强)
    每一个横切关注点上要做的事情都需要写一个方法来实现,这样的方法就叫通知方法;

前置通知:目标方法执行;
返回通知:目标方法成功结束后执行
异常通知:目标方法异常结束后执行
后置通知:目标方法最终结束后执行
环绕通知:使用try—catch—finally围绕整个目标方法,包含上述四种通知位置

  1. 切面
    封装通知方法的类
    在这里插入图片描述
  2. 目标
    被代理的目标对象
  3. 代理
    代理对象
  4. 连接点
    逻辑概念,方法中每个横切位置看作连接点,即Spring允许使用通知的地方
  5. 切入点
    定位连接点的方式,Spring的AOP技术可以通过切入点定位到特定的连接点,即要增强的地方
    eg. 连接点—数据库中的记录;切入点—查询记录的SQL语句

作用

  • 简化代码:抽取固定位置重复代码,让目标方法专注核心功能;
  • 代码增强:特定功能封装进切面类中,在有需要的地方套用,被套用了切面逻辑的方法就被切面增强;

基于注解的AOP

  1. 动态代理分为JDK方式和cglib方式;
  2. 当目标类有接口时使用JDK和cglib方式,没有接口时只能使用cglib方式;
  3. JDK动态代理生成代理类会在com.sun.proxy包下,类名为$proxy1,和目标类实现相同接口;
  4. cglib动态代理生成代理类会在目标相同包下,继承目标类;
    在这里插入图片描述
    在这里插入图片描述
  5. AspectJ:AOP思想的一种实现,本质是静态代理,其将代理逻辑”织入“目标类编译得到的字节码文件,所以最终效果是动态的。Spring只是借用AspectJ的注解。

步骤

  1. 引入AOP依赖
  2. 创建目标资源:接口;实现类;
  3. 创建切面类:切入点;通知类型;

依赖

<!--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>

配置文件

<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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!--组件扫描--><context:component-scan base-package="com.jobs.spring6.aop.annotation_aop"></context:component-scan><!--aspectj自动代理,并为目标对象生成代理--><aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</bean>

切入点表达式语法

在这里插入图片描述

切面类

设置切面类即可在目标对象上套用切面功能

@Aspect//切面类
@Component//IoC容器
public class LogAspect {//设置切入点和通知类型//切入点表达式://execution(访问修饰符 增强方法返回类型 增强方法所在类的全路径.方法名称(参数列表)//通知类型://前置@Befor(value="切入点表达式")@Before(value = "execution(public int com.jobs.spring6.aop.annotation_aop.CalculatorImpl.*(..))")public void beforeMethod(){System.out.println("before!");}//返回@AfterReturning//returning可以传递至方法内部,要求同名@AfterReturning(value = "execution(public int com.jobs.spring6.aop.annotation_aop.CalculatorImpl.*(..))",returning = "result")public void afterReturningMethod(Object result){System.out.println("afterreturning! result: " + result);}//异常@AfterThrowing//throwing可以传递错误信息至方法内部,要求同名@AfterThrowing(value = "execution(public int com.jobs.spring6.aop.annotation_aop.CalculatorImpl.*(..))",throwing = "exception")public void afterThrowingMethod(Throwable exception){System.out.println("afterthrowing! exception: " + exception);}//后置@After@After(value = "execution(public int com.jobs.spring6.aop.annotation_aop.CalculatorImpl.*(..))")public void afterMethod( ){System.out.println("after!");}//环绕@Around@Around(value = "execution(public int com.jobs.spring6.aop.annotation_aop.CalculatorImpl.*(..))")public Object afterReturningMethod(ProceedingJoinPoint joinPoint){Object result = null;try {System.out.println("around_before");//调用目标方法result = joinPoint.proceed();System.out.println("around_afterreturn");}catch (Throwable throwable){throwable.printStackTrace();System.out.println("around_afterthrow");}finally {System.out.println("around_after");}return result;}
}

在这里插入图片描述

重用切入点表达式

  1. 声明
//重用切入点表达式
@Pointcut(value = "execution(* com.jobs.spring6.aop.annotation_aop.CalculatorImpl.*(..))")
public void pointCut() { }
  1. 使用
//在同一个切面中,直接使用缩写
@After(value = "pointCut()")
//在不同切面中,添加缩写全路径
@After(value = "com.jobs.spring6.aop.annotation_aop.LogAspect.pointCut()")

切面的优先级

  1. 外层的切面 > 内层的切面
  2. 利用@Order注解可以控制优先级:

@Order(num1)…
@Order(num2)…
num1 > num2 则num2优先级高

基于XML的AOP

beanaop.xml
<!--配置aop通知类型-->
<aop:config><!--配置切面类--><aop:aspect ref="logAspect"><!--配置切入点--><aop:pointcut id="pointcut" expression="execution(*com.jobs.spring6.aop.xml_aop.CalculatorImpl.*(..))"/><!--配置通知--><!--before--><aop:before method="beforeMethod" pointcut-ref="pointcut"></aop:before><!--after--><aop:after method="afterMethod" pointcut-ref="pointcut"></aop:after><!--afterreturning--><aop:after-returning method="afterReturningMethod"returning="result"pointcut-ref="pointcut"></aop:after-returning><!--afterthrowing--><aop:after-throwing method="afterThrowingMethod"throwing="exception"pointcut-ref="pointcut"></aop:after-throwing><!--around--><aop:around method="aroundMethod" pointcut-ref="pointcut"></aop:around></aop:aspect>
</aop:config>

单元测试JUnit

减少固定任务

引入依赖

<!--spring整合junit依赖-->
<dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>6.0.2</version>
</dependency>

JUnit5

@SpringJUnitConfig(locations = "classpath:bean.xml")
/*      or
@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath:bean.xml")
*/
public class SpringJUnitTest {//injection@Autowiredprivate User user;//Test@Testpublic void userTest(){System.out.println(user);user.run();}
}

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

antd+Vue 3实现table行内upload文件图片上传【超详细图解】

目录 一、背景 二、效果图 三、代码 一、背景 一名被组长逼着干前端的苦逼后端&#xff0c;在一个晴天霹雳的日子&#xff0c;被要求前端订单产品实现上传产品图片并立刻回显图片。 二、效果图 三、代码 <template><a-table :dataSource"dataSource" :c…

CTF之矛盾

这一题就是php的弱比较“” 这里要求输入的不是数字&#xff0c;并且输入要为1才打印flag 那我们就输入一个1后面接随便什么字符&#xff0c;因为php的弱比较将字符与数字进行比较的时候&#xff0c;会把字符转换成数字再比较&#xff0c;当转换到字符时后面便都为空了 flag{…

Android如何实现一个应用位于前台时全局页面每隔三分钟弹出一次一天最多弹出5次的GroMore半插屏广告,处于付费页和后台时停止

首先我们需要添加一个全局的Application public class MyApp extends LitePalApplication {private static final String TAG "MyApp";private static Context mContext;private boolean isManageMent;public static String oaid;Overridepublic void onCreate() {…

【opencv】示例-epipolar_lines.cpp 对极线

这段代码总的功能是使用OpenCV库进行立体视觉的估计。它从命令行读取两个图像文件名&#xff0c;使用SIFT算法检测关键点并计算这些点的描述子&#xff0c;接着通过FLANN库进行快速近似最近邻搜索来找到匹配的关键点。然后使用RANSAC方法计算基础矩阵&#xff0c;找到内点&…

Python中大的一把锁

今天可以来讲解下GIL是个什么了。 GIL为什么是Python中大的一把锁&#xff1f; GIL是Global Interpreter Lock的缩写&#xff0c;翻译过来就是全局解释器锁。 从字面上去理解&#xff0c;它就是锁在解释器头上的一把锁&#xff0c;它使Python代码运行变得有序。 假如有一段…

基于FPGA轻松玩转AI

启动人工智能应用从来没有像现在这样容易&#xff01;受益于像Xilinx Zynq UltraScale MPSoC 这样的FPGA&#xff0c;AI现在也可以离线使用或在边缘部署、使用.可用于开发和部署用于实时推理的机器学习应用&#xff0c;因此将AI集成到应用中变得轻而易举。图像检测或分类、模式…

关于hive启动的相关问题记录

问题&#xff1a;初始化hive元数据报错 [atguiguhadoop102 software]$ schematool -initSchema -dbType mysql -verboseError: Table CTLGS already exists (state42S01,code1050) Closing: 0: jdbc:mysql://hadoop102:3306/metastore?useSSLfalse org.apache.hadoop.hive.me…

基于GAN的多变量时间序列污染训练集异常检测

论文地址&#xff1a;https://ieeexplore.ieee.org/document/9618824 论文源码&#xff1a;https://github.com/sxxmason/FGANomaly 期刊&#xff1a;IEEE Transactions on Knowledge and Data Engineering 多元时间序列异常检测在结构健康监测、智能运维、量化交易等诸多实际…

【Locust分布式压力测试】

Locust分布式压力测试 https://docs.locust.io/en/stable/running-distributed.html Distributed load generation A single process running Locust can simulate a reasonably high throughput. For a simple test plan and small payloads it can make more than a thousan…

推荐学习什么编程语言?

选择编程语言学习时&#xff0c;除了就业因素外&#xff0c;还可以考虑以下几个方面来决定学习哪些编程语言&#xff1a; 个人兴趣与目标&#xff1a;如果你对某个特定领域感兴趣&#xff0c;比如游戏开发、数据分析、人工智能等&#xff0c;可以选择与该领域紧密相关的编程语言…

MySql数据库从0-1学习-第三天多表设计学习

项目开发中,在进行数据库表结构设计时,会根据业务需求及业务模块之间的关系,分析并设计表结构,由于业务之间相互关联,所以各个表结构之间也存在着各种联系,基本上分为三种: 一对多(多对一)多对多一对一 一对多 需求:根据需求,完成部门和员工表的设计 一对多,很多人会使用外键,…

记录我第一场面了40min+的面试

中冶赛迪信息技术(重庆)有限公司 国企 首先3/24投递的&#xff0c;4/10打了电话问是否接受劳务派遣&#xff0c;我当时不知道劳务派遣什么意思&#xff0c;问了和售前售后是不是类似&#xff0c;得到了不大一样的回答&#xff0c;后面加了微信&#xff0c;定了11开始面试。 这…

【Ubuntu】 Github Readme导入GIF

1.工具安装 我们使用 ffmpeg 软件来完成转换工作1.1 安装命令 sudo add-apt-repository ppa:jonathonf/ffmpeg-3sudo apt-get updatesudo apt-get install ffmpeg1.2 转换命令 &#xff08;1&#xff09;直接转换命令&#xff1a; ffmpeg -i out.mp4 out.gif(2) 带参数命令&…

uos安装lxml避坑记录

环境&#xff1a;紫光电脑uos系统 python&#xff1a;系统自带3.7.3 条件&#xff1a;已打开开发者模式&#xff0c;可以自行安装应用商店之外的软件 一、pip3 install lxml4.8.0可以正正常下载&#xff0c;但出现如下错误 另&#xff1a;为什么是4.8.0&#xff1f;因为这个…

【前缀合】Leetcode 寻找数组的中心下标

题目解析 724. 寻找数组的中心下标 算法讲解 我们使用一个前缀和数组&#xff0c;一个后缀和数组 class Solution { public:int pivotIndex(vector<int>& nums) {// lsum[i] 表⽰&#xff1a;[0, i - 1] 区间所有元素的和// rsum[i] 表⽰&#xff1a;[i 1, n - …

计算机网络----第七天

交换机与路由器 路由器的作用&#xff1a; 作用&#xff1a;寻IP地址 路由转发 隔离广播域 交换和维护路由信息 路由器的特点&#xff1a; 特点&#xff1a;位于网络层 转发流量 实现从源地址到目的地址转发 支持丰富的接口类型 支持多种路由协议 支持数据链路层协议 交换…

机器学习——模型融合:平均法

机器学习——模型融合&#xff1a;平均法 在机器学习领域&#xff0c;模型融合是一种通过结合多个基本模型的预测结果来提高整体模型性能的技术。模型融合技术通常能够降低预测的方差&#xff0c;提高模型的鲁棒性&#xff0c;并在一定程度上提高预测的准确性。本文将重点介绍…

pyside6的QSpinBox自定义特性初步研究(二)

当前的需求是&#xff0c;蓝色背景的画面&#xff0c;需要一个相对应色系的QSpinBox部件。已有的部件风格是这样的&#xff0c;需要新的部件与之般配。 首先新建一个QDoubleSpinBox&#xff0c;并定义其背景色和边框&#xff1a; QDoubleSpinBox { color: white; border:1px…

【精选】发布应用到应用商店的基本介绍

摘要 本文旨在介绍如何在各大应用商店发布应用&#xff0c;包括市场选择、准备材料、上架步骤以及常见被拒原因及解决方法。通过详细的步骤和经验分享&#xff0c;帮助开发者顺利将应用推向市场。 引言 随着移动应用市场的不断发展&#xff0c;越来越多的开发者希望将他们的…

VScode代码查找、替换

VScode代码查找、替换 快捷方法按CtrlF &#xff08;Mac为CommandF&#xff09; 右上角出现的框就是查找框&#xff0c;可以输入想找的内容 点击左边的小尖儿&#xff0c;输入替换的内容后 按回车是替换一个&#xff0c;按Ctrl回车&#xff08;Command回车&#xff09;是全替换…