What is BeanDefinition
BeanDefinition的元信息
BeanDefinition:Spring framework
中定义Bean的配置元信息
,包含关于Bean的众多信息。
Spring通过扫描配置信息,得到BeanDefinition信息,再通过BeanDefinition创建Bean
属性 | 说明 | 对应的方法 |
---|---|---|
Class Name | Bean的全限定类名,必须是具体类,不可以使用接口或抽象类 | #setBeanClassName(@Nullable String beanClassName) |
name | Bean的名称或ID,Bean名在当前容器中唯一,如果没有显示设置,则会生成默认的Bean名 | DefaultBeanNameGenerator 和AnnotationBeanNameGenerator |
Scope | 作用域:singleton,prototype | |
Constructor Arguments | BeanDefinition#getConstructorArgumentValues 和子类的AbstractBeanDefinition#setConstructorArgumentValues(ConstructorArgumentValues constructorArgumentValues) |
构造器参数,记录顺序,不记录名称 |
Autowiring mode | 自动绑定模式:byName或byType | #setAutowireCandidate(boolean autowireCandidate |
Lazy Initialization Mode | 延迟初始化方式 | #setInitMethodName(@Nullable String initMethodName) |
Initialization Method | 初始化回调函数 | #setInitMethodName(@Nullable String initMethodName) |
Destruction Method | 销毁回调函数 | #setDestroyMethodName(@Nullable String destroyMethodName) |
DependsOn | 其他Bean引用 | #setDependsOn(@Nullable String... dependsOn) |
Property | 属性配置 | BeanDefinition#getPropertyValues() 和子类的AbstractBeanDefinition#setPropertyValues(MutablePropertyValues propertyValues) |
(为了排版,Constructor Arguments行的列描述换位撑开中间宽度…)
如何构建BeanDefinition
- 通过BeanDefinitionBuild
- 通过AbstractBeanBeanDefinition以及派生类
public static void main(String[] args) {
// 1.通过 BeanDefinitionBuilder 构建
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
beanDefinitionBuilder
.addPropertyValue("id", 18)
.addPropertyValue("name", "asteroid");
BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
// BeanDefinition 并非 Bean 终态,可以自定义修改
// 2. 通过 AbstractBeanDefinition 以及派生类
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
genericBeanDefinition.setBeanClass(User.class);
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues
.add("id", 18)
.add("name", "asteroid");
genericBeanDefinition.setPropertyValues(propertyValues);
}
name and alias
name
- Bean名在当前容器中唯一
- 如果没有显示设置,则会生成默认的Bean名
DefaultBeanNameGenerator
和AnnotationBeanNameGenerator
生成默认名
alias
- alias可以有多个
- 使同一个bean可以在不同场景中更好的调用
未完待续…
How to register
如何将Bean注册入容器中?
- XML配置:
- Java注解配置:
- @Bean:最常用的,被扫描后,自动注册进容器
- @Component:直接类上增加@Component
- @Import:启动类上增加注解@Import(ImportBean.class)
// 3. 通过 @Import 来进行导入
@Import(AnnotationRegistryBean.Config.class)
public class AnnotationRegistryBean {
public static void main(String[] args) {
// 创建 BeanFactory 容器,注册 Configuration Class(配置类)
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(AnnotationRegistryBean.class);
// 1.命名 Bean 的注册方式和非命名 Bean 的注册方法
registerUserBeanDefinition(applicationContext, "asteroid");
registerUserBeanDefinition(applicationContext);
applicationContext.refresh();
System.out.println("Config 类型的所有 Beans" + applicationContext.getBeansOfType(Config.class));
System.out.println("User 类型的所有 Beans" + applicationContext.getBeansOfType(User.class));
//打印时不会出现别名,因为Alisa只是辅助作用,而不是真正的Bean名称,Alisa在另一个地方管理
applicationContext.close();
}
public static void registerUserBeanDefinition(BeanDefinitionRegistry registry) {
registerUserBeanDefinition(registry, null);
}
public static void registerUserBeanDefinition(BeanDefinitionRegistry registry, String beanName) {
BeanDefinitionBuilder beanDefinitionBuilder = genericBeanDefinition(User.class);
beanDefinitionBuilder
.addPropertyValue("id", 18)
.addPropertyValue("name", "asteroid");
if (StringUtils.hasText(beanName)) {
// 注册 BeanDefinition
registry.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition());
} else {
// 非命名 Bean 注册方法
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinitionBuilder.getBeanDefinition(), registry);
}
}
// 2. 通过 @Component 方式定义当前类作为 Spring Bean(组件)
@Component
public static class Config {
/**
* 1. 通过 @Bean 方式定义
* 通过 Java 注解的方式,定义了一个 Bean
*/
@Bean(name = {"user"})
public User user() {
User user = new User();
user.setId(18);
user.setName("asteroid");
return user;
}
}
}
- JavaAPI配置:
方式 | 方法 |
---|---|
命名方式 | BeanDefinitionRegistry#registerBeanDefination |
非命名方式 | BeanDefinitionReaderUtils#registerWithGeneratedName |
实现略…
instantiation - 实例化
BeanDefinition已生成,依赖注入时触发实例化。
实例化的方式有哪些?
常规方式
- 通过构造器:new
- 通过静态工厂方法:比如XML中bean标签的
factory-method
属性指定静态工厂方法
。 - 通过Bean工厂方法:比如定义一个
UserFactory
类和内部的一个createUser()
非静态方法;然后在XML中定义一个bean标签并指定其属性factory-bean
和factory-method
分别为前工厂的对应类和方法名。 - 通过
FactoryBean
:定义一个UserFactoryBean
并实现FactoryBean
接口并实现其getObject()
方法和getObjectType()
方法。然后直接再XML中定义bean标签其class属性就是UserFactoryBean全限定名称即可。
<!-- 静态方法实例化 Bean -->
<bean id="by-static-method" class="org.domain.User" factory-method="createUser"/>
<!-- Bean工厂方法实例化 Bean ,1、定义工厂,2、通过bean工厂的方法实例化Bean-->
<bean id="userFactory" class="org.factory.DefaultUserFactory"/>
<bean id="by-instance-method" factory-bean="userFactory" factory-method="createUser"/>
<!-- FactoryBean实例化 Bean -->
<bean id="by-factory-bean" class="org.factory.UserFactoryBean" />
public static void main(String[] args) {
//读取配置文件,并通过依赖查找获取Bean
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/bean.xml");
User user = beanFactory.getBean("by-static-method", User.class);
User userByInstanceMethod = beanFactory.getBean("by-instance-method", User.class);
User userByFactoryBean = beanFactory.getBean("by-factory-bean", User.class);
System.out.println(user);
System.out.println(userByInstanceMethod);
System.out.println(userByFactoryBean);
System.out.println(user == userByInstanceMethod);
System.out.println(user == userByFactoryBean);
System.out.println(userByFactoryBean == userByInstanceMethod);
//从不同渠道产生的Bean,所以输出3个false
}
特殊方式
- ServiceLoadFactoryBean:在classpath的META-INF/servives下创建一个文件,名称是某接口的全限定名称,文件无后缀。文件中直接写上接口实现类的全限定名。然后使用ServiceLoader相关的api即可实现接口实现类的实例化。
- AutowireCapableFactory#createBean:注意class参数不能是接口或者抽象类,否则不能初始化
- BeanDefinitionRegistry#registBeanDefinition:
实现略…
initialization - 初始化
非延迟初始化
- @PostConstruct
- 实现InitializingBean接口,重写
#afterPropertiesSet
方法 - 自定义初始化方法
- Xml:
- Java注解:@Bean(initMethod=“doInit”)
- Java API:AbstractBeanDefinition#setInitMethodName
- Xml:
public class InitializationDemo implements InitializingBean {
@PostConstruct
public void init() {
System.out.println("@PostConstruct : InitializationDemo 初始化中...");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean#afterPropertiesSet() : InitializationDemo 初始化中...");
}
public void doInit() {
System.out.println("自定义初始化方法 doInit() : InitializationDemo 初始化中...");
}
}
执行顺序:
@PostConstruct
>InitializingBean#afterPropertiesSet
>自定义初始化方法
延迟初始化
使用方式
- XML:
- 注解:@Lazy
一点归纳
- 可以解决一定情况下的依赖冲突(有解决方法不代表可以出现依赖冲突,出现依赖冲突说明代码设计有误)
- 会在获取调用
#getBean
时才初始化,使用上与非延迟Bean无异 - spring的
#refresh
方法,会显示调用初始化Bean方法,并注明初始化非延迟加载的 - 定义BeanDefinition上没有过多不通过,区别再与依赖查找和依赖注入时的一点细微不同
destroy
在Bean销毁、应用上下文关闭ApplicationContext#close
时回调的方法,容器会调用所有单例Bean的销毁方法
- @PreDestroy
- 实现DisposableBean接口的destroy方法
- 自定义销毁方法:
- XML:
- @Bean(destro=“doDestroy”)
- AbstractBeanDefinition# setDestroyMethodName
- XML:
public class DestoryBeanDemo implements DisposableBean {
@PreDestroy
public void preDestroy() {
System.out.println("@PreDestroy : DestoryBeanDemo 销毁中...");
}
@Override
public void destroy() throws Exception {
System.out.println("DisposableBean#destroy : DestoryBeanDemo 销毁中...");
}
public void doDestroy() {
System.out.println("自定义销毁方法 doDestroy : DestoryBeanDemo 销毁中...");
}
}
执行顺序:
@PreDestroy
>DisposableBean#destroy
>自定义
未完待续…(BeanDefinition#ParentName,BeanDefinition#Role)
评论区