BeanDefinition概念
BeanDefinition是Spring框架中定义Bean的配置元信息接口, 包含:
- Bean类名
- Bean行为配置元素, 如作用域, 自动绑定的模式, 生命周期回调等
- 其他Bean引用, 又可称作合作者(Collaborators)或者依赖(Dependencies)
- 配置设置, 比如Bean属性(Properties)
BeanDefinition构建
- 通过BeanDefinitionBuilder
通过AbstractBeanDefinition以及派生类 ```java public class BeanDefinitionCreationDemo {
public static void main(String[] args) {
// 1. 通过BeanDefinitionBuilder构建
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
// 设置属性
beanDefinitionBuilder.addPropertyValue("age", 18);
beanDefinitionBuilder.addPropertyValue("name", "erha");
// 获取实例, 其中beanDefinition并非终态, 还可以自定义修改
BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
// 2. 通过AbstractBeanDefinition构建
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
genericBeanDefinition.setBeanClass(User.class);
// 设置属性
MutablePropertyValues propertyValues = new MutablePropertyValues();
// propertyValues.addPropertyValue(“age”,18); // propertyValues.addPropertyValue(“name”,”erha”);
propertyValues.add("age", 17).add("name", "sansha");
genericBeanDefinition.setPropertyValues(propertyValues);
}
}
<a name="AuFW3"></a>
## 命名SpringBean
每个Bean拥有一个或多个标识符(identifiers), 这些标识符在Bean所在的容器必须是唯一的.<br />通常, 一个Bean仅有一个标识符, 如果需要额外的, 可用别名来扩充.
- 基于xml配置时, 可用id/name属性来规定Bean的标识符. 命名官方推荐驼峰
- 如果未指定, 容器为Bean自动生成一个唯一的名称(BeanNameGenerator)
![image.png](https://cdn.nlark.com/yuque/0/2021/png/281275/1616937478707-8565ea10-fd07-4bda-aace-bda240e0012f.png#align=left&display=inline&height=147&margin=%5Bobject%20Object%5D&name=image.png&originHeight=147&originWidth=581&size=7067&status=done&style=none&width=581)
**Bean的别名**
- 复用现有的BeanDefinition
- 更具有场景化的命名方法
```xml
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<import resource="classpath:/META-INF/dependency-lookup-context.xml"/>
<!--建立别名-->
<alias name="user" alias="zhangsan-user"/>
</beans>
public class BeanAliasDemo {
public static void main(String[] args) {
// 配置XML配置文件, 启动Spring应用上下文
BeanFactory beanFactory = new ClassPathXmlApplicationContext(
"classpath:META-INF/bean-definition-context.xml");
User aliaUser = beanFactory.getBean("zhangsan-user", User.class);
User user = beanFactory.getBean("user", User.class);
System.out.println(user == aliaUser);//true
}
}
注册SpringBean
@Import(AnnotationBeanDefinitionDemo.Config.class) // 3. 通过 @Import进行导入
public class AnnotationBeanDefinitionDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 1. 通过 @Bean方式定义, 注意, 注解尽管多种方式, 但是不会重复注册, API会多次注册
applicationContext.register(Config.class);
applicationContext.refresh();
registerUserBeanDefinition(applicationContext,"erHuUser");
registerUserBeanDefinition(applicationContext);
Map<String, Config> configMap = applicationContext.getBeansOfType(Config.class);
Map<String, User> userMap = applicationContext.getBeansOfType(User.class);
System.out.println(
configMap);// {annotationBeanDefinitionDemo.Config=top.xinzhang0618.spring.bean.AnnotationBeanDefinitionDemo$Config@2c039ac6}
System.out.println(userMap);// {user=User{id=1, name='一旦'}, erHuUser=User{id=2, name='二虎'}, top.xinzhang0618.ioc.overview.domain.User#0=User{id=2, name='二虎'}}
applicationContext.close();
}
@Component //2. 通过 @Component方式
public static class Config {
// 1. 通过 @Bean方式定义
@Bean(name = {"user", "yiDanUser"})
public User user() {
User user = new User();
user.setId(1L);
user.setName("一旦");
return user;
}
}
/**
* 通过API注册Bean
*/
public static void registerUserBeanDefinition(BeanDefinitionRegistry registry, String beanName) {
BeanDefinitionBuilder beanDefinitionBuilder = genericBeanDefinition(User.class);
beanDefinitionBuilder.addPropertyValue("id", 2L).addPropertyValue("name", "二虎");
if (StringUtils.hasText(beanName)) {
// 命名Bean的注册方式
registry.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition());
} else {
// 非命名Bean的注册方式
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinitionBuilder.getBeanDefinition(), registry);
}
}
public static void registerUserBeanDefinition(BeanDefinitionRegistry registry) {
registerUserBeanDefinition(registry, null);
}
}
实例化SpringBean
- 常规方式
- 通过构造器(配置元信息: XML. Java注解和API)
- 通过静态工厂方法
- 通过Bean工厂方法
- 通过FactoryBean
以下代码通过XML配置的方式演示了三种情况
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--静态方法实例化Bean-->
<bean id="user-by-static-method" class="top.xinzhang0618.ioc.overview.domain.User"
factory-method="createUser"/>
<!--实例方法实例化Bean-->
<bean id="user-by-instance-method" factory-bean="userFactory" factory-method="createUser"/>
<!--通过FactoryBean实例化Bean-->
<bean id="user-by-factory-bean" class="top.xinzhang0618.spring.bean.factory.UserFactoryBean"/>
<bean id="userFactory" class="top.xinzhang0618.spring.bean.factory.DefaultUserFactory"/>
</beans>
public class User {
private Long id;
private String name;
...
/**
* 通过静态方法构建user
* @return
*/
public static User createUser() {
User user = new User();
user.setId(1L);
user.setName("lisi");
return user;
}
}
------------------
public interface UserFactory {
default User createUser() {
return User.createUser();
}
}
----------------------
public class DefaultUserFactory implements UserFactory {
}
-----------------------
public class UserFactoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
return User.createUser();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
public static void main(String[] args) {
BeanFactory beanFactory = new ClassPathXmlApplicationContext(
"classpath:/META-INF/bean-instantiation-context.xml");
User user = beanFactory.getBean("user-by-static-method", User.class);
User userByInstanceMethod = beanFactory.getBean("user-by-instance-method", User.class);
User userByFactoryBean = beanFactory.getBean("user-by-factory-bean", User.class);
System.out.println(user);
System.out.println(userByInstanceMethod);
System.out.println(userByFactoryBean);
System.out.println(user == userByInstanceMethod);//false
System.out.println(userByInstanceMethod == userByFactoryBean);//false
}
- 特殊方式
- 通过ServiceLoaderFactoryBean
- 通过AutowireCapableBeanFactory#createBean(java.lang.Class, int, boolean)
- 通过BeanDefinitionRegistry#registerBeanDefinition(String, BeanDefinition)
初始化SpringBean
执行顺序如下:
- @PostConstruct标注方法
- 实现InitializingBean接口的afterPropertiesSet()方法
- 自定义初始化方法
- XML配置:
- Java注解: @Bean(initMethod=”init”)
- Java API: AbstractBeanDefinition#setInitMethosName(String)
- XML配置:
示例代码如下:
@Configuration
public class BeanInitializationDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(BeanInitializationDemo.class);
applicationContext.refresh();
// 非延迟初始化 在Spring应用启动上下文完成后, 被初始化
System.out.println("Spring应用上下文已启动...");
UserFactory userFactory = applicationContext.getBean(UserFactory.class);
System.out.println(userFactory);
applicationContext.close();
}
@Bean(initMethod = "initUserFactory", destroyMethod = "doDestroy")
// @Lazy
public UserFactory userFactory() {
return new DefaultUserFactory();
}
}
public class DefaultUserFactory implements UserFactory , InitializingBean, DisposableBean {
// 1. 基于 @PostConstruct 注解实现
@PostConstruct
public void init(){
System.out.println("userFactory的@PostConstruct初始化");
}
public void initUserFactory(){
System.out.println("@Bean自定义初始化方法");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean#afterPropertiesSet初始化方法");
}
@PreDestroy
public void preDestroy(){
System.out.println("userFactory的@PreDestroy销毁方法");
}
@Override
public void destroy() throws Exception {
System.out.println("DisposableBean#destroy销毁方法");
}
public void doDestroy(){
System.out.println("@Bean自定义销毁方法");
}
}
userFactory的@PostConstruct初始化
InitializingBean#afterPropertiesSet初始化方法
@Bean自定义初始化方法
Spring应用上下文已启动...
top.xinzhang0618.spring.bean.factory.DefaultUserFactory@19dc67c2
userFactory的@PreDestroy销毁方法
DisposableBean#destroy销毁方法
@Bean自定义销毁方法
注: spring的启动初始化是单线程的
延迟初始化Bean
常用来解决循环依赖问题
- XML配置:
- java注解: @Lazy(true)
非延迟初始化: 先初始化Bean后再启动Spring上下文
延迟初始化: 先启动Spring上下文, 首次调用方法或者字段时, 才进行初始化
销毁SpringBean
执行顺序如下:
- @PreDestroy标注方法
- 实现DisposableBean接口的destory()方法
- 自定义销毁方法
- XML配置:
- Java注解: @Bean(destroy=”destroy”)
- Java API : AbstractBeanDefiniton#setDestroyMethosName(String)
- XML配置:
回收SpringBean
Bean垃圾回收(GC)
- 关闭Spring容器应用上下文
- 执行GC
- SpringBean覆盖的finalize()方法被回调