定义Spring Bean
对应代码中的 BeanDefinition,是 Spring Framework 中定义 Bean 的配置元信息接口,主要包含:
- Bean 的类名,全限定名称,具体实现类
- Bean 配置元信息:作用域、自动绑定(Auto Wiring)、生命周期回调……
- Bean 的引用:合作者(Collaborators)或者依赖(Dependencies),
- 配置的设置:Bean 的属性(比如连接池的大小)
BeanDefinition 元信息
概览
| 属性 | 说明 | 备注 | | —- | —- | —- | | Class | Bean 全类名,具体的类,不能是抽象类或接口 | | | Name | Bean 的名称或者 ID | | | Scope | Bean 的作用域(singleton、prototype、……) | | | Constructor arguments | Bean 构造器参数(用于依赖注入) | | | Properties | Bean 的属性设置(用于依赖注入) | | | Autowiring mode | Bean 自动绑定模式(比如:通过名称 byName……) | | | Lazy initialization mode | Bean 延迟初始化(延迟「需要时再初始化,缩短时间」、非延迟「默认」) | | | Initialization method | Bean 初始化回调方法名称 | | | Destruction method | Bean 销毁回调方法名称 | |
构建
通过 BeanDefinitionBuilder
// 1. 通过 BeanDefinitionBuilder 构建BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);// 通过属性设置(挨个添加),此处可以使用「beanDefinitionBuilder.addPropertyValue("name","Steve").addPropertyValue("id",30);」beanDefinitionBuilder.addPropertyValue("name","Steve");beanDefinitionBuilder.addPropertyValue("id",30);// 获取 BeanDefinition 实例BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();// beanDefinition 有好多 set 方法,BeanDefinition 并非 Bean 的终态,可以自定义修改
通过 AbstractBeanDefinition 以及派生类
// 2. 通过 AbstractBeanDefinition 以及派生类GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();// 设置 Bean 类型genericBeanDefinition.setBeanClass(User.class);// 通过 MutablePropertyValues 批量操作属性,此处可以使用 「propertyValues.add("name","Steve").add("id",31)」MutablePropertyValues propertyValues = new MutablePropertyValues();propertyValues.addPropertyValue("name","Steve");propertyValues.addPropertyValue("id",31);genericBeanDefinition.setPropertyValues(propertyValues);
命名Spring Bean
Bean 名称
每个 Bean 都有一个或者多个标识符,标识符要在 Bean 的所在容器唯一。通常情况下,一个 Bean 有一个标识符,如果需要额外的标识符则使用别名扩充。
基于 XML 的情况下,可以用 id 或者 name 属性规定 Bean 的标识符。如果想使用别名,在 name 属性使用「,」或者「;」分开。
Bean 的 id 或者 name 可以留空,留空后,容器会为 Bean 自动生成唯一的名称。推荐使用驼峰,符合 Java 命名规范。
Spring 中可查看BeanNameGenerator 的两个实现。
注解实现
具体看:AnnotationBeanNameGenerator
比如用到的 @component、@Repository、@Service、@Controller等,其实后三者只是简单包了一层第一个
@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Componentpublic @interface Service {/*** The value may indicate a suggestion for a logical component name,* to be turned into a Spring bean in case of an autodetected component.* @return the suggested component name, if any (or empty String otherwise)*/@AliasFor(annotation = Component.class)String value() default "";}
默认实现
具体看:DefaultBeanNameGenerator
Spring Bean 的别名
好处
- 可以复用现有的 BeanDefinitio
- 能够通过命名看出来使用场景(比如同一个 Bean 在 A 系统里叫 beanInA,在 B 系统里可以叫 beanInB)
注册 Spring Bean
基础
XML 配置元信息
Java 注解
Java API 配置元信息
- 命名方式:
BeanDefinitionRegistry#registerBeanDefinition(String beanName, BeanDefinition beanDefinition) - 非命名方式:
BeanDifinitionReaderUtils#registerWithGeneratedName(AbstractBeanDefinition definition, BeanDefinitionRegistry registry) - 配置类方式:
AnnotatedBeanDefinitionReader#register(Class<?>... componentClasses)代码
```java import static org.springframework.beans.factory.support.BeanDefinitionBuilder.genericBeanDefinition;
/**
- 注解 BeanDefinition 示例 *
- @author mindartisan.blog.csdn.net
@date */ @Import(AnnotationBeanDefinitionDemo.Config.class)// 通过 @Import 进行导入 public class AnnotationBeanDefinitionDemo { public static void main(String[] args) {
// 创建 BeanFactory 容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 注册 配置类// 方式 3:配置类方式;详细看:AnnotationConfigApplicationContext#register(Class<?>... componentClasses) -> AnnotatedBeanDefinitionReader#register(Class<?>... componentClasses)applicationContext.register(AnnotationBeanDefinitionDemo.class);registerUserBeanDefinition(applicationContext,"mindartisan-user");registerUserBeanDefinition(applicationContext);// 启动 Spring 应用上下文applicationContext.refresh();// 输出Config 类型的 Bean:{com.mindartisan.spring.geek.bean.definition.AnnotationBeanDefinitionDemo$Config=com.mindartisan.spring.geek.bean.definition.AnnotationBeanDefinitionDemo$Config@7f416310}System.out.println("Config 类型的 Bean:" + applicationContext.getBeansOfType(Config.class));// User 类型的 Bean:{user=User{id=1, name='Steve'}}System.out.println("User 类型的 Bean:" + applicationContext.getBeansOfType(User.class));// 关闭 Spring 应用上下文applicationContext.close();
}
/*** bean 的注册方式** @param beanDefinitionRegistry* @param beanName*/public static void registerUserBeanDefinition(BeanDefinitionRegistry beanDefinitionRegistry, String beanName) {BeanDefinitionBuilder beanDefinitionBuilder = genericBeanDefinition(User.class);beanDefinitionBuilder.addPropertyValue("id", 1L).addPropertyValue("name", "Steve");if (StringUtils.hasText(beanName)) {// 命名方式注册 BeanDefinitionbeanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition());} else {// 非命名方式BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinitionBuilder.getBeanDefinition(), beanDefinitionRegistry);}}public static void registerUserBeanDefinition(BeanDefinitionRegistry beanDefinitionRegistry) {registerUserBeanDefinition(beanDefinitionRegistry, null);}@Component// 通过 @Component 定义当前类作为 Spring Bean(组件)public static class Config {/*** 通过 Java 注解,定义 Bean** @return*/@Bean(name = {"user", "steve-user"})// 通过 @Bean,定义 Beanpublic User user() {User user = new User();user.setId(1L);user.setName("Steve");return user;}}
}
<a name="UmRRd"></a>## 扩展通过外部单体对象注册,主要用到的是 `SingletonBeanRegistry#registerSingleton(String beanName, Object singletonObject);` 方法<br />SingtonBeanRegistrationDemo.class:```java/*** 外部单体 Bean 注册实例* 外部 bean:不被 Spring 管理的类** @author mindartisan.blog.csdn.net* @date*/public class SingtonBeanRegistrationDemo {public static void main(String[] args) {// 创建 BeanFactory 容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 这里的 userFactory 未被 Spring 管理UserFactory userFactory = new DefaultUserFactory();ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();// 启动 Spring 应用上下文applicationContext.refresh();// 注册外部单例对象beanFactory.registerSingleton("userFactory", userFactory);// 通过依赖查找的方式获取 userFactoryUserFactory userFactoryByLookup = beanFactory.getBean("userFactory", UserFactory.class);System.out.println("userFactory == userFactoryByLookup:" + (userFactory == userFactoryByLookup));// 关闭 Spring 应用上下文applicationContext.close();}}
实例化 Spring Bean
常规
通过构造器(配置元信息:XML、Java 注解、Java API)
通过静态工厂方法(配置元信息:XML、Java API)
通过 Bean 工厂方法(配置元信息:XML、Java API)
通过 FactoryBean 方式(配置元信息:XML、Java 注解、Java API)
代码
具体方式看 xml 中注释,和 main 方法中的命名
User.class:
/*** 用户** @author mindartisan.blog.csdn.net* @date*/public class User {private Long id;private String name;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +'}';}/*** 通过静态方法实例化** @return {@link User}*/public static User createUser(){User user = new User();user.setId(1L);user.setName("Steve");return user;}}
bean-instantiation-context.xml:
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd"><!--静态方法实例化 Bean--><bean id="user-by-static-method" class="com.mindartisan.spring.geek.ioc.overview.domain.User"factory-method="createUser"/><!--实例 Bean 方法实例化 bean--><bean id="user-by-instance-method" factory-bean="userFactory" factory-method="createUser"/><bean id="userFactory" class="com.mindartisan.spring.geek.bean.factory.DefaultUserFactory"/><!--FactoryBean 实例化 bean--><bean id="user-by-factory-bean" class="com.mindartisan.spring.geek.bean.factory.UserFactoryBean"/></beans>
BeanInstantinationDemo.class:
/*** Bean 实例化 demo** @author mindartisan.blog.csdn.net* @date*/public class BeanInstantinationDemo {public static void main(String[] args) {BeanFactory beanFactory = new ClassPathXmlApplicationContext("META-INF/bean-instantiation-context.xml");User userByStaticMethod = beanFactory.getBean("user-by-static-method", User.class);// 输出「User{id=1, name='Steve'}」System.out.println(userByStaticMethod);User userByInstanceMethod = beanFactory.getBean("user-by-instance-method", User.class);// 输出「User{id=1, name='Steve'}」System.out.println(userByInstanceMethod);// 输出「false」System.out.println(userByStaticMethod == userByInstanceMethod);User userByFactoryBean = beanFactory.getBean("user-by-factory-bean", User.class);// 输出「User{id=1, name='Steve'}」System.out.println(userByFactoryBean);// 输出「false」System.out.println(userByStaticMethod == userByFactoryBean);// 输出「false」System.out.println(userByFactoryBean == userByInstanceMethod);}}
UserFactory.class:
/*** 工厂类** @author mindartisan.blog.csdn.net* @date*/public interface UserFactory {default User createUser(){return User.createUser();}}
DefaultUserFactory.class:
/*** 默认用户工厂** @author mindartisan.blog.csdn.net* @date*/public class DefaultUserFactory implements UserFactory {}
UserFactoryBean.class:
/*** 实现了 FactoryBean 的实现** @author mindartisan.blog.csdn.net* @date*/public class UserFactoryBean implements FactoryBean {@Overridepublic Object getObject() throws Exception {return User.createUser();}@Overridepublic Class<?> getObjectType() {return User.class;}}
特殊
通过 ServiceLoaderFactoryBean(配置元信息:XML、Java 注解、Java API)
通过 AutowireCapableBeanFactory#createBean(Java.lang.Class,int,boolean)
通过 BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition)
代码
SpecialBeanInstantinationDemo.class:
/*** 特殊的 Bean 实例化 demo** @author mindartisan.blog.csdn.net* @date*/public class SpecialBeanInstantinationDemo {public static void main(String[] args) {// serviceloaderBeanFactory beanFactory = new ClassPathXmlApplicationContext("META-INF/special-bean-instantiation-context.xml");// 从 ServiceLoaderFactoryBean 中创建一个 ServiceLoader,再通过遍历的方式获取所有该 ServiceLoader 的实现类// 在此代码中,创建一个「SecondUserFactory」的实现,displayServiceLoader 会输出两个「User{id=1, name='Steve'}」ServiceLoader<UserFactory> userFactoryServiceLoader = beanFactory.getBean("userFactoryServiceLoader", ServiceLoader.class);displayServiceLoader(userFactoryServiceLoader);// demoServiceLoader();System.out.println("---------------");// 通过 applicationContext 获取 autowireCapableBeanFactoryApplicationContext applicationContext = new ClassPathXmlApplicationContext("META-INF/special-bean-instantiation-context.xml");AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();// 通过 autowireCapableBeanFactory 创建 userFactory 对象// 注意:在 AutowireCapableBeanFactory#createBean(Class<T> beanClass) 的时候,beanClass 要具体的类,不能是接口或者抽象类UserFactory userFactory = autowireCapableBeanFactory.createBean(DefaultUserFactory.class);User user = userFactory.createUser();// 输出「User{id=1, name='Steve'}」System.out.println(user);}/*** serviceloader demo*/public static void demoServiceLoader() {ServiceLoader<UserFactory> userFactoryServiceLoader = ServiceLoader.load(UserFactory.class,Thread.currentThread().getContextClassLoader());displayServiceLoader(userFactoryServiceLoader);}public static void displayServiceLoader(ServiceLoader<UserFactory> userFactoryServiceLoader) {Iterator<UserFactory> userFactoryIterator = userFactoryServiceLoader.iterator();while (userFactoryIterator.hasNext()) {UserFactory userFactory = userFactoryIterator.next();// 输出「User{id=1, name='Steve'}」System.out.println(userFactory.createUser());}}}
special-bean-instantiation-context.xml:
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="userFactoryServiceLoader"class="org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean"><property name="serviceType" value="com.mindartisan.spring.geek.bean.factory.UserFactory"/></bean></beans>
SecondUserFactory.class:
/*** 次要用户工厂** @author mindartisan.blog.csdn.net* @date*/public class SecondUserFactory implements UserFactory {}
META-INF/services/com.mindartisan.spring.geek.bean.factory.UserFactory
与 ServiceLoader 有关
com.mindartisan.spring.geek.bean.factory.DefaultUserFactorycom.mindartisan.spring.geek.bean.factory.SecondUserFactory
上述内容指定了com.mindartisan.spring.geek.bean.factory.UserFactory的实现类
扩展:ServiceLoader
体现了 SPI 机制
JDK 的 ServiceLoader
在 main 方法中,使用了 JDK 自带的ServiceLoader。上述的_META-INF/services/com.mindartisan.spring.geek.bean.factory.UserFactory_之所以在 META/INF/services这个路径下是因为 ServiceLoader 中下述代码:
private static final String PREFIX = "META-INF/services/";
Spring 中的 「ServiceLoader」
在 Spring 中,也提供了适配 JDK 中ServiceLoader的实现:ServiceLoaderFactoryBean.class,其父类AbstractServiceLoaderBasedFactoryBean.class有三个子类,如下:
三个子类中对 AbstractServiceLoaderBasedFactoryBean#getObjectToExpose(ServiceLoader<?> serviceLoader)有三种不同的实现:
- ServiceFactoryBean:返回一个
- ServiceLoaderFactoryBean:
- ServiceListFactoryBean:返回所有
在使用时,还要注意设置 serviceType,xml 的配置方式如下:
<bean id="userFactoryServiceLoader" class="org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean"><property name="serviceType" value="com.mindartisan.spring.geek.bean.factory.UserFactory"/></bean>
初始化 Spring Bean
实现
- @PostConstruct 标注方法
- 实现 InitializingBean 接口的 afterPropertiesSet() 方法
自定义初始化方法
- XML 配置:
- Java 注解:@Bean(initMethod=”init”)
Java API:AbstractBeanDefinition#setInitMethodName(String)
代码
BeanInitializationDemo.class
@Configurationpublic class BeanInitializationDemo {public static void main(String[] args) {// 创建 BeanFactory 容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();applicationContext.register(BeanInitializationDemo.class);// 启动 Spring 应用上下文applicationContext.refresh();UserFactory userFactory = applicationContext.getBean(UserFactory.class);// 关闭 Spring 应用上下文applicationContext.close();}@Bean(initMethod = "initUserFactory")public UserFactory userFactory() {return new DefaultUserFactory();}}
DefaultUserFactory.class ```java /**
- 默认用户工厂 *
- @author mindartisan.blog.csdn.net
@date */ public class DefaultUserFactory implements UserFactory, InitializingBean {
// Bean 初始化使用 // 1. 基于 @PostConstruct 注解 @PostConstruct public void init() { System.out.println(“@PostConstruct:UserFactory 初始化中”); }
- XML 配置:
public void initUserFactory() {System.out.println("自定义初始化方法 initUserFactory():UserFactory 初始化中");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("afterPropertiesSet:UserFactory 初始化中");}
}
<a name="hPD77"></a>## 顺序参考:[Spring official](https://docs.spring.io/spring-framework/docs/5.2.2.RELEASE/spring-framework-reference/core.html#beans-factory-lifecycle-combined-effects)1. 使用注解1. 继承接口,重写方法1. 手动配置的方法<a name="d4d8269c"></a># 延迟初始化 Spring Bean<a name="UkUhu"></a>## 实现1. XML 配置<bean lazy-init = "true" …/>1. Java 注解:@Lazy<a name="rNM6J"></a>## 代码:BeanInitializationDemo.class```java@Configurationpublic class BeanInitializationDemo {public static void main(String[] args) {// 创建 BeanFactory 容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();applicationContext.register(BeanInitializationDemo.class);// 启动 Spring 应用上下文applicationContext.refresh();// 非延迟初始化在 Spring 应用上下文启动完成后被初始化System.out.println("Spring 应用上下文已经启动");UserFactory userFactory = applicationContext.getBean(UserFactory.class);System.out.println("使用了 @Lazy 注解「当前为 true」:"+userFactory);// 关闭 Spring 应用上下文applicationContext.close();}@Bean(initMethod = "initUserFactory")@Lazy(value = true)public UserFactory userFactory() {return new DefaultUserFactory();}}
当 @Lazy(value = true) 时,输出以下内容:
Spring 应用上下文已经启动 @PostConstruct:UserFactory 初始化中 afterPropertiesSet:UserFactory 初始化中 自定义初始化方法 initUserFactory():UserFactory 初始化中 使用了 @Lazy 注解「当前为 true」:com.mindartisan.spring.geek.bean.factory.DefaultUserFactory@197d671
BeanInitializationDemo.class
@Configurationpublic class BeanInitializationDemo {public static void main(String[] args) {// 创建 BeanFactory 容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();applicationContext.register(BeanInitializationDemo.class);// 启动 Spring 应用上下文applicationContext.refresh();// 非延迟初始化在 Spring 应用上下文启动完成后被初始化System.out.println("Spring 应用上下文已经启动");UserFactory userFactory = applicationContext.getBean(UserFactory.class);System.out.println("使用了 @Lazy 注解「当前为 false」:"+userFactory);// 关闭 Spring 应用上下文applicationContext.close();}@Bean(initMethod = "initUserFactory")@Lazy(value = false)public UserFactory userFactory() {return new DefaultUserFactory();}}
当 @Lazy(value = fale) 时,输出以下内容:
@PostConstruct:UserFactory 初始化中 afterPropertiesSet:UserFactory 初始化中 自定义初始化方法 initUserFactory():UserFactory 初始化中 Spring 应用上下文已经启动 使用了 @Lazy 注解「当前为 false」:com.mindartisan.spring.geek.bean.factory.DefaultUserFactory@6b4a4e18
延迟初始化和非延迟初始化的主要区别是:延迟初始化在 Spring 应用上下文之后,非延迟在之前。
销毁Spring Bean
方式
@PreDestory标注方法- 实现
DisposableBean#destory()方法 自定义销毁方法
- XML 配置:
<bean destroy = "xxx" … /> - Java 注解:
@Bean(destroy = "xxx") Java API:
AbstractBeanDefinition#setDestroyMethodName(String)代码
BeanInitializationDemo.class
@Configurationpublic class BeanInitializationDemo {public static void main(String[] args) {// 创建 BeanFactory 容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();applicationContext.register(BeanInitializationDemo.class);// 启动 Spring 应用上下文applicationContext.refresh();// 非延迟初始化在 Spring 应用上下文启动完成后被初始化System.out.println("Spring 应用上下文已经启动");UserFactory userFactory = applicationContext.getBean(UserFactory.class);System.out.println("使用了 @Lazy 注解「当前为 false」:"+userFactory);System.out.println("Spring 应用上下文准备关闭");// 关闭 Spring 应用上下文applicationContext.close();System.out.println("Spring 应用上下文已经关闭");}@Bean(initMethod = "initUserFactory",destroyMethod = "doDestroy")@Lazy(value = false)public UserFactory userFactory() {return new DefaultUserFactory();}}
DefaultUserFactory.class: ```java /**
- 默认用户工厂 *
- @author mindartisan.blog.csdn.net
@date */ public class DefaultUserFactory implements UserFactory, InitializingBean, DisposableBean {
// Bean 初始化使用 // 1. 基于 @PostConstruct 注解 @PostConstruct public void init() { System.out.println(“@PostConstruct:UserFactory 初始化中”); }
- XML 配置:
public void initUserFactory() {System.out.println("自定义初始化方法 initUserFactory():UserFactory 初始化中");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("afterPropertiesSet:UserFactory 初始化中");}@PreDestroypublic void preDestroy() {System.out.println("@PreDestroy:UserFactory 销毁中");}@Overridepublic void destroy() throws Exception {System.out.println("DisposableBean#destroy():UserFactory 销毁中");}/*** 自定义销毁方法*/public void doDestroy() {System.out.println("自定义销毁方法 doDestroy():UserFactory 销毁中");}
}
``
当@Lazy(value = fale)` 时,输出以下内容:
@PostConstruct:UserFactory 初始化中 afterPropertiesSet:UserFactory 初始化中 自定义初始化方法 initUserFactory():UserFactory 初始化中 Spring 应用上下文已经启动 使用了 @Lazy 注解「当前为 false」:com.mindartisan.spring.geek.bean.factory.DefaultUserFactory@197d671 Spring 应用上下文准备关闭 @PreDestroy:UserFactory 销毁中 DisposableBean#destroy():UserFactory 销毁中 自定义销毁方法 doDestroy():UserFactory 销毁中 Spring 应用上下文已经关闭
顺序
- 使用注解
- 继承接口,重写方法
-
源码分析
@PreDestory 标注方法
比较简单,直接 IDEA 搜
@PreDestory的 usage: CommonAnnotationBeanPostProcessor.CommonAnnotationBeanPostProcessor();
- InitDestroyAnnotationBeanPostProcessor.setDestroyAnnotationType()
再在当前类下搜destroyAnnotationType,会发现buildLifecycleMetadata()方法中使用反射去找标注了注解的方法,有的话,就添加到销毁方法的集合中currDestroyMethods.add(new LifecycleElement(method));
实现 DisposableBean#destory()方法
首先看上文的输出,确定好是在 applicationContext.close() 将 Bean 销毁:
- AbstractApplicationContext.close();
- AbstractApplicationContext.doClose();
- AbstractApplicationContext.destroyBeans();
- ConfigurableBeanFactory.destroySingletons();
- DefaultListableBeanFactory.destroySingletons();
- DefaultSingletonBeanRegistry.destroySingletons();「这里通过遍历循环调用下一步」
- DefaultSingletonBeanRegistry.destroySingleton();
- DefaultSingletonBeanRegistry.destroyBean(String beanName, @Nullable DisposableBean bean);
- DisposableBean.destroy();
垃圾回收 Spring Bean
- 未理解,待办
