1. 定义Spring Bean
BeanDefinition用来描述Spring中的Bean对象,包含:
- Bean的类名
- Bean配置元信息:作用域、自动绑定的模式、生命周期回调
- 其他Bean引用,或依赖
- Bean属性
2. BeanDefinition 元信息
2.1 概述
属性 | 说明 |
---|---|
class | Bean 全类名,必须是具体类,不能用抽象类或接口 |
Name | Bean 的名称或ID(Bean的识别符) |
Scope | Bean 的作用域(如:singleton ,prototype 等) |
Constructor arguments | Bean 构造器参数(用于依赖注入) |
Properties | Bean 属性设置(用于依赖注入) |
Autowiring mode | Bean 自动绑定模式(如:byName,byType等等) |
Lazy initialization mode | Bean 延迟初始化模式(延迟和非延迟) |
Initialization method | Bean 初始化回调方法名称 |
Destruction method | Bean 销毁回调方法名称 |
2.2 BeanDefinition构建
有以下2种方式可以构建BeanDefinition:
- 通过
BeanDefinitionBuilder
- 通过
AbstractBeanDefinition
以及派生类
public class BeanDefinitionCreationDemo {
public static void main(String[] args) {
}
/**
* 通过 BeanDefinitionBuilder 来构建BeanDefinition
*/
private void createBeanDefinitionByBeanDefinitionBuilder() {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
// 通过属性设置
beanDefinitionBuilder.addPropertyValue("id", 1);
beanDefinitionBuilder.addPropertyValue("name", "张三");
BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
// BeanDefinition 并非 Bean 的最终态,可以自定义修改:比如 beanDefinition.setXXX()
}
/**
* 通过 AbstractBeanDefinition 来创建BeanDefinition
*/
private void createBeanDefinitionByAbstractBeanDefinition() {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
// 设置Bean类型
beanDefinition.setBeanClass(User.class);
// 通过 MutablePropertyValues 批量操作属性
MutablePropertyValues values = new MutablePropertyValues();
values.add("id", 1)
.add("name", "李四");
beanDefinition.setPropertyValues(values);
}
}
3. 命名Spring Bean
每个Bean拥有一个或多个标识符,这些标识符在Bean所在的容器中必须是唯一的。通常,一个Bean仅有一个标识符,可以使用别名来扩充。
可以使用id或者name来规定Bean的标识符,如果想引入别名,可以在name属性中使用 “,” 或 “;” 来间隔。
如果不指定id或者name属性,则可以由 DefaultBeanNameGenerator
来生成Bean的名称。
3.1 Bean的别名
Bean别名的价值:
- 复用现有的BeanDefinition
- 更具有场景化的命名方式
<?xml version="1.0" encoding="UTF-8"?>
<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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 如果只设置id,则id就是bean的标识符;如果只设置name,则name就是bean的标识符 -->
<!-- 如果既设置了id,也设置了name,则id是标识符,name是别名 -->
<!-- name可以设置多个,比如 name="a,b,c",但是不管id还是name,在容器中必须唯一 -->
<bean id="user" class="com.hermione.entity.User">
<property name="id" value="1"/>
<property name="name" value="hermione"/>
</bean>
<!-- 必须加上primary,这样在获取单个Bean的时候不会报错(因为容器中有两个User类型的Bean) -->
<bean id="superUser" class="com.hermione.entity.SuperUser" parent="user" primary="true">
<property name="address" value="上海"/>
</bean>
<!-- 给Spring 容器中的 user Bean 建立一个别名 common-user -->
<alias name="user" alias="common-user"/>
</beans>
public class BeanAliasDemo {
public static void main(String[] args) {
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-definition-context.xml");
User user1 = beanFactory.getBean("common-user", User.class);
User user2 = beanFactory.getBean("user", User.class);
System.out.println("common-user " + (user1 == user2 ? "==" : "!=") + " user"); // common-user == user
}
}
4. 注册Spring Bean
BeanDefinition
的注册:
-
XML配置元信息:
<bean name="xx" .. />
-
Java注解配置元信息
@Bean
@Component
@Import
-
Java API配置元信息
-
命名方式:
BeanDefinitionRegistry#registerBeanDefinition(String , BeanDefinition)
-
非命名方式:
BeanDefinitionReaderUtils#registerWithGeneratedName(AbstractBeanDefinition, BeanDefinitionRegistry)
本质上也是调用了
BeanDefinitionRegistry#registerBeanDefinition(String , BeanDefinition)
-
配置类方式:
AnnotatedBeanDefinitionReader#register(Class)
-
@Import(AnnotationBeanDefinitionDemo.Config.class) // 把 Config 注册为Spring Bean
public class AnnotationBeanDefinitionDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(AnnotationBeanDefinitionDemo.class); // 把 AnnotationBeanDefinitionDemo 注册为Spring Bean
applicationContext.refresh();
Map<String, AnnotationBeanDefinitionDemo> map1 = applicationContext.getBeansOfType(AnnotationBeanDefinitionDemo.class);
System.out.println(map1); // {annotationBeanDefinitionDemo=com.hermione.bean.register.AnnotationBeanDefinitionDemo@36b4cef0}
Map<String, Config> map2 = applicationContext.getBeansOfType(Config.class);
System.out.println(map2); // {com.hermione.bean.register.AnnotationBeanDefinitionDemo$Config=com.hermione.bean.register.AnnotationBeanDefinitionDemo$Config@fad74ee}
Map<String, User> map3 = applicationContext.getBeansOfType(User.class);
System.out.println(map3); // {user=com.hermione.entity.User@1a1d6a08}
Map<String, Student> map4 = applicationContext.getBeansOfType(Student.class);
System.out.println(map4); // {}
Map<String, Config.Teacher> map5 = applicationContext.getBeansOfType(Config.Teacher.class);
System.out.println(map5); // {}
}
public static class Config {
/**
* 1. 通过 @Bean 方式定义
*/
@Bean(name = {"user", "hermione"})
public User user() {
User user = new User();
user.setId(1);
user.setName("hermione");
return user;
}
@Component
public static class Teacher {
private String name = "teacher";
}
}
@Component
public static class Student {
private String name = "student";
}
}
5. 实例化Spring Bean
Bean实例化的方式:
-
常规方式:
-
通过构造器(配置元信息:XML、Java注解和Java API)
-
通过静态工厂方法(配置元信息:XML和Java API)
-
通过Bean工厂方法(配置元信息:XML和Java API)
-
通过FactoryBean(配置元信息:XML、Java注解和Java API)
FactoryBean
主要使用在对象初始化较复杂的场景中
-
-
特殊方式:
-
通过
ServiceLoaderFactoryBean
(配置元信息:XML、Java注解和Java API)-
ServiceLoader
是JDK1.6提供的一种IoC机制,默认会去加载classpath下的META-INF/services
目录中符合格式的文件,文件名是接口的全路径,文件内容是接口的所有实现类(用 “,” 间隔),ServiceLoader
可以获取文件中列举的接口的所有实现类 -
META-INF/services
这个路径是在ServiceLoader
类中定义的
-
-
通过
AutowireCapableBeanFactory#createBean(Class, int, boolean)
-
通过
BeanDefinitionRegistry#registerBeanDefinition(String, BeanDefinition)
-
1. 常规方式
public class BeanInstantiationDemo {
public static void main(String[] args) {
ClassPathXmlApplicationContext beanFactory = new ClassPathXmlApplicationContext(
"classpath:/META-INF/bean-instantiation-context.xml");
User user = beanFactory.getBean("user-by-static-method", User.class);
System.out.println(user);
user = beanFactory.getBean("user-by-instance-method", User.class);
System.out.println(user);
user = beanFactory.getBean("user-by-factory-bean", User.class);
System.out.println(user);
beanFactory.close();
}
}
public class UserFactoryBean implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
return User.createUser();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
public class UserFactory {
public User createUser() {
return User.createUser();
}
}
public class User {
private int id;
private String name;
public static User createUser() {
User user = new User();
user.setId(2);
user.setName("hermione");
return user;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 通过静态工厂的方式实例化Bean -->
<bean id="user-by-static-method" class="com.hermione.entity.User" factory-method="createUser" />
<!-- 实例方法实例化Bean,一般很少这样用 -->
<bean id="user-by-instance-method" factory-bean="userFactory" factory-method="createUser" />
<bean id="userFactory" class="com.hermione.bean.instantiation.DefaultUserFactory" />
<!-- FactoryBean实例化 Bean -->
<bean id="user-by-factory-bean" class="com.hermione.bean.instantiation.UserFactoryBean" />
</beans>
2. 特殊方式
public class SpecialBeanInstantiationDemo {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"classpath:META-INF/special-bean-instantiation-context.xml");
// 通过ApplicationContext 获取 AutowireCapableBeanFactory
AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();
ServiceLoader<UserFactory> serviceLoader = beanFactory.getBean("user-factory-service-loader", ServiceLoader.class);
display(serviceLoader);
// 特殊方式第二种
User user = beanFactory.createBean(User.class);
System.out.println(user); // User(id=0, name=null)
}
private static void display(ServiceLoader<UserFactory> serviceLoader) {
Iterator<UserFactory> iterator = serviceLoader.iterator();
while (iterator.hasNext()) {
UserFactory userFactory = iterator.next();
System.out.println(userFactory.createUser());
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 这个 ServiceLoaderFactoryBean 本质是一个FactoryBean,所以getBean的时候返回的就是 getObject() 中 返回的对象,也就是 ServiceLoader -->
<!-- 这里可以对比下 ServiceLoaderFactoryBean 和 ServiceFactoryBean: -->
<!--
public class ServiceFactoryBean extends AbstractServiceLoaderBasedFactoryBean implements BeanClassLoaderAware {
@Override
protected Object getObjectToExpose(ServiceLoader<?> serviceLoader) {
Iterator<?> it = serviceLoader.iterator();
if (!it.hasNext()) {
throw new IllegalStateException("ServiceLoader could not find service.. ");
}
return it.next();
}
}
public class ServiceLoaderFactoryBean extends AbstractServiceLoaderBasedFactoryBean implements BeanClassLoaderAware {
@Override
protected Object getObjectToExpose(ServiceLoader<?> serviceLoader) {
return serviceLoader;
}
}
对比这两个类发现:
ServiceLoaderFactoryBean#getObject() 返回的是 ServiceLoader 的对象,
ServiceFactoryBean#getObject() 返回 ServiceLoader 中加载的接口的实现类(只有第一个)
-->
<bean id="user-factory-service-loader" class="org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean">
<property name="serviceType" value="com.hermione.bean.instantiation.UserFactory"/>
</bean>
6. 初始化Spring Bean
Bean初始化的方式:
@PostConstruct
标注方法- 实现
InitializingBean
接口的afterPropertiesSet()
方法 - 自定义初始化方法:下面这三种方式本质是相同的,都是调用了
setInitMethodName()
方法- XML配置:
<eabn init-methodd="init" ../>
- Java注解:
@Bean(initMethod = "init")
- Java API:
AbstractBeanDefinition#setInitMethodName(String)
- XML配置:
public class BeanInitializationDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(BeanInitializationDemo.class);
applicationContext.refresh();
applicationContext.getBean(UserFactory.class);
applicationContext.close();
}
@Lazy // 延迟初始化
@Bean(initMethod = "initUserFactory")
public UserFactory userFactory() {
return new DefaultUserFactory();
}
}
public class DefaultUserFactory implements UserFactory, InitializingBean {
// 1. 基于 @PostConstruct 注解
@PostConstruct
public void init() {
System.out.println("@PostConstruct");
}
@Override
public void initUserFactory() {
System.out.println("自定义初始化方法");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet");
}
}
执行顺序是:
@PostConstruct
->InitializingBean#afterPropertiesSet()
-> 自定义初始化方法。
7. 延迟初始化Spring Bean
Bean延迟初始化的方式:
- XML配置:
<bean lazy-init = "true" .. />
- Java注解:
@Lazy(true)
非延迟加载是在Spring应用上下文启动完成(
refresh()
)后,被初始化延迟加载是按需初始化,只有在使用到这个Bean的时候才会初始化。
public abstract class AbstractApplicationContext {
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons. 在这里会初始化所有非懒加载的单体Bean
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
// ..
}
finally {
// ..
}
}
}
}
8. 销毁Spring Bean
Bean的销毁方式:
@PreDestory
注解方法- 实现
DisposableBean
接口的destroy()
方法 - 自定义销毁方法:
- XML配置:
<bean destroy = "destroy" ../>
- Java注解:
@Bean(destroy = "destroy")
- Java API:
AbstractBeanDefinition#setDestroyMethodName(String)
- XML配置:
执行顺序和初始化方法相同:
@PreDestory
->DisposableBean#destroy()
-> 自定义销毁方法