泛型 + 反射 + 注解 + 动态代理 + 设计模式 + Factory(BeanFactory,FactoryBean)

news2024/11/19 23:25:44

1.泛型

编译器可以对泛型参数进行检测,并且通过泛型参数可以指定传入的对象类型。比如 ArrayList<Person> persons = new ArrayList<Person>() 这行代码就指明了该 ArrayList 对象只能传入 Person 对象,如果传入其他类型的对象就会报错。

原生 List 返回类型是 Object ,需要手动转换类型才能使用,使用泛型后编译器自动转换

ArrayList list = new ArrayList();
    list.add("aaa");
System.out.println((String)list.get(0));
ArrayList<String> list = new ArrayList<>();
    list.add("aaa");

https://blog.csdn.net/weixin_45395059/article/details/126006369

泛型一般有三种使用方式:泛型类、泛型接口、泛型方法

泛型类

public class Generic<T>{

    private T key;

    public Generic(T key) {
        this.key = key;
    }

    public T getKey(){
        return key;
    }
}

T 是泛型标识被称作是类型参数,用于指代任何数据类型。泛型标识是任意设置的

泛型类中的静态方法和静态变量不可以使用泛型类所声明的类型参数

  • 泛型类中的类型参数的确定是在创建泛型类对象的时候(例如 ArrayList< Integer >)。
  • 而静态变量和静态方法在类加载时已经初始化,直接使用类名调用;在泛型类的类型参数未确定时,静态成员有可能被调用,因此泛型类的类型参数是不能在静态成员中使用的。

泛型接口

public interface Generator<T> {
    public T method();
}

实现:

class GeneratorImpl<T> implements Generator<T>{
    @Override
    public T method() {
        return null;
    }
}

泛型方法

public static < E > void printArray( E[] inputArray )
   {
         for ( E element : inputArray ){
            System.out.printf( "%s ", element );
         }
         System.out.println();
    }

2.反射

通过反射你可以获取任意一个类的所有属性和方法,你还可以调用这些方法和属性。
加载类,允许以变成 的方式解剖类中的各种成分(成员变量、方法、构造器等)
(1)加载类,获取字节码:class对象
(2)获取类的构造器:constructor对象
(3)获取成员变量:Field
(4)获取类成员方法:Method

(1)获取Class对象
在这里插入图片描述
在这里插入图片描述
True,True,True
c1,c2,c3都是相同的,都是Student类的字节码

(2)获取构造器
在这里插入图片描述

获取构造器的作用:依然是初始化对象返回

(3)获取成员变量
在这里插入图片描述
作用:赋值、取值
在这里插入图片描述
(4)获取成员方法
在这里插入图片描述
触发方法,Object obj 是要传一个对象 。这里可以方法可能会使用创建对象才有的变量,所以必须要有实例对象才能执行方法
在这里插入图片描述

反射做框架

对于任意一个对象,该框架都可以把对象的字段名和对应的值,保存到文件中去。
在这里插入图片描述
用反射设计一个框架来解决

//目标:保存任务一对象的字段和数据到文件中去
public static void saveobject(Object obj){
//1.obj是任务对象,到底有多少字段要保存
	Class c = obj,getClass();
//2.从类中提取它的全部成员变量
	Fielf[] fields = c.getDeclaredFields();
//3.遍历每个成员变量
	for(Field field:fields){
		//4.拿到成员变量的名字
		String name = field.getName;
		//5.拿到成员变量在对象中的数据
		String value = field.get(obj)+"" ;
	}

}

在苍穹外卖中的实例:

Object entity = args[0];//实体对象

//准备赋值的数据
LocalDateTime now = LocalDateTime.now();//时间
Long currentId = BaseContext.getCurrentId();//用户ID

//根据当前不同的操作类型,为对应的属性通过反射来赋值
if (value == OperationType.INSERT) {
    //插入:为4个公共字段赋值
    try {//反射拿到类方法
        Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
        Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
        Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
        Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
        //通过反射赋值
        setCreateTime.invoke(entity, now);
        setUpdateTime.invoke(entity, now);
        setCreateUser.invoke(entity, currentId);
        setUpdateUser.invoke(entity, currentId);
    } catch (Exception e) {
        e.printStackTrace();
    }

这些框架中也大量使用了动态代理,而动态代理的实现也依赖反射

3.注解

Annotation 其实就是代码里的特殊标记, 这些标记可以在编译, 类加载, 运行时被读取, 并执行相应的处理。
通过使用Annotation, 程序员可以在不改变原有逻辑的情况下, 在源文件中嵌入一些补充信息
代码分析工具、开发工具和部署工具可以通过这些补充信息进行验证或者进行部署

原文链接:https://blog.csdn.net/weixin_52533007/article/details/127487847

  1. 注解本质是一个继承了Annotation 的特殊接口:
  2. @注解(...)其实就是一个实现类对象,实现了该注解以及Annotation接口
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)//之作用在源码阶段
public @interface Override {

}

public interface Override extends Annotation{

}

  1. 注解只有被解析之后才会生效,常见的解析方法有两种:
  • 编译期直接扫描:编译器在编译 Java 代码的时候扫描对应的注解并处理,比如某个方法使用@Override 注解,编译器在编译的时候就会检测当前的方法是否重写了父类对应的方法。
  • 运行期通过反射处理:像框架中自带的注解(比如 Spring 框架的 @Value、@Component)都是通过反射来进行处理的。

自定义注解

在这里插入图片描述
实例:自定义注解
Annotation.AutoFill.java

@Target(ElementType.METHOD)//指定注解只能加载方法上
@Documented
@Retention(RetentionPolicy.RUNTIME)//控制下面的注解一直保留到运行时
public @interface AutoFill {
    //通过枚举-指定当前属性OperationType就两种 Update 和 Insert
    OperationType value();
}

mapper:

 @AutoFill(OperationType.INSERT)//这里本质是在创建注解的实现类对象
 @Insert("insert into category(type, name, sort, status, create_time, update_time, create_user, update_user)" +
            " VALUES" +
            " (#{type}, #{name}, #{sort}, #{status}, #{createTime}, #{updateTime}, #{createUser}, #{updateUser})")
 void insert(Category category);

元注解

在这里插入图片描述

注解示例: 模拟junit程序

对有@MyTest注解的方法执行

public static void mai(String[] args){
	AnnotationTest4 a= new AnnotationTest4();
	//1.得到Class对象
	Class c = AnnotationTest4.class;
	//2.提取全部成员方法
	Method[] methods = c.getDeclareMethods();
	//3.遍历数组中的方法,看否存在@MyTest注解,存在则触发执行
	for(Method method:methods){
		if(method.isAnnotationPresent(MyTest.class)){
			method.invoke(a);
		}
	}
}

注解用来标记某个程序,让其他程序根据注解信息决定怎么去对待它

4.动态代理

使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。
代理模式的主要作用是扩展目标对象的功能,比如说在目标对象的某个方法执行前后你可以增加一些自定义的操作。

从 JVM 角度来说,动态代理是在运行时动态生成类字节码,并加载到 JVM 中的
说到动态代理,Spring AOP、RPC 框架应该是两个不得不提的,它们的实现都依赖了动态代理。
(1)来生成一个代理对象

  • loader :类加载器,用于加载代理对象。
  • interfaces : 被代理类实现的一些接口;
  • h : 实现了 InvocationHandler 接口的对象;
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        ......
    }

(2)要实现动态代理的话,还必须需要实现InvocationHandler 来自定义处理逻辑。 当我们的动态代理对象调用一个方法时,这个方法的调用就会被转发到实现InvocationHandler 接口类的 invoke 方法来调用。

public interface InvocationHandler {

    /**
     * 当你使用代理对象调用方法的时候实际会调用到这个方法
     */
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

invoke() 方法有下面三个参数:

  • proxy :动态生成的代理类
  • method : 与代理类对象调用的方法相对应
  • args : 当前 method方法的参数
  • 也就是说:你通过Proxy 类的 newProxyInstance()创建的代理对象在调用方法的时候,实际会调用到实现InvocationHandler 接口的类invoke()方法。 你可以在invoke() 方法中自定义处理逻辑,比如在方法执行前后做什么事情

以下代码是将上述两者结合表示:
在这里插入图片描述
创建 statProxy来代理的BigStar对象
所以3.的return method.invoke是要用调用BigStar的方法

方便进行模版设计

5.工厂

Spring框架在其设计和实现中使用了多种设计模式,这些设计模式有助于提高代码的可重用性、灵活性和可维护性。以下是一些在Spring中常用的设计模式:

  1. 工厂模式:Spring通过BeanFactory和ApplicationContext来创建对象,其中BeanFactory就是简单工厂模式的体现。工厂模式隐藏了对象实例化的复杂性,并提供一个统一的方式来获取对象。
    应用场景:
    ①当需要一个对象时,我们不需要知道该对象所对应的具体类,只要知道哪个具体工厂可以生成该对象,实例化这个具体工厂即可创建该对象。
    ②类的数目不固定,随时有新的子类增加进来,或者是还不知道将来需要实例化哪些具体类。
    ③定义一个创建对象接口,由子类决定要实例化的类是哪一个;客户端可以动态地指定工厂子类创建具体产品。
    客户只需要知道所需产品的具体工厂,而无须知道具体工厂的创建产品的过程,甚至不需要知道具体产品的类名。
//打工人
public abstract class Worker {
}
 
//志愿者
public class Volunteer extends Worker {
}
 
//大学生
class  Undergraduate extends Worker {
}
 
//工厂
public interface IFactory {
	Worker CreateWorker();
}
//志愿者工厂
public class VolunteerFactory implements IFactory {
	@Override
	public Worker CreateWorker() {
		return new Volunteer();
	}
 
}
 
//大学生工厂
class UndergraduateFactory implements IFactory {
	@Override
	public Worker CreateWorker() {
		return new Undergraduate();
	}
 
}
IFactory factory = new UndergraduateFactory();//new对象类型用接口类型
Worker student = factory.CreateWorker();
	
IFactory factory2 = new VolunteerFactory();//new对象类型用接口类型
Worker volunteer = factory2.CreateWorker();	
  1. 单例模式:在Spring中,默认情况下,bean以单例的形式存在。这意味着对于每个bean定义,Spring容器只会创建一个共享的实例。这样做可以减少系统资源的消耗,并减少垃圾回收器的压力。
  2. 代理模式:Spring的面向切面编程(AOP)功能使用到了JDK的动态代理和CGLIB字节码生成技术。这使得可以在不修改源代码的情况下,为对象添加额外的行为。
  3. 策略模式:例如,Resource接口的不同实现类针对不同的资源文件实现了不同的资源获取策略。策略模式允许在运行时选择算法或操作的具体实现。
  4. 模板方法模式:Spring中的JdbcTemplate、RestTemplate等都是模板方法模式的应用。它们提供了一个操作的框架,而具体的实现步骤则可以由子类来提供,从而实现代码复用和减少重复代码。

Spring的IOC和DI用了什么设计模式

Spring 的 IoC(控制反转)和 DI(依赖注入)使用了工厂模式、单例模式和代理模式等设计模式。具体如下:

(1)工厂模式:IoC 容器负责创建对象,当需要创建一个对象时,只需配置好相应的配置文件或注解,无需关心对象的创建过程。IoC 容器就像一个工厂,它根据配置文件或注解来生成和管理对象实例。
(2)单例模式:在 Spring 框架中,默认情况下单例模式,确保每个 Bean 的生命周期内只有一个共享的实例
(3)代理模式:AOP(面向切面编程)使用代理模式来实现。通过代理模式,可以在不修改原始类代码的情况下,为对象提供额外的功能,例如事务管理和日志记录。
综上所述,这些设计模式共同工作,使得 Spring 框架能够提供一个高度解耦、易于扩展和维护的应用程序架构。

(BeanFactory,FactoryBean)

  1. BeanFactory:是所有Spring Bean的容器根接口,给Spring 的容器定义一套规范,给IOC容器提供了一套完整的规范,负责管理Bean的生命周期、配置元数据和依赖注入。

(1)BeanFactory的主要功能包括:

  • Bean的实例化和管理:BeanFactory负责创建、初始化和管理Bean的生命周期。它会根据配置文件中定义的Bean定义来创建Bean的实例。
  • 依赖注入:BeanFactory负责解决Bean之间的依赖关系,确保每个Bean都能获取它所依赖的其他Bean。
  • 配置元数据的管理:BeanFactory会读取和管理应用程序的配置元数据,通常以XML、注解或Java配置的方式定义Bean及其属性。
  • 延迟初始化:BeanFactory支持延迟初始化,即只有在需要时才创建Bean实例。
  • AOP支持:BeanFactory支持面向切面编程(AOP),允许在Bean的生命周期中应用切面。

BeanFactory是Spring IOC容器的基础,但它通常不会直接使用,而是通过其更高级的实现来使用,如ApplicationContext
(2)BeanFactory和ApplicationContext有什么区别?
BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。

两者区别如下:

  1. 功能上的区别。BeanFactory是Spring里面最底层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。
    ApplicationContext接口作为BeanFactory的派生,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能,如继承MessageSource、支持国际化、统一的资源文件访问方式、同时加载多个配置文件等功能。

  2. 加载方式的区别。BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。

    ApplicationContext是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。 ApplicationContext启动后预载入所有的单例Bean,那么在需要的时候,不需要等待创建bean,因为它们已经创建好了。

相对于基本的BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢

  1. FactoryBean:是一个bean通常是用来创建比较复杂的bean,一般的bean 直接用xml配置即可,但如果一个bean的创建过程中涉及到很多其他的bean 和复杂的逻辑,直接用xml配置比较麻烦,这时可以考虑用FactoryBean,可以隐藏实例化复杂Bean的具体的细节.

BeanFactory 和 FactoryBean区别
(1)用途:
BeanFactory是Spring IoC容器的核心接口,负责管理Bean的生命周期和依赖注入。
FactoryBean是一个特殊的Bean,充当其他Bean的工厂,用于自定义Bean的创建过程。
(2)创建对象:
BeanFactory负责创建Bean对象
FactoryBean是一个Bean,它的实例本身是一个工厂,负责创建特殊的比较复杂的Bean的对象。
(3)自定义性:
BeanFactory通常不需要自定义实现,而是由Spring框架提供的。
FactoryBean需要自定义实现,您需要编写一个类,实现FactoryBean接口,并重写getObject方法来定义Bean的创建逻辑。
(4)懒加载:
BeanFactory默认支持懒加载,直到被请求时才初始化。
FactoryBean可以通过返回代理对象来实现懒加载,它控制何时创建实际的Bean实例对象。

总结:不是所有的Bean都是由FactoryBean创建的。大多数普通的Bean由BeanFactory(或ApplicationContext)创建,而FactoryBean通常用于创建特殊类型的Bean,或者对Bean的创建过程进行自定义控制。如果您只需要普通Bean,不需要实现FactoryBean接口。

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

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

相关文章

周周星分享7.3—基于气象大数据的自动站实况联合预测

赛题 2024中国高校计算机大赛 — 大数据挑战赛 经验分享 大家好&#xff0c;我是扫地僧团队的队长&#xff0c;以前参加这样打榜的比赛比较少&#xff0c;了解的打榜技巧不是太多&#xff0c;所以想从科研的角度给大家一点分享。 这次比赛主要从以下五个步骤进行&#xff1a…

全网最详细金融APP测试功能点-测试用例,详细整理(全)

2024软件测试面试刷题&#xff0c;这个小程序&#xff08;永久刷题&#xff09;&#xff0c;靠它快速找到工作了&#xff01;&#xff08;刷题APP的天花板&#xff09;-CSDN博客跳槽涨薪的朋友们有福了&#xff0c;今天给大家推荐一个软件测试面试的刷题小程序。https://blog.c…

660错题

不能局部求导,局部洛必达

IO多路复用学习

Linux中的I/O多路复用 相关基础概念 在学习I/O多路复用之前&#xff0c;先学习一些相关的基础概念&#xff0c;便于理解。 内核缓冲区和用户缓冲区 &#x1f62e; CPU 上会运行两种程序&#xff0c;一种是操作系统的内核程序&#xff08;也称为系统程序&#xff09;&#x…

[OC]萝卜圈Python手动游戏

小游戏示意图 游戏规则 1.wasd上下左右移动 2.玩家一次可以移动1-3随机距离&#xff0c;人机一次移动1格或斜着移 3.玩家需要躲避人机追杀 4.当出现如图所示情况时——你输了 5.墙&#xff08;概率通过&#xff0c;对人机无效&#xff09; 难度可根据代码自己调&#xff…

python - 列表 / 元组 / 字符串

一.列表 由于pyhon的变量没有数据类型&#xff0c;所以python是没有数组的&#xff08;因为数组只能存放一种类型&#xff0c;要么全部存放整型&#xff0c;要么全部存放浮点型&#xff09;&#xff0c;只有列表list&#xff0c;所以整数&#xff0c;浮点数&#xff0c;字符串…

机械设备制造企业MES系统解决方案介绍

机械设备制造行业涵盖了各类工业设备、工程机械、农业机械等多个领域&#xff0c;对生产精度、质量控制和效率提出了较高要求。为了提升生产效率、保证产品质量并满足客户需求&#xff0c;越来越多的机械设备制造企业引入了MES系统。本文将详细介绍MES系统在机械设备制造行业的…

【嵌入式DIY实例-ESP8266篇】-LCD ST7735显示网络时间

LCD ST7735显示网络时间 文章目录 LCD ST7735显示网络时间1、硬件准备2、代码实现本文将介绍如何使用 ESP8266 NodeMCU Wi-Fi 板实现互联网时钟,其中时间和日期显示在 ST7735 TFT 显示屏上。 ST7735 TFT是一款分辨率为128160像素的彩色显示屏,采用SPI协议与主控设备通信。 1…

Vue前端练习

此练习项目只涉及前端&#xff0c;主要是vue和ElementUI框架的使用。&#xff08;ElementUI官网&#xff1a;Element - The worlds most popular Vue UI framework&#xff09; 一、环境准备 安装idea 安装Node.js 一键式安装(不需要做任何配置) npm -v&#xff08;也可用nod…

封装stater时配置导入配置类提示功能

提示功能如下 使用注解导入配置属性时添加依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency>

前端初学java二(类、多态、接口、内部类、泛型)

目录 类 种类 Javabean类 测试类 工具类 类的初始化 构照函数 新建对象的内存图 static 继承 This Super 虚方法表 Override 修饰符权限 构造代码块 静态代码块 多态 前提 优点 缺点 示例 抽象方法 抽象类 接口 implements 继承 内部类 成员内部类…

windows@无密码的本地用户账户相关问题@仅用用户名免密登录远程桌面登录和控制@无密码用户访问共享文件夹以及挂载问题

文章目录 abstract此用户无法登录账户被禁用问题访问共享文件夹时带上凭据错误案例和解决 两类登录方式控制台登录与远程登录的区别为什么限制空密码账户只允许控制台登录相关安全策略如何修改该策略注意事项 启用允许被免密登录功能使用空密码进行远程桌面连接设置远程桌面链接…

巴图制自动化Profinet协议转Modbus协议模块连接PLC和电表通信

1、免编写Modbus轮询程序实现PLC与电表通信的方法 在智能化时代&#xff0c;工业自动控制中的PLC和电表之间的通信是一个常见的需求。传统上&#xff0c;为了使PLC与电表通信&#xff0c;通常需要编写Modbus查询程序来读取和控制数据。然而&#xff0c;使用 巴图制自动化Prof…

Vue项目打包上线

Nginx 是一个高性能的开源HTTP和反向代理服务器&#xff0c;也是一个IMAP/POP3/SMTP代理服务器。它在设计上旨在处理高并发的请求&#xff0c;是一个轻量级、高效能的Web服务器和反向代理服务器&#xff0c;广泛用于提供静态资源、负载均衡、反向代理等功能。 1、下载nginx 2、…

创建kobject

1、kobject介绍 kobject的全称是kernel object&#xff0c;即内核对象。每一个kobject都会对应系统/sys/下的一个目录。 2、相关结构体和api介绍 2.1 struct kobject // include/linux/kobject.h 2.2 kobject_create_and_add kobject_create_and_addkobject_createkobj…

卷积层里的填充和步幅

一、定义 1、对于卷积&#xff0c;我们另一个超参数是核的大小&#xff0c;通常使用的卷积核是33或者55&#xff0c;很少用偶数核 2、填充是为了让输出不变或者变大&#xff0c;是为了在输入不太大&#xff0c;又能使模型足够深的情况下使用 3、填充&#xff1a;在输入周围添…

Vite: 插件流水线之核心编译能力

概述 Vite 在开发阶段实现了一个按需加载的服务器&#xff0c;每一个文件请求进来都会经历一系列的编译流程&#xff0c;然后 Vite 会将编译结果响应给浏览器。在生产环境下&#xff0c;Vite 同样会执行一系列编译过程&#xff0c;将编译结果交给 Rollup 进行模块打包这一系列…

【Docker安装】OpenEuler系统下部署Docker环境

【Docker安装】OpenEuler系统下部署Docker环境 前言一、本次实践介绍1.1 本次实践规划1.2 本次实践简介二、检查本地环境2.1 检查操作系统版本2.2 检查内核版本2.3 检查yum仓库三、卸载Docker四、部署Docker环境4.1 配置yum仓库4.2 检查可用yum仓库4.3 安装Docker4.4 检查Docke…

Pointnet++改进即插即用系列:全网首发GLSA聚合和表示全局和局部空间特征|即插即用,提升特征提取模块性能

简介:1.该教程提供大量的首发改进的方式,降低上手难度,多种结构改进,助力寻找创新点!2.本篇文章对Pointnet++特征提取模块进行改进,加入GLSA,提升性能。3.专栏持续更新,紧随最新的研究内容。 目录 1.理论介绍 2.修改步骤 2.1 步骤一 2.2 步骤二 2.3 步骤三 1.理论介…

运维锅总浅析云原生DevOps工具

本文从Tekton与Kubevela、Jenkins、GitLab CI的区别与联系对常见的云原生DevOps工具进行对比分析&#xff0c;最后给出DevOps工具选型思路。希望对您有所帮助&#xff01; 一、DevOps简介 DevOps是一种结合了软件开发&#xff08;Development&#xff09;和IT运维&#xff08…