目录

一、概述

二、第一种方式: XML配置方式

三、第二种方式: 使用@Component注解 + @ComponentScan包扫描方式

四、第三种方式:@Configuration + @Bean方式

五、第四种方式:FactoryBean方式

六、第五种方式:@Import方式

七、第六种方式:@Import + ImportSelector方式

八、第七种方式:@Import + ImportBeanDefinitionRegistrar方式

九、第八种方式:BeanDefinitionRegistryPostProcessor方式

十、第九种方式:BeanFactoryPostProcessor方式


一、概述

我们知道,在使用Spring框架后,Bean统一都交给IOC容器去管理和创建,那么将一个对象加入到Spring容器中有哪些方式呢,今天我们结合具体的代码来总结一下。

二、第一种方式: XML配置方式

XML配置的方式,是Spring最早支持的方式,不过现在XML方式已经用的比较少了,基本上都是用后面的配置方式替代了。

public class Student {
}<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="student" class="com.wsh.injectbean.method_01.Student"/>
</beans>/*** 第一种方式: XML文件配置*/
public class Client {public static void main(String[] args) {ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring-config.xml");System.out.println(applicationContext.getBean("student"));}
}

三、第二种方式: 使用@Component注解 + @ComponentScan包扫描方式

为了解决bean太多时,XML文件过大,从而导致膨胀不好维护的问题。在Spring2.5中开始支持:@Component、@Repository、@Service、@Controller等注解定义bean。@Component放在类名上面,然后通过@ComponentScan指定一个路径,Spring进行扫描带有@Componet注解的bean,然后加至容器中。

注意,这种方式不单单指的是@Component注解,还包括@Controler、@Service、@Repository等派生的注解。

具体代码如下:

@Component
public class UserHandler {
}@Service
public class UserService {
}@Repository
public class UserDao {
}@Controller
public class UserController {
}@ComponentScan("com.wsh.injectbean.method_02")
@Configuration
public class AppConfig {
}/*** 第二种方式: 使用@Component注解 + @ComponentScan包扫描方式* 包括@Controler、@Service、@Repository等派生的注解。* 为了解决bean太多时,xml文件过大,从而导致膨胀不好维护的问题。在spring2.5中开始支持:@Component、@Repository、@Service、@Controller等注解定义bean。* 其实本质上@Controler、@Service、@Repository也是使用@Component注解修饰的。* <p>* 通常情况下:** @Controller:一般用在控制层* @Service:一般用在业务层* @Repository:一般用在持久层* @Component:一般用在公共组件上*/
public class Client {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);System.out.println(applicationContext.getBean("userDao"));System.out.println(applicationContext.getBean("userService"));System.out.println(applicationContext.getBean("userController"));System.out.println(applicationContext.getBean("userHandler"));}
}

四、第三种方式:@Configuration + @Bean方式

这种方式其实也是我们最常用的方式之一,@Configuration用来声明一个配置类,然后使用 @Bean 注解声明一个bean,将其加入到Spring容器中。通常情况下,如果项目中有使用到第三方类库中的工具类的话,我们都是采用这种方式注册Bean。

具体代码如下:

public class Student {
}@Configuration
public class AppConfig {@Beanpublic Student student() {return new Student();}}/*** 第三种方式:@Configuration + @Bean方式* <p>* 通常情况下,如果项目中有使用到第三方类库中的工具类的话,我们都是采用这种方式注册Bean*/
public class Client {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);System.out.println(applicationContext.getBean("student"));}
}

五、第四种方式:FactoryBean方式

FactoryBean是一个Bean,它允许我们自定义Bean的创建,主要有三个方法:

  • 1、getObject():自定义Bean如何创建;
  • 2、getObjectType():要注册的Bean的类型;
  • 3、isSingleton():是否单例;
public class User {
}@Component
public class UserFactoryBean implements FactoryBean<User> {@Overridepublic User getObject() throws Exception {return new User();}@Overridepublic Class<?> getObjectType() {return User.class;}@Overridepublic boolean isSingleton() {return true;}
}@Configuration
@ComponentScan("com.wsh.injectbean.method_04")
public class AppConfig {}/*** 第四种方式:使用FactoryBean** FactoryBean在一些框架整合上用的比较多,如Mybatis与Spring的整合中:MapperFactoryBean、SqlSessionFactoryBean等*/
public class Client {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);System.out.println(applicationContext.getBean("userFactoryBean"));System.out.println(applicationContext.getBean("&userFactoryBean"));}
}

六、第五种方式:@Import方式

public class Student {
}@Import({Student.class})
@Configuration
public class AppConfig {}/*** 第五种方式:@Import方式*/
public class Client {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {System.out.println(beanDefinitionName);}System.out.println("================");System.out.println(applicationContext.getBean("com.wsh.injectbean.method_05.Student"));System.out.println(applicationContext.getBean("student"));}
}

七、第六种方式:@Import + ImportSelector方式

首先介绍一下ImportSelector接口的好处,主要有以下两点:

  • 1、把某个功能的相关类放到一起,方面管理和维护。
  • 2、重写selectImports方法时,能够根据条件判断某些类是否需要被实例化,或者某个条件实例化这些bean,其他的条件实例化那些bean等,我们能够非常灵活的定制化bean的实例化。

这种方式我们需要实现ImportSelector接口,并重写selectImports()方法,然后将我们要导入的类的全限定名写在里面即可。

指定需要定义bean的类名,注意要包含完整路径,而非相对路径。

public class Product {
}public class User {
}public class MyImportSelector implements ImportSelector {// 指定需要定义bean的类名,注意要包含完整路径,而非相对路径@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {return new String[]{"com.wsh.injectbean.method_06.Product", "com.wsh.injectbean.method_06.User"};}}@Import({MyImportSelector.class})
@Configuration
public class AppConfig {}/*** 第六种方式:@Import + ImportSelector方式* <p>* ImportSelector接口的好处主要有以下两点:* <p>* 1.把某个功能的相关类放到一起,方面管理和维护。* 2.重写selectImports方法时,能够根据条件判断某些类是否需要被实例化,或者某个条件实例化这些bean,其他的条件实例化那些bean等,我们能够非常灵活的定制化bean的实例化。*/
public class Client {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {System.out.println(beanDefinitionName);}System.out.println("================");System.out.println(applicationContext.getBean("com.wsh.injectbean.method_06.Product"));try {System.out.println(applicationContext.getBean("product"));} catch (Exception e) {e.printStackTrace();}System.out.println("================");System.out.println(applicationContext.getBean("com.wsh.injectbean.method_06.User"));try {System.out.println(applicationContext.getBean("user"));} catch (Exception e) {e.printStackTrace();}}
}

八、第七种方式:@Import + ImportBeanDefinitionRegistrar方式

这种方式我们需要实现ImportBeanDefinitionRegistrar接口,并重写registerBeanDefinitions()方法,然后定义我们需要注册的Bean的定义信息,然后registry.registerBeanDefinition()方法注册即可。这种方式比ImportSelector更加灵活,可以自定义bean的名称、作用域等很多参数。 像我们常见的Spring Cloud中的Feign,就使用了ImportBeanDefinitionRegistrar,具体可以参考FeignClientsRegistrar类。

public class User {
}public class Product {
}public class CustomImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {// 可以自定义bean的名称、作用域等很多参数registry.registerBeanDefinition("user", new RootBeanDefinition(User.class));RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Product.class);rootBeanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);registry.registerBeanDefinition("product", rootBeanDefinition);}
}@Import({CustomImportBeanDefinitionRegistrar.class})
@Configuration
public class AppConfig {}/*** 第七种方式:@Import + ImportBeanDefinitionRegistrar方式** 可以自定义bean的名称、作用域等很多参数, 像我们常见的Spring Cloud中的Feign,就使用了ImportBeanDefinitionRegistrar* class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {*      public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {*         this.registerDefaultConfiguration(metadata, registry);*         this.registerFeignClients(metadata, registry);*     }* }*/
public class Client {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);System.out.println(applicationContext.getBean("product"));System.out.println(applicationContext.getBean("user"));}
}

九、第八种方式:BeanDefinitionRegistryPostProcessor方式

在Spring容器启动方法refresh()方法的invokeBeanFactoryPostProcessors()方法中,会执行 BeanDefinitionRegistryPostProcessor 的 postProcessBeanDefinitionRegistry()方法,它允许对beanDefinition进行后置处理,我们可以在这个方法调整IOC容器中的beanDefinition定义信息,从而干扰到后面bean初始化的过程。

具体代码如下:

public class User {
}@Component
public class CustomBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {registry.registerBeanDefinition("user", new RootBeanDefinition(User.class));}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
}@Configuration
@ComponentScan("com.wsh.injectbean.method_08")
public class AppConfig {}/*** 第八种方式:BeanDefinitionRegistryPostProcessor方式*/
public class Client {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);System.out.println(applicationContext.getBean("user"));}
}

十、第九种方式:BeanFactoryPostProcessor方式

其实BeanDefinitionRegistryPostProcessor就是继承自BeanFactoryPostProcessor,所以使用BeanFactoryPostProcessor也可以实现注册Bean的功能。它们的区别如下:

  • 1、 BeanDefinitionRegistryPostProcessor:侧重于bean的注册;
  • 2、 BeanFactoryPostProcessor:侧重于对已经注册的bean的属性进行修改,虽然也可以注册bean;
public class Product {
}@Component
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {DefaultListableBeanFactory registry = (DefaultListableBeanFactory) beanFactory;registry.registerBeanDefinition("product", new RootBeanDefinition(Product.class));}
}@Configuration
@ComponentScan("com.wsh.injectbean.method_09")
public class AppConfig {}/*** 第九种方式:BeanFactoryPostProcessor方式* <p>* 1. BeanDefinitionRegistryPostProcessor: 侧重于bean的注册;* 2. BeanFactoryPostProcessor:侧重于对已经注册的bean的属性进行修改,虽然也可以注册bean;*/
public class Client {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);System.out.println(applicationContext.getBean("product"));}
}

本篇文章主要介绍了Spring中九种注册Bean的方式,大家在实际项目中,根据具体的需求,选择合适的即可。

Spring中注册Bean的方式有哪些?相关推荐

  1. Spring中获取bean的方式

    1. 获取bean 在上图的测试类中我们是通过id来获取bean的.实际上获取bean的方式有很多种,下面我们就一一说明. 1.1 方式一:根据id获取 由于 id 属性指定了 bean 的唯一标识, ...

  2. 【小家Spring】Spring注解驱动开发---向Spring Ioc容器中注册Bean的7种方式

    每篇一句 比你有钱的人一定会比你努力,而比你努力的人终有一天会比你有钱 前言 Spring是一个非常强大的反转控制(IOC)框架,以帮助分离项目组件之间的依赖关系.因此可以说Spring容器对Bean ...

  3. Spring注解驱动开发第11讲——面试官让我说说:如何使用FactoryBean向Spring容器中注册bean?

    写在前面 经过前面的学习,我们知道可以通过多种方式向Spring容器中注册bean.可以使用@Configuration注解结合@Bean注解向Spring容器中注册bean:可以按照条件向Sprin ...

  4. Spring注解驱动开发第10讲——在@Import注解中使用ImportBeanDefinitionRegistrar向容器中注册bean

    写在前面 在前面的文章中,我们学习了如何使用@Import注解向Spring容器中导入bean,不仅可以使用@Import注解快速向容器中导入bean,也可以在@Import注解中使用ImportSe ...

  5. Spring注解驱动开发第7讲——如何按照条件向Spring容器中注册bean?这次我懂了!!

    写在前面 当bean是单实例,并且没有设置懒加载时,Spring容器启动时,就会实例化bean,并将bean注册到IOC容器中,以后每次从IOC容器中获取bean时,直接返回IOC容器中的bean,而 ...

  6. 详细讲解Spring中的@Bean注解

    点击关注公众号,实用技术文章及时了解 来源:blog.csdn.net/weixin_42140261/ article/details/104864333 随着SpringBoot的流行,我们现在更 ...

  7. Spring 中的bean 是线程安全的吗?

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 作者:myseries cnblogs.com/myser ...

  8. ImportBeanDefinitionRegistrar向容器中注册bean

    一.ImportBeanDefinitionRegistrar 我们先来看看ImportBeanDefinitionRegistrar是个什么鬼,点击进入ImportBeanDefinitionReg ...

  9. Spring中的Bean配置、属性配置、装配内容详细叙述

    文章目录 1.Bean的配置 1.1.配置方式 2.Bean的实例化 2.1.构造器实例化 2.2.静态工厂方式实例化 2.3.实例工厂方式实例化 3.Bean的作用域 3.1.作用域的种类 4.Be ...

  10. spring扩展点之二:spring中关于bean初始化、销毁等使用汇总,ApplicationContextAware将ApplicationContext注入...

    <spring扩展点之二:spring中关于bean初始化.销毁等使用汇总,ApplicationContextAware将ApplicationContext注入> <spring ...

最新文章

  1. 机器学习误差分析(Error Analysis)实战
  2. poj2186 求有向图G中所有点都能到达的点的数量
  3. Mybatis-Plus基本
  4. java 使用jasper_使用Jasper Reports以Java创建报告
  5. CSS3 FlexBox布局入门简析
  6. openglshader实现虚拟场景_虚拟演播室设计原则
  7. DotNetNuke 4/5 安装提示 msajax错误,下载AJAX 1.0即可解决
  8. php生成文章页,php结合smarty生成静态页面php文章内分页代码
  9. 请问客户端PC应该如何限制其自动获取IP地址?
  10. 淘宝爬取某人的所有购物订单
  11. sever client
  12. Atitit.部分错误 设计模式,异常处理框架atiPartErr 的总结
  13. BoundsChecker的使用
  14. 中国武打明星——杨丽菁的故事
  15. Java中的数据类型
  16. 郭霖的LitePal版本历程
  17. svn上文件符号的意思
  18. 简单三步实现给公众号添加附件
  19. 数据仓库之主题模型之IBM与TD金融模型
  20. 苹果xr如何截屏_iphone敲两下截屏如何操作 苹果手机触控截屏方法【教程步骤】...

热门文章

  1. 翻译:自动驾驶相关术语的分类和定义Taxonomy and Definitions for Terms Related to On-Road Motor Vehicle Automated
  2. 阿里云云计算 33 PolarDB的优势 产品架构
  3. 阿里云云计算 11 ECS初体验-- 动手实验
  4. 翻译:Google研究:回顾2020年并展望2021年 - Jeff Dean
  5. iOS网络请求架构图URL Loading System
  6. 正态分布下贝叶斯决策的特例(二)
  7. php_eol为什么没有换行,PHP PHP_EOL 换行符
  8. Leetcode-Implement strStr()-Python
  9. 图解Python机器学习pdf 中日双语 第1页
  10. 357.计算各个位数不同的数字个数