文章目录
- 写在前面
- 一、初识BeanDefinition
- 二、Bean深入
- 1、Bean注册到IOC容器
- 2、Bean命名
- 3、Bean实例化
- 通过构造器、GETSET(配置元信息:XML、Java 注解和 Java API )
- 通过静态工厂方法(配置元信息:XML 和 Java API )
- 通过 Bean 工厂方法(配置元信息:XML和 Java API )
- 通过 FactoryBean(配置元信息:XML、Java 注解和 Java API )
- 通过 ServiceLoaderFactoryBean(配置元信息:XML、Java 注解和 Java API )
- 通过 AutowireCapableBeanFactory#createBean(java.lang.Class, int, boolean)
- 通过 BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition)
- 4、Bean的初始化
- 5、Bean 垃圾回收(GC)
写在前面
该文对spring初学者不友好,学习讨论spring-beans模块源码的大佬们请批评指正。
一、初识BeanDefinition
1、什么是BeanDefinition?
BeanDefinition 是 Spring Framework 中定义 Bean 的配置元信息接口,包含:
- Bean 的类名
- Bean 行为配置元素,如作用域、自动绑定的模式,生命周期回调等
- 其他 Bean 引用,又可称作合作者(collaborators)或者依赖(dependencies)
- 配置设置,比如 Bean 属性(Properties)
2、BeanDefinition元信息
属性(Property) | 说明 |
---|---|
Class Bean | 全类名,必须是具体类,不能用抽象类或接口 |
Name | Bean 的名称或者 ID |
Scope | Bean 的作用域(如:singleton、prototype 等) |
Constructor arguments | Bean 构造器参数(用于依赖注入) |
Properties | Bean 属性设置(用于依赖注入) |
Role | 角色提示(用户bean、外部配置、后台创建) |
primary | 是否是首要Bean |
Autowiring mode | Bean 自动绑定模式(如:通过名称 byName) |
Lazy initialization mode | Bean 延迟初始化模式(延迟和非延迟) |
Initialization method | Bean 初始化回调方法名称 |
Destruction method | Bean 销毁回调方法名称 |
3、手动构建BeanDefinition
// 1.通过 BeanDefinitionBuilder 构建
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
// 通过属性设置
beanDefinitionBuilder
.addPropertyValue("id", 1)
.addPropertyValue("name", "张三");
beanDefinitionBuilder.addConstructorArgValue("1"); // 设置构造方法参数
beanDefinitionBuilder.addConstructorArgValue("2"); // 设置构造方法第二个参数
beanDefinitionBuilder.addConstructorArgReference("order"); // 设置构造方法bean引用参数
// 获取 BeanDefinition 实例
BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
beanDefinition.getConstructorArgumentValues().addArgumentValues(new RuntimeBeanNameReference("order")); // 设置构造方法参数
// 2. 通过 AbstractBeanDefinition 以及派生类
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
// 设置 Bean 类型
genericBeanDefinition.setBeanClass(User.class);
// 通过 MutablePropertyValues 批量操作属性
MutablePropertyValues propertyValues = new MutablePropertyValues();
// propertyValues.addPropertyValue("id", 1);
// propertyValues.addPropertyValue("name", "张三");
propertyValues
.add("id", 1)
.add("name", "张三");
// 通过 set MutablePropertyValues 批量操作属性
genericBeanDefinition.setPropertyValues(propertyValues);
二、Bean深入
1、Bean注册到IOC容器
XML配置元信息
<bean name=”...” ... />
Java注解配置元信息
// @Bean
@Bean(name = {"user", "ts-user"})
public User user() {
User user = new User();
user.setId(1L);
user.setName("张三");
return user;
}
// @Component(及其派生注解比如(@Service、@Controller、@Repository))
@Component // 定义当前类作为 Spring Bean(组件)
public static class Config {
// @Import
// 通过 @Import 来进行导入
@Import(Config.class)
@Component
public class AnnotationBeanDefinitionDemo {
Java API配置元信息
1、配置类方式:AnnotatedBeanDefinitionReader#register(Class…)
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 Configuration Class(配置类)
applicationContext.register(AnnotationBeanDefinitionDemo.class);
// 启动 Spring 应用上下文
applicationContext.refresh();
2、使用BeanDefinitionRegistry 注册
// BeanDefinitionRegistry 就是用来注册bean的
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 注册方法(参考下面Bean命名-自动命名)
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinitionBuilder.getBeanDefinition(), registry);
}
}
public static void registerUserBeanDefinition(BeanDefinitionRegistry registry) {
registerUserBeanDefinition(registry, null);
}
BeanDefinitionReader
在Spring源码中所提供的BeanDefinition读取器(BeanDefinitionReader),这些BeanDefinitionReader在我们使用Spring时用得少,但在Spring源码中用得多,相当于Spring源码的基础设施。
AnnotatedBeanDefinitionReader
可以直接把某个类转换为BeanDefinition,并且会解析该类上的注解,比如
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(context);
// 将User.class解析为BeanDefinition
annotatedBeanDefinitionReader.register(User.class);
System.out.println(context.getBean("user"));
注意:它能解析的注解是:@Conditional,@Scope、@Lazy、@Primary、@DependsOn、@Role、@Description
XmlBeanDefinitionReader
可以解析<bean/>
标签
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(context);
int i = xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");
System.out.println(context.getBean("user"));
ClassPathBeanDefinitionScanner
ClassPathBeanDefinitionScanner是扫描器,但是它的作用和BeanDefinitionReader类似,它可以进行扫描,扫描某个包路径,对扫描到的类进行解析,比如,扫描到的类上如果存在@Component注解,那么就会把这个类解析为一个BeanDefinition,比如:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.scan("com.test");
System.out.println(context.getBean("userService"));
2、Bean命名
每个 Bean 拥有一个或多个标识符(identifiers),这些标识符在 Bean 所在的容器必须是唯一的。通常,一个 Bean 仅有一个标识符,如果需要额外的,可考虑使用别名(Alias)来扩充。
Bean 的 id 或 name 属性并非必须制定,如果留空的话,容器会为 Bean 自动生成一个唯一的名称。Bean 的命名尽管没有限制,不过官方建议采用驼峰的方式,更符合 Java 的命名约定。
自定义命名
在xml中我们可以使用id属性自定义命名:
每个bean的id(身份证号)都不同,但可以有相同的name (人名)。 但配置文件中允许出现两个name相同的<bean>,在用getBean()返回实例时,后面一个Bean被返回,应该是前面那 个<bean>被后面同名的<bean>覆盖了。有鉴于此,为了避免不经意的同名覆盖的现象,尽量用id属性而不要用name属性。
<bean id="user" class="com.cxf.demo.User">
<property name="id" value="1"/>
<property name="name" value="张三"/>
</bean>
使用注解时,我们可以使用value指定Bean的id:
@Bean("myId")
public User user() {
User user = new User();
user.setId(1L);
user.setName("张三");
return user;
}
// 使用@Component、@Configuration、以及@Component的派生注解比如(@Service、@Controller、@Repository)都可以直接指定其value值来设置bean的id
自动命名
创建Bean的时候,其id或name属性并非必须,如果留空的话,容器会为Bean自动生成一个唯一的名称。
这个Bean的名称生成器接口就是BeanNameGenerator接口,它只有一个方法。
public interface BeanNameGenerator {
/**
* Generate a bean name for the given bean definition.
* @param definition the bean definition to generate a name for
* @param registry the bean definition registry that the given definition
* is supposed to be registered with
* @return the generated bean name
*/
String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry);
}
BeanNameGenerator接口有两个实现类,第一个是DefaultBeanNameGenerator,默认通用 BeanNameGenerator 实现,它使用以下方式生成一个Bean的名称。
BeanDefinitionReaderUtils.generateBeanName(definition, registry);
/*
generatedBeanName
如果全路径类名为空
-父Bean名字存在,假设为Parent,generatedBeanName = "Parent$child"
-工厂类Bean存在,假设为FactoryBean,generatedBeanName = "FactoryBean$created"
接着,
-为内嵌Bean,id = generatedBeanName#随机数
-非内嵌Bean,id = generatedBeanName#递增数
*/
// org.springframework.beans.factory.support.BeanDefinitionReaderUtils#generateBeanName(org.springframework.beans.factory.config.BeanDefinition, org.springframework.beans.factory.support.BeanDefinitionRegistry, boolean)
// isInnerBean : 给定的bean定义是注册为内部bean还是顶级bean(允许为内部bean和顶级bean生成特殊的名称)
public static String generateBeanName(
BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean)
throws BeanDefinitionStoreException {
String generatedBeanName = definition.getBeanClassName();
if (generatedBeanName == null) {
if (definition.getParentName() != null) {
generatedBeanName = definition.getParentName() + "$child";
}
else if (definition.getFactoryBeanName() != null) {
generatedBeanName = definition.getFactoryBeanName() + "$created";
}
}
if (!StringUtils.hasText(generatedBeanName)) {
throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither " +
"'class' nor 'parent' nor 'factory-bean' - can't generate bean name");
}
if (isInnerBean) {
// Inner bean: generate identity hashcode suffix.
return generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition);
}
// Top-level bean: use plain class name with unique suffix if necessary.
return uniqueBeanName(generatedBeanName, registry);
}
// org.springframework.beans.factory.support.BeanDefinitionReaderUtils#uniqueBeanName
public static String uniqueBeanName(String beanName, BeanDefinitionRegistry registry) {
String id = beanName;
int counter = -1;
// Increase counter until the id is unique.
String prefix = beanName + GENERATED_BEAN_NAME_SEPARATOR;
while (counter == -1 || registry.containsBeanDefinition(id)) {
counter++;
id = prefix + counter;
}
return id;
}
BeanNameGenerator接口第二个实现类是AnnotationBeanNameGenerator,基于注解扫描的 BeanNameGenerator 实现,起始于Spring Framework 2.5。
/*
判断是为注解-@Component等,且指定value值,直接返回value值
相反,根据spring规则生成,
-如果发现类的前两个字符都是大写,则直接返回类名; MYService
-将类名的第一个字母转成小写,然后返回 MyService -> myService
*/
// org.springframework.context.annotation.AnnotationBeanNameGenerator#generateBeanName
@Override
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
if (definition instanceof AnnotatedBeanDefinition) {
String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
if (StringUtils.hasText(beanName)) {
// Explicit bean name found.
return beanName;
}
}
// Fallback: generate a unique default bean name.
return buildDefaultBeanName(definition, registry);
}
// org.springframework.context.annotation.AnnotationBeanNameGenerator#determineBeanNameFromAnnotation
@Nullable
protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
AnnotationMetadata amd = annotatedDef.getMetadata();
Set<String> types = amd.getAnnotationTypes();
String beanName = null;
for (String type : types) {
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);
if (attributes != null) {
Set<String> metaTypes = this.metaAnnotationTypesCache.computeIfAbsent(type, key -> {
Set<String> result = amd.getMetaAnnotationTypes(key);
return (result.isEmpty() ? Collections.emptySet() : result);
});
if (isStereotypeWithNameValue(type, metaTypes, attributes)) {
Object value = attributes.get("value");
if (value instanceof String) {
String strVal = (String) value;
if (StringUtils.hasLength(strVal)) {
if (beanName != null && !strVal.equals(beanName)) {
throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
"component names: '" + beanName + "' versus '" + strVal + "'");
}
beanName = strVal;
}
}
}
}
}
return beanName;
}
别名
bean的别名通常用于场景化的情况。
1、使用xml方式为指定bean创建别名
<!-- 将 Spring 容器中 "user" Bean 关联/建立别名 - "new-user" -->
<alias name="user" alias="new-user" />
<!-- 创建bean时直接起别名 -->
<bean id="app:dataSource" class="...">
<alias name="app:dataSoure" alias="user:dataSoure"/>
<alias name="app:dataSoure" alias="device:dataSoure"/>
</bean>
2、使用代码方式:
@Component
public class AliasConfiguration implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 为bean指定别名
beanFactory.registerAlias("originalBeanName", "newAlias");
beanFactory.registerAlias("originalBeanName", "newAlias2");
beanFactory.registerAlias("otherOriginalBeanName", "newAlias3");
}
}
指定别名后,与id一样用。
3、使用注解方式指定多个名称
@Bean(name = {"user", "my-user"})
public User user() {
User user = new User();
user.setId(1L);
user.setName("张三");
return user;
}
3、Bean实例化
通过构造器、GETSET(配置元信息:XML、Java 注解和 Java API )
<bean id="user" class="com.demo.domain.User">
<property name="id" value="1"/>
<property name="name" value="张三"/>
<property name="city" value="qingdao"/>
</bean>
通过静态工厂方法(配置元信息:XML 和 Java API )
<!-- 静态方法实例化 Bean -->
<bean id="user-by-static-method" class="com.demo.domain.User"
factory-method="createUser"/>
public class User {
private Long id;
private String name;
public static User createUser() {
User user = new User();
user.setId(1L);
user.setName("张三");
return user;
}
通过 Bean 工厂方法(配置元信息:XML和 Java API )
<!-- 实例(Bean)方法实例化 Bean -->
<bean id="user-by-instance-method" factory-bean="userFactory" factory-method="createUser"/>
<bean id="userFactory" class="com.demo.factory.DefaultUserFactory"/>
public class DefaultUserFactory implements UserFactory {
}
public interface UserFactory {
default User createUser() {
return User.createUser();
}
}
通过 FactoryBean(配置元信息:XML、Java 注解和 Java API )
<!-- FactoryBean实例化 Bean -->
<bean id="user-by-factory-bean" class="com.demo.factory.UserFactoryBean" />
import org.springframework.beans.factory.FactoryBean;
public class UserFactoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
return User.createUser();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
通过 ServiceLoaderFactoryBean(配置元信息:XML、Java 注解和 Java API )
1、在META-INF/services/目录下创建接口的全限定名文件
文件名:com.demo.factory.UserFactory
文件内容为文件名指定接口的实现类(多个实现类可以依次换行写):
com.demo.factory.DefaultUserFactory
com.demo.factory.DefaultUserFactory2
2、写代码使用ServiceLoader加载bean
public static void demoServiceLoader() {
ServiceLoader<UserFactory> serviceLoader = ServiceLoader.load(UserFactory.class, Thread.currentThread().getContextClassLoader());
displayServiceLoader(serviceLoader);
}
private static void displayServiceLoader(ServiceLoader<UserFactory> serviceLoader) {
Iterator<UserFactory> iterator = serviceLoader.iterator();
while (iterator.hasNext()) {
UserFactory userFactory = iterator.next();
System.out.println(userFactory.createUser());
}
}
3、(进阶)使用spring容器注册可以使用UserFactory的ServiceLoaderFactoryBean
<bean id="userFactoryServiceLoader" class="org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean">
<property name="serviceType" value="com.demo.UserFactory" />
</bean>
public static void main(String[] args) {
// 配置 XML 配置文件
// 启动 Spring 应用上下文
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/special-bean-instantiation-context.xml");
ServiceLoader<UserFactory> serviceLoader = beanFactory.getBean("userFactoryServiceLoader", ServiceLoader.class);
displayServiceLoader(serviceLoader);
// demoServiceLoader();
}
4、ServiceLoader基本原理
// ServiceLoaderFactoryBean的父类AbstractFactoryBean的getObject方法
@Override
public final T getObject() throws Exception {
if (isSingleton()) {
return (this.initialized ? this.singletonInstance : getEarlySingletonInstance());
}
else {
return createInstance();
}
}
// org.springframework.beans.factory.serviceloader.AbstractServiceLoaderBasedFactoryBean
// 此处就使用ServiceLoader来加载bean
@Override
protected Object createInstance() {
Assert.notNull(getServiceType(), "Property 'serviceType' is required");
return getObjectToExpose(ServiceLoader.load(getServiceType(), this.beanClassLoader));
}
protected abstract Object getObjectToExpose(ServiceLoader<?> serviceLoader);
通过 AutowireCapableBeanFactory#createBean(java.lang.Class, int, boolean)
// 配置 XML 配置文件
// 启动 Spring 应用上下文
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/special-bean-instantiation-context.xml");
// 通过 ApplicationContext 获取 AutowireCapableBeanFactory
AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();
// 创建 UserFactory 对象,通过 AutowireCapableBeanFactory
UserFactory userFactory = beanFactory.createBean(DefaultUserFactory.class);
System.out.println(userFactory.createUser());
通过 BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition)
在上面1、Bean注册到IOC容器中-Java API配置元信息中介绍过。
// BeanDefinitionRegistry 就是用来注册bean的
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 注册方法(参考下面Bean命名-自动命名)
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinitionBuilder.getBeanDefinition(), registry);
}
}
public static void registerUserBeanDefinition(BeanDefinitionRegistry registry) {
registerUserBeanDefinition(registry, null);
}
4、Bean的初始化
初始化bean的方法的几种方式
public class DefaultUserFactory implements UserFactory, InitializingBean {
// 1. 基于 @PostConstruct 注解(子类会集成父类的 @PostConstruct,父类有的话初始化子类 父类也会执行一次)
@PostConstruct
public void init() {
System.out.println("@PostConstruct : UserFactory 初始化中...");
}
// 2.@Bean(initMethod = "initUserFactory") 或者用xml:<bean init-method=”initUserFactory” ... /> 或者用Java API方式
public void initUserFactory() {
System.out.println("自定义初始化方法 initUserFactory() : UserFactory 初始化中...");
}
// 3.实现InitializingBean 接口,重写afterPropertiesSet方法
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean#afterPropertiesSet() : UserFactory 初始化中...");
}
}
@Bean(initMethod = "initUserFactory")
public UserFactory userFactory() {
return new DefaultUserFactory();
}
// 经过测试我们发现,打印顺序为:
// @PostConstruct : UserFactory 初始化中...
// InitializingBean#afterPropertiesSet() : UserFactory 初始化中...
// 自定义初始化方法 initUserFactory() : UserFactory 初始化中...
Java API方式设置自定义初始化方法,就是使用AbstractBeanDefinition#setInitMethodName(String)
// 通过 AbstractBeanDefinition 以及派生类
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
// 设置 Bean 类型
genericBeanDefinition.setBeanClass(User.class);
// 设置初始化方法
genericBeanDefinition.setInitMethodName("initUserFactory");
// 其实,@Bean(initMethod = "initUserFactory") 或者用xml:<bean init-method=”initUserFactory” ... /> 或者用Java API方式 自定义初始化方法,都最终会落地于AbstractBeanDefinition 的initMethodName 属性中
Bean的延迟初始化
关于Bean的懒加载更多详情请点击:
Springboot之Bean懒加载的实现详解
Bean的销毁
Bean的销毁方法与Bean的初始化方法如出一辙。
public class DefaultUserFactory implements UserFactory, DisposableBean {
// 1.标注@PreDestroy的方法
@PreDestroy
public void preDestroy() {
System.out.println("@PreDestroy : UserFactory 销毁中...");
}
// 2.实现DisposableBean 接口,重写destroy方法
@Override
public void destroy() throws Exception {
System.out.println("DisposableBean#destroy() : UserFactory 销毁中...");
}
// 3.@Bean(destroy = "initUserFactory") 或者用xml:<bean destroy-method=”initUserFactory” ... /> 或者用Java API方式
public void doDestroy() {
System.out.println("自定义销毁方法 doDestroy() : UserFactory 销毁中...");
}
}
// 执行顺序:
// @PreDestroy : UserFactory 销毁中...
// DisposableBean#destroy() : UserFactory 销毁中...
// 自定义销毁方法 doDestroy() : UserFactory 销毁中...
applicationContext.close(); 调用之后,也就是Spring应用上下文关闭时会调用Bean的销毁方法。
Bean的销毁源码分析
1、实现DisposableBean 接口,重写destroy方法
ApplicationContext.close()
——> org.springframework.context.support.AbstractApplicationContext#doClose
——> org.springframework.context.support.AbstractApplicationContext#destroyBeans
——> org.springframework.beans.factory.support.DefaultListableBeanFactory#destroySingletons
——> org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#destroySingletons
——> org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#destroySingleton
——> org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#destroyBean
protected void destroyBean(String beanName, @Nullable DisposableBean bean) {
// Trigger destruction of dependent beans first...
Set<String> dependencies;
synchronized (this.dependentBeanMap) {
// Within full synchronization in order to guarantee a disconnected Set
dependencies = this.dependentBeanMap.remove(beanName);
}
if (dependencies != null) {
if (logger.isTraceEnabled()) {
logger.trace("Retrieved dependent beans for bean '" + beanName + "': " + dependencies);
}
for (String dependentBeanName : dependencies) {
destroySingleton(dependentBeanName);
}
}
// Actually destroy the bean now...
if (bean != null) {
try {
bean.destroy(); // 调用bean的destroy方法进行销毁
}
catch (Throwable ex) {
if (logger.isWarnEnabled()) {
logger.warn("Destruction of bean with name '" + beanName + "' threw an exception", ex);
}
}
}
// Trigger destruction of contained beans...
Set<String> containedBeans;
synchronized (this.containedBeanMap) {
// Within full synchronization in order to guarantee a disconnected Set
containedBeans = this.containedBeanMap.remove(beanName);
}
if (containedBeans != null) {
for (String containedBeanName : containedBeans) {
destroySingleton(containedBeanName);
}
}
// Remove destroyed bean from other beans' dependencies.
synchronized (this.dependentBeanMap) {
for (Iterator<Map.Entry<String, Set<String>>> it = this.dependentBeanMap.entrySet().iterator(); it.hasNext();) {
Map.Entry<String, Set<String>> entry = it.next();
Set<String> dependenciesToClean = entry.getValue();
dependenciesToClean.remove(beanName);
if (dependenciesToClean.isEmpty()) {
it.remove();
}
}
}
// Remove destroyed bean's prepared dependency information.
this.dependenciesForBeanMap.remove(beanName);
}
2、标注@PreDestroy的方法
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#CommonAnnotationBeanPostProcessor
——> org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#setDestroyAnnotationType 中,将destroyAnnotationType设置好
——> org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#buildLifecycleMetadata
// org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#buildLifecycleMetadata
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
return this.emptyLifecycleMetadata;
}
List<LifecycleElement> initMethods = new ArrayList<>();
List<LifecycleElement> destroyMethods = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<LifecycleElement> currInitMethods = new ArrayList<>();
final List<LifecycleElement> currDestroyMethods = new ArrayList<>();
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
LifecycleElement element = new LifecycleElement(method);
currInitMethods.add(element); // 将初始化方法添加进去
if (logger.isTraceEnabled()) {
logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
}
}
if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
currDestroyMethods.add(new LifecycleElement(method)); // 将销毁方法添加进去
if (logger.isTraceEnabled()) {
logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
}
}
});
initMethods.addAll(0, currInitMethods);
destroyMethods.addAll(currDestroyMethods);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
new LifecycleMetadata(clazz, initMethods, destroyMethods));
}
5、Bean 垃圾回收(GC)
public class DefaultUserFactory {
// 对象回收执行的方法
@Override
public void finalize() throws Throwable {
System.out.println("当前 DefaultUserFactory 对象正在被垃圾回收...");
}
}
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(BeanInitializationDemo.class);
//启动应用上下文
applicationContext.refresh();
System.out.println("Spring 应用上下文已启动");
//依赖查找
UserFactory bean = applicationContext.getBean(UserFactory.class);
System.out.println(bean.createUser());
//关闭
applicationContext.close();
//触发垃圾回收
bean=null;
System.gc();
Thread.sleep(5000);
由此可见,当IOC容器关闭的时候,bean才会被垃圾回收。
实际中IOC容器关闭也就意味着应用关闭了,bean的存活时间基本上是等于IOC容器,等于应用的。