IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 深入浅出弄明白Spring的BeanDefinition,Spring-Beans部分源码分析 -> 正文阅读

[Java知识库]深入浅出弄明白Spring的BeanDefinition,Spring-Beans部分源码分析

写在前面

该文对spring初学者不友好,学习讨论spring-beans模块源码的大佬们请批评指正。

一、初识BeanDefinition

1、什么是BeanDefinition?

BeanDefinition 是 Spring Framework 中定义 Bean 的配置元信息接口,包含:

  • Bean 的类名
  • Bean 行为配置元素,如作用域、自动绑定的模式,生命周期回调等
  • 其他 Bean 引用,又可称作合作者(collaborators)或者依赖(dependencies)
  • 配置设置,比如 Bean 属性(Properties)

2、BeanDefinition元信息

属性(Property)说明
Class Bean全类名,必须是具体类,不能用抽象类或接口
NameBean 的名称或者 ID
ScopeBean 的作用域(如:singleton、prototype 等)
Constructor argumentsBean 构造器参数(用于依赖注入)
PropertiesBean 属性设置(用于依赖注入)
Role角色提示(用户bean、外部配置、后台创建)
primary是否是首要Bean
Autowiring modeBean 自动绑定模式(如:通过名称 byName)
Lazy initialization modeBean 延迟初始化模式(延迟和非延迟)
Initialization methodBean 初始化回调方法名称
Destruction methodBean 销毁回调方法名称

3、手动构建BeanDefinition

// 1.通过 BeanDefinitionBuilder 构建
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
// 通过属性设置
beanDefinitionBuilder
        .addPropertyValue("id", 1)
        .addPropertyValue("name", "张三");
// 获取 BeanDefinition 实例
BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
// BeanDefinition 并非 Bean 终态,可以自定义修改
beanDefinition.xxxx  // 可以修改信息
// 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);
}

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容器,等于应用的。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-12-25 10:52:39  更:2022-12-25 10:56:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年3日历 -2024/3/29 0:47:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码