Spring 是如何将BeanDefinition注册到容器,到底我们有多少种方法来操作?
本篇主要围绕这两个议题通过不同的维度来进行讨论,下面是我主要罗列了几种不同的实现方案
看过Spring 源码的朋友应该注意到这里还有一种配置方式就是关于Properties文件的一个配置方法,这里不做展开后续再做介绍
简要说明
第一种方式:我们可以看出一个特点是我们的Bean的名称是通过XML元素内属性进行定义的,还有其它包括我们前面所提到的比如:它的Class,Lazy-init 等一些属性配置
第二种方式:Bean的注解方式其实也用的比较多,尤其在Spring boot 场景里面会用的特别多@Bean。同样在Spring MVC里面我们也会用到@Controller很重的这么一个控制器,它其实就是@Component的一个派生
第三种方式:对于Java API 的配置实现这种方式可能一些觉得的比较陌生,但是阅读过Spring 或者 Spring boot 源码的想必比较熟悉,那就是@import 方式来进行导入某个Bean来实现
案例分享
由于前面XML配置过多这里就跳过忽略
/**
* 注解 BeanDefinition 示例
*
* @author <a href="shangzhi.ibyte@gmail.com">ibyte</a>
* @since
*/
// 3. 通过 @Import 来进行导入
@Import(AnnotationBeanDefinitionDemo.Config.class)
public class AnnotationBeanDefinitionDemo {
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 Configuration Class(配置类)
applicationContext.register(AnnotationBeanDefinitionDemo.class);
// 启动 Spring 应用上下文
applicationContext.refresh();
// 按照类型依赖查找
System.out.println("Config 类型的所有 Beans" + applicationContext.getBeansOfType(Config.class));
System.out.println("User 类型的所有 Beans" + applicationContext.getBeansOfType(User.class));
// 显示地关闭 Spring 应用上下文
applicationContext.close();
}
// 2. 通过 @Component 方式
@Component // 定义当前类作为 Spring Bean(组件)
public static class Config {
// 1. 通过 @Bean 方式定义
/**
* 通过 Java 注解的方式,定义了一个 Bean
*/
@Bean(name = {"user", "xiaomage-user"})
public User user() {
User user = new User();
user.setId(1L);
user.setName("小码哥");
return user;
}
}
}
执行结果
Config 类型的所有 Beans{com.ibytecoding.spring.bean.definition.AnnotationBeanDefinitionDemo$Config=com.ibytecoding.spring.bean.definition.AnnotationBeanDefinitionDemo$Config@59906517}
User 类型的所有 Beans{user=User{id=1, name='小码哥'}}
从结果中我们可以看出Spring Bean 在同一个容器中中不会被重复定义
/**
* 注解 BeanDefinition 示例
*
* @author <a href="shangzhi.ibyte@gmail.com">ibyte</a>
* @since
*/
// 3. 通过 @Import 来进行导入
@Import(AnnotationBeanDefinitionDemo.Config.class)
public class AnnotationBeanDefinitionDemo {
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 Configuration Class(配置类)
applicationContext.register(AnnotationBeanDefinitionDemo.class);
// 通过 BeanDefinition 注册 API 实现
// 1.命名 Bean 的注册方式
registerUserBeanDefinition(applicationContext, "iByteCoding-user");
// 2. 非命名 Bean 的注册方法
registerUserBeanDefinition(applicationContext);
// 启动 Spring 应用上下文
applicationContext.refresh();
// 按照类型依赖查找
// System.out.println("Config 类型的所有 Beans" + applicationContext.getBeansOfType(Config.class));
System.out.println("User 类型的所有 Beans" + applicationContext.getBeansOfType(User.class));
// 显示地关闭 Spring 应用上下文
applicationContext.close();
}
public static void registerUserBeanDefinition(BeanDefinitionRegistry registry, String beanName) {
BeanDefinitionBuilder beanDefinitionBuilder = genericBeanDefinition(User.class);
beanDefinitionBuilder
.addPropertyValue("id", 1L)
.addPropertyValue("name", "小码哥");
// 判断如果 beanName 参数存在时
if (StringUtils.hasText(beanName)) {
// 注册 BeanDefinition
registry.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition());
} else {
// 非命名 Bean 注册方法
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinitionBuilder.getBeanDefinition(), registry);
}
}
public static void registerUserBeanDefinition(BeanDefinitionRegistry registry) {
registerUserBeanDefinition(registry, null);
}
// 2. 通过 @Component 方式
@Component // 定义当前类作为 Spring Bean(组件)
public static class Config {
// 1. 通过 @Bean 方式定义
/**
* 通过 Java 注解的方式,定义了一个 Bean
*/
@Bean(name = {"user", "xiaomage-user"})
public User user() {
User user = new User();
user.setId(1L);
user.setName("小码哥");
return user;
}
}
}
执行结果
User 类型的所有 Beans{iByteCoding-user=User{id=1, name='小码哥'}, org.ibyte.thinking.in.spring.ioc.domain.User#0=User{id=1, name='小码哥'}, user=User{id=1, name='小码哥'}}
源码地址
https://gitee.com/iByteCoding/thinking-in-spring