IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 实力总结四类Bean注入Spring的方式 -> 正文阅读

[Java知识库]实力总结四类Bean注入Spring的方式

  • xml 方式

  • 注解方式

    • @Configuration + @Bean

    • @Import

  • FactoryBean

  • BDRegistryPostProcessor

    • 源码

    • 实战

一提到Spring,大家最先想到的是啥?是AOPIOC的两大特性?是SpringBean的初始化流程?还是基于SpringSpring Cloud全家桶呢?

今天我们就从SpringIOC特性入手,聊一聊Spring中把Bean注入Spring容器的几种方式。

我们先来简单了解下IOC的概念:IOC即控制反转,也称为依赖注入,是指将对象的创建或者依赖关系的引用从具体的对象控制转为框架或者IOC容器来完成,也就是依赖对象的获得被反转了。

可以简单理解为原来由我们来创建对象,现在由Spring来创建并控制对象。

xml 方式

依稀记得最早接触Spring的时候,用的还是SSH框架,不知道大家对这个还有印象吗?所有的bean的注入得依靠xml文件来完成。

它的注入方式分为:set方法注入、构造方法注入、字段注入,而注入类型分为值类型注入(8种基本数据类型)和引用类型注入(将依赖对象注入)。

以下是set方法注入的简单样例

<bean?name="teacher"?class="org.springframework.demo.model.Teacher">
????<property?name="name"?value="阿Q"></property>
</bean>

对应的实体类代码

public?class?Teacher?{

?private?String?name;

?public?void?setName(String?name)?{
??this.name?=?name;
????}
}

xml方式存在的缺点如下:

  1. xml文件配置起来比较麻烦,既要维护代码又要维护配置文件,开发效率低;

  2. 项目中配置文件过多,维护起来比较困难;

  3. 程序编译期间无法对配置项的正确性进行验证,只能在运行期发现并且出错之后不易排查;

  4. 解析xml时,无论是将xml一次性装进内存,还是一行一行解析,都会占用内存资源,影响性能。

注解方式

随着Spring的发展,Spring 2.5开始出现了一系列注解,除了我们经常使用的@Controller、@Service、@Repository、@Component 之外,还有一些比较常用的方式,接下来我们简单了解下。

@Configuration + @Bean

当我们需要引入第三方的jar包时,可以用@Bean注解来标注,同时需要搭配@Configuration来使用。

  • @Configuration用来声明一个配置类,可以理解为xml<beans>标签

  • @Bean?用来声明一个bean,将其加入到Spring容器中,可以理解为xml<bean>标签

简单样例:将 RedisTemplate 注入 Spring

@Configuration
public?class?RedisConfig?{
????@Bean
????public?RedisTemplate<String,?Object>?redisTemplate(LettuceConnectionFactory?redisConnectionFactory)?{
????????RedisTemplate<String,?Object>?redisTemplate?=?new?RedisTemplate<String,?Object>();
????????......
????????return?redisTemplate;
????}
}

@Import

我们在翻看Spring源码的过程中,经常会看到@Import注解,它也可以用来将第三方jar包注入Spring,但是它只可以作用在类上。

例如在注解EnableSpringConfigured上就包含了@Import注解,用于将SpringConfiguredConfiguration配置文件加载进Spring容器。

@Import(SpringConfiguredConfiguration.class)
public?@interface?EnableSpringConfigured?{}

@Importvalue值是一个数组,一个一个注入比较繁琐,因此我们可以搭配ImportSelector接口来使用,用法如下:

@Configuration
@Import(MyImportSelector.class)
public?class?MyConfig?{}

public?class?MyImportSelector?implements?ImportSelector?{
?@Override
????public?String[]?selectImports(AnnotationMetadata?annotationMetadata)?{
????????return?new?String[]{"org.springframework.demo.model.Teacher","org.springframework.demo.model.Student"};
????}
}

其中selectImports方法返回的数组就会通过@Import注解注入到Spring容器中。

无独有偶,ImportBeanDefinitionRegistrar接口也为我们提供了注入bean的方法。

@Import(AspectJAutoProxyRegistrar.class)
public?@interface?EnableAspectJAutoProxy?{
????......
}

我们点击AspectJAutoProxyRegistrar类,发现它实现了ImportBeanDefinitionRegistrar接口,它的registerBeanDefinitions方法便是注入bean的过程,可以参考下。

如果觉得源代码比较难懂,可以看一下我们自定义的类

@Configuration
@Import(value?=?{MyImportBeanDefinitionRegistrar.class})
public?class?MyConfig?{}

public?class?MyImportBeanDefinitionRegistrar?implements?ImportBeanDefinitionRegistrar?{
????@Override
????public?void?registerBeanDefinitions(AnnotationMetadata?importingClassMetadata,
????????????????????????????????????????BeanDefinitionRegistry?registry)?{
????????????RootBeanDefinition?tDefinition?=?new?RootBeanDefinition(Teacher.class);
????????????//?注册?Bean,并指定bean的名称和类型
????????????registry.registerBeanDefinition("teacher",?tDefinition);
????????}
????}
}

这样我们就把Teacher类注入到Spring容器中了。

FactoryBean

提到FactoryBean,就不得不与BeanFactory比较一番。

  • BeanFactory?: 是?Factory,?IOC容器或者对象工厂,所有的Bean都由它进行管理

  • FactoryBean?: 是Bean?,是一个能产生或者修饰对象生成的工厂?Bean,实现与工厂模式和修饰器模式类似

那么FactoryBean是如何实现bean注入的呢?

先定义实现了FactoryBean接口的类

public?class?TeacherFactoryBean?implements?FactoryBean<Teacher>?{

?/**
??*?返回此工厂管理的对象实例
??**/
?@Override
?public?Teacher?getObject()?throws?Exception?{
??return?new?Teacher();
?}

?/**
??*?返回此?FactoryBean?创建的对象的类型
??**/
?@Override
?public?Class<?>?getObjectType()?{
??return?Teacher.class;
?}

}

然后通过 @Configuration + @Bean的方式将TeacherFactoryBean加入到容器中

@Configuration
public?class?MyConfig?{
?@Bean
?public?TeacherFactoryBean?teacherFactoryBean(){
??return?new?TeacherFactoryBean();
?}
}

注意:我们没有向容器中注入Teacher, 而是直接注入的TeacherFactoryBean,然后从容器中拿Teacher这个类型的bean,成功运行。

BDRegistryPostProcessor

看到这个接口,不知道对于翻看过Spring源码的你来说熟不熟悉。如果不熟悉的话请往下看,要是熟悉的话就再看一遍吧😃。

源码

public?interface?BeanDefinitionRegistryPostProcessor?extends?BeanFactoryPostProcessor?{
????//?注册bean到spring容器中
?void?postProcessBeanDefinitionRegistry(BeanDefinitionRegistry?registry)?throws?BeansException;
}

@FunctionalInterface
public?interface?BeanFactoryPostProcessor?{
?void?postProcessBeanFactory(ConfigurableListableBeanFactory?beanFactory)?throws?BeansException;
}

BeanFactoryPostProcessor接口是BeanFactory的后置处理器,方法postProcessBeanFactorybean的定义进行控制。今天我们重点来看看postProcessBeanDefinitionRegistry方法:它的参数是BeanDefinitionRegistry,顾名思义就是与BeanDefinition注册相关的。

通过观察该类,我们发现它里边包含了registerBeanDefinition方法,这个不就是我们想要的吗?为了能更好的使用该接口来达到注入bean的目的,我们先来看看Spring是如何操作此接口的。

看下invokeBeanFactoryPostProcessors方法,会发现没有实现PriorityOrderedOrderedbean(这种跟我们自定义的实现类有关)会执行以下代码。

while?(reiterate)?{
????......
????invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors,?registry);
????......
}

进入该方法

private?static?void?invokeBeanDefinitionRegistryPostProcessors(
????Collection<??extends?BeanDefinitionRegistryPostProcessor>?postProcessors,?
????BeanDefinitionRegistry?registry)?{

????for?(BeanDefinitionRegistryPostProcessor?postProcessor?:?postProcessors)?{
????????postProcessor.postProcessBeanDefinitionRegistry(registry);
????}
}

会发现实现了BeanDefinitionRegistryPostProcessor接口的bean,其postProcessBeanDefinitionRegistry方法会被调用,也就是说如果我们自定义接口实现该接口,它的postProcessBeanDefinitionRegistry方法也会被执行。

实战

话不多说,直接上代码。自定义接口实现类

public?class?MyBeanDefinitionRegistryPostProcessor?implements?BeanDefinitionRegistryPostProcessor?{

?/**
??*?初始化过程中先执行
??**/
?@Override
?public?void?postProcessBeanDefinitionRegistry(BeanDefinitionRegistry?registry)?throws?BeansException?{
??RootBeanDefinition?rootBeanDefinition?=?new?RootBeanDefinition(Teacher.class);
??//Teacher?的定义注册到spring容器中
??registry.registerBeanDefinition("teacher",?rootBeanDefinition);
?}

?/**
??*?初始化过程中后执行
??**/
?@Override
?public?void?postProcessBeanFactory(ConfigurableListableBeanFactory?beanFactory)?throws?BeansException?{}
}

启动类代码

public?static?void?main(String[]?args)?{
????AnnotationConfigApplicationContext?context?=?new?AnnotationConfigApplicationContext();
????MyBeanDefinitionRegistryPostProcessor?postProcessor?=?new?MyBeanDefinitionRegistryPostProcessor();
????//将自定义实现类加入?Spring?容器
????context.addBeanFactoryPostProcessor(postProcessor);
????context.refresh();
????Teacher?bean?=?context.getBean(Teacher.class);
????System.out.println(bean);
}

启动并打印结果

org.springframework.demo.model.Teacher@2473d930

发现已经注入到Spring容器中了。

以上就是我们总结的几种将bean注入Spring容器的方式,赶快行动起来实战演练一下吧!

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-04-26 11:28:38  更:2022-04-26 11:30:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:40:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码