Bean放入Spring容器,你知道几种方式?

b3f8de610e6cdffc75d49e225564813b.png

作者:三尺微命  一介书生

来源:blog.csdn.net/weixin_43741092/article/details/120176466

我们知道平时在开发中使用Spring的时候,都是将对象交由Spring去管理,那么将一个对象加入到Spring容器中,有哪些方式呢,下面我就来总结一下

1、@Configuration + @Bean

这种方式其实,在上一篇文章已经介绍过了,也是我们最常用的一种方式,@Configuration用来声明一个配置类,然后使用 @Bean 注解,用于声明一个bean,将其加入到Spring容器中。

具体代码如下:

@Configuration
public class MyConfiguration {@Beanpublic Person person() {Person person = new Person();person.setName("spring");return person;}
}

2、@Componet + @ComponentScan

这种方式也是我们用的比较多的方式,@Componet中文译为组件,放在类名上面,然后@ComponentScan放置在我们的配置类上,然后可以指定一个路径,进行扫描带有@Componet注解的bean,然后加至容器中。

具体代码如下:

@Component
public class Person {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Person{" +"name='" + name + "'" +'}';}
}@ComponentScan(basePackages = "com.springboot.initbean.*")
public class Demo1 {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Demo1.class);Person bean = applicationContext.getBean(Person.class);System.out.println(bean);}
}

结果输出:

Person{name='null'}

表示成功将Person放置在了IOC容器中。

3、@Import注解导入

前两种方式,大家用的可能比较多,也是平时开发中必须要知道的,@Import注解用的可能不是特别多了,但是也是非常重要的,在进行Spring扩展时经常会用到,它经常搭配自定义注解进行使用,然后往容器中导入一个配置文件。

关于@Import注解,我会多介绍一点,它有四种使用方式。这是@Import注解的源码,表示只能放置在类上。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {/*** 用于导入一个class文件* {@link Configuration @Configuration}, {@link ImportSelector},* {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.*/Class<?>[] value();}

3.1 @Import直接导入类

代码示例如下:

public class Person {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +'}';}
}
/**
* 直接使用@Import导入person类,然后尝试从applicationContext中取,成功拿到
**/
@Import(Person.class)
public class Demo1 {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Demo1.class);Person bean = applicationContext.getBean(Person.class);System.out.println(bean);}
}

上述代码直接使用@Import导入了一个类,然后自动的就被放置在IOC容器中了。

注意:我们的Person类上 就不需要任何的注解了,直接导入即可。

3.2 @Import + ImportSelector

其实在@Import注解的源码中,说的已经很清楚了,感兴趣的可以看下,我们实现一个ImportSelector的接口,然后实现其中的方法,进行导入。

代码如下:

@Import(MyImportSelector.class)
public class Demo1 {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Demo1.class);Person bean = applicationContext.getBean(Person.class);System.out.println(bean);}
}class MyImportSelector implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {return new String[]{"com.springboot.pojo.Person"};}
}

我自定义了一个 MyImportSelector 实现了 ImportSelector 接口,重写selectImports 方法,然后将我们要导入的类的全限定名写在里面即可,实现起来也是非常简单。

3.3 @Import + ImportBeanDefinitionRegistrar

这种方式也需要我们实现 ImportBeanDefinitionRegistrar 接口中的方法,具体代码如下:

@Import(MyImportBeanDefinitionRegistrar.class)
public class Demo1 {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Demo1.class);Person bean = applicationContext.getBean(Person.class);System.out.println(bean);}
}class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {// 构建一个beanDefinition, 关于beanDefinition我后续会介绍,可以简单理解为bean的定义.AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Person.class).getBeanDefinition();// 将beanDefinition注册到Ioc容器中.registry.registerBeanDefinition("person", beanDefinition);}
}

上述实现其实和Import的第二种方式差不多,都需要去实现接口,然后进行导入。接触到了一个新的概念,BeanDefinition,可以简单理解为bean的定义(bean的元数据),也是需要放在IOC容器中进行管理的,先有bean的元数据,applicationContext再根据bean的元数据去创建Bean。

3.4 @Import + DeferredImportSelector

这种方式也需要我们进行实现接口,其实它和@Import的第二种方式差不多,DeferredImportSelector 它是 ImportSelector 的子接口,所以实现的方法和第二种无异。只是Spring的处理方式不同,它和Spring Boot中的自动导入配置文件 延迟导入有关,非常重要。使用方式如下:

@Import(MyDeferredImportSelector.class)
public class Demo1 {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Demo1.class);Person bean = applicationContext.getBean(Person.class);System.out.println(bean);}
}
class MyDeferredImportSelector implements DeferredImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {// 也是直接将Person的全限定名放进去return new String[]{Person.class.getName()};}
}

关于@Import注解的使用方式,大概就以上三种,当然它还可以搭配@Configuration注解使用,用于导入一个配置类。

4、使用FactoryBean接口

FactoryBean接口和BeanFactory千万不要弄混了,从名字其实可以大概的区分开,FactoryBean, 后缀为bean,那么它其实就是一个bean, BeanFactory,顾名思义 bean工厂,它是IOC容器的顶级接口,这俩接口都很重要。

代码示例:

@Configuration
public class Demo1 {@Beanpublic PersonFactoryBean personFactoryBean() {return new PersonFactoryBean();}public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Demo1.class);Person bean = applicationContext.getBean(Person.class);System.out.println(bean);}
}class PersonFactoryBean implements FactoryBean<Person> {/***  直接new出来Person进行返回.*/@Overridepublic Person getObject() throws Exception {return new Person();}/***  指定返回bean的类型.*/@Overridepublic Class<?> getObjectType() {return Person.class;}
}

上述代码,我使用@Configuration + @Bean的方式将 PersonFactoryBean 加入到容器中,注意,我没有向容器中注入 Person, 而是直接注入的 PersonFactoryBean 然后从容器中拿Person这个类型的bean,成功运行。

5、使用 BeanDefinitionRegistryPostProcessor

其实这种方式也是利用到了 BeanDefinitionRegistry,在Spring容器启动的时候会执行 BeanDefinitionRegistryPostProcessor 的 postProcessBeanDefinitionRegistry 方法,大概意思就是等beanDefinition加载完毕之后,对beanDefinition进行后置处理,可以在此进行调整IOC容器中的beanDefinition,从而干扰到后面进行初始化bean。

具体代码如下:

public class Demo1 {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();MyBeanDefinitionRegistryPostProcessor beanDefinitionRegistryPostProcessor = new MyBeanDefinitionRegistryPostProcessor();applicationContext.addBeanFactoryPostProcessor(beanDefinitionRegistryPostProcessor);applicationContext.refresh();Person bean = applicationContext.getBean(Person.class);System.out.println(bean);}
}class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Person.class).getBeanDefinition();registry.registerBeanDefinition("person", beanDefinition);}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
}

上述代码中,我们手动向beanDefinitionRegistry中注册了person的BeanDefinition。最终成功将person加入到applicationContext中,上述的几种方式的具体原理,我后面会进行介绍。

小结

向spring容器中加入bean的几种方式:

  • @Configuration + @Bean

  • @ComponentScan + @Component

  • @Import 配合接口进行导入

  • 使用FactoryBean。

  • 实现BeanDefinitionRegistryPostProcessor进行后置处理。

c710339d6af1c0fe20b33a01d1054fac.gif

往期推荐

d6cf434d38df08948fe08ae08998e68d.png

SpringBoot 热部署神器快速重启的秘密!


4fde061a1b55d5e04396f165099e411a.png

实战!工作中常用到哪些设计模式


ca0b92a6aa31f0d252910502f952847d.png

聊聊索引失效的10种场景,太坑了


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

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

相关文章

KMP POJ 2752 Seek the Name, Seek the Fame

题目传送门 1 /*2 题意&#xff1a;求出一个串的前缀与后缀相同的字串的长度3 KMP&#xff1a;nex[]就有这样的性质&#xff0c;倒过来输出就行了4 */5 /************************************************6 * Author :Running_Time7 * Created Time :2015-8-1…

c语言 函数的参数传递示例_C ++中带有示例的nearint()函数

c语言 函数的参数传递示例C 附近的int()函数 (C nearbyint() function) nearbyint() function is a library function of cmath header, it is used to round the given value to an integral value based on the specified direction by fegetround() function. It accepts a …

Spring boot项目(问答网站)之Python学习基础篇

简介 当问答网站基本框架搭建完毕之后需要一些初始的数据来进行填充&#xff0c;因此选用Python爬虫的方式&#xff0c;从网上截取一些资料信息&#xff08;当然是自己做项目使用&#xff0c;非商用&#xff09;放入到项目网站上面。这篇主要是关于Python基础知识的学习笔记。…

Spring Boot Admin,贼好使!

作者 | 磊哥来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;Spring Boot Admin&#xff08;SBA&#xff09;是一个开源的社区项目&#xff0c;用于管理和监控 Spring Boot 应用程序。应…

适用于各种列表操作的Python程序

Here, we are implementing a python program for various list operations, following operations are being performed in the list, 在这里&#xff0c;我们正在为各种列表操作实现python程序&#xff0c;正在列表中执行以下操作&#xff0c; Declaring an integer list 声…

一个障碍,就是一个超越自我的契机

一个障碍&#xff0c;就是一个新的已知条件&#xff0c;只要愿意&#xff0c;任何一个障碍&#xff0c;都会成为一个超越自我的契机。 有一天&#xff0c;素有森林之王之称的狮子&#xff0c;来到了 天神面前&#xff1a;"我很感谢你赐给我如此雄壮威武的体格、如此强大无…

JAVA基础之容器基础内容

Java Collections框架 Java Collections框架中包含了大量的集合接口以及这些接口的实现类和操作它们的方法&#xff0c;具体包含了Set(集合&#xff09;、List(列表)、Map(键值对)、Queue(队列)、Stack(栈)等&#xff0c;其中List、Set、Queue、Stack都继承了Collection接口。…

更快的Maven构建工具mvnd和Gradle哪个性能更好?

作者 | 磊哥来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;Maven 作为经典的项目构建工具相信很多人已经用很久了&#xff0c;但如果体验过 Gradle&#xff0c;那感觉只有两个字“真香…

页面访问的常见错误码解析

200 OK 一切正常301 Moved Permanently 客户请求的文档在其他地方&#xff0c;新的URL在Location头中给出&#xff0c;浏览器应该自动地访问新的URL。 302 Found 类似于301&#xff0c;但新的URL应该被视为临时性的替代&#xff0c;而不是永久性的。注意&#xff0c;在HTT…

aptitude_PHP Numbers Aptitude问题与解答

aptitudeThis section contains Aptitude Questions and Answers on PHP Numbers. 本节包含有关PHP数字的能力问题。 1) PHP supports automatic type conversion? YesNo Answer & Explanation Correct answer: 1Yes Yes, PHP supports automatic type conversion. 1)PHP…

SpringBoot + ShardingSphere 秒级分库分表!

Spring Boot 作为主流微服务框架&#xff0c;拥有成熟的社区生态。市场应用广泛&#xff0c;为了方便大家&#xff0c;整理了一个基于spring boot的常用中间件快速集成入门系列手册&#xff0c;涉及RPC、缓存、消息队列、分库分表、注册中心、分布式配置等常用开源组件&#xf…

JAVA基础之自定义容器实现

容器 容器主要是指Collection所包含的实现类&#xff0c;常用的有List、Map以及Set三种结构。本文主要介绍了几种常见的集合实现类&#xff0c;对它们进行自定义实现。 ArrayList&#xff1a;有序的容器列表&#xff0c;顺序存储着元素&#xff0c;可以使用下标进行索引&…

git reset, git checkout, git revert 区别 (译)

博客原文地址: http://blog.mexiqq.com/index.php/archives/3/题记&#xff1a;团队中大多数成员使用 sourceTree 和 github 两款 git 工具&#xff0c;然而大家对于图形化工具提供的 reset,checkout,revert 功能点并不是很了解&#xff0c;甚至于混淆,然后凭借猜测去使用。功夫…

Redis笔记之基本数据结构 动态字符串SDS

简单动态字符串 传统上的C语言的字符串表示是以空字符结尾的字符数组&#xff08;C字符串&#xff09;&#xff0c;redis自己实现一个动态字符串&#xff08;SDS&#xff09;&#xff0c;两者之间的区别以及使用SDS的好处有&#xff1a; 结构不同。C字符串以空字符结尾的字符…

weakhashmap_Java WeakHashMap size()方法与示例

weakhashmapWeakHashMap类的size()方法 (WeakHashMap Class size() method) size() method is available in java.util package. size()方法在java.util包中可用。 size() method is used to get the number of key-value pairs that exist in this map. size()方法用于获取此映…

扯一把 Spring 的三种注入方式,到底哪种注入方式最佳?

1. 实例的注入方式首先来看看 Spring 中的实例该如何注入&#xff0c;总结起来&#xff0c;无非三种&#xff1a;属性注入set 方法注入构造方法注入我们分别来看下。1.1 属性注入属性注入是大家最为常见也是使用最多的一种注入方式了&#xff0c;代码如下&#xff1a;Service p…

在项目中引入领域驱动设计的经验

Chris Patuzzo近期在一次演讲中介绍了领域驱动设计&#xff08;DDD&#xff09;的原则&#xff0c;并结合一个基于Ruby on Rails的真实项目进行讲解。在这次项目之前&#xff0c;Chris所在的团队为重新设计公司的主营网站所做的两个概念验证都因为可伸缩性方面的问题而失败了。…

Redis笔记之基本数据结构 链表

链表 链表具有空间存储不连续&#xff0c;增删节点快的优点&#xff0c;因此redis在列表键、发布与订阅、慢查询、监视器等使用了链表作为底层实现。由于C语言中没有内置的链表实现&#xff0c;因此redis自己进行了实现。 双向链表。每个listtNode都有perv和next指针&#x…

treeset java_Java TreeSet iterator()方法与示例

treeset javaTreeSet类的iterator()方法 (TreeSet Class iterator() method) iterator() method is available in java.util package. iterator()方法在java.util包中可用。 iterator() method is used to iterate the elements of this TreeSet is ascending or increasing or…

SpringCloud组件:Ribbon负载均衡策略及执行原理!

大家好&#xff0c;我是磊哥。今天我们来看下微服务中非常重要的一个组件&#xff1a;Ribbon。它作为负载均衡器在分布式网络中扮演着非常重要的角色。本篇主要内容如下&#xff1a;在介绍 Ribbon 之前&#xff0c;不得不说下负载均衡这个比较偏僻的名词。为什么说它偏僻了&…