定义Spring Bean

对应代码中的 BeanDefinition,是 Spring Framework 中定义 Bean 的配置元信息接口,主要包含:

  1. Bean 的类名,全限定名称,具体实现类
  2. Bean 配置元信息:作用域、自动绑定(Auto Wiring)、生命周期回调……
  3. Bean 的引用:合作者(Collaborators)或者依赖(Dependencies),
  4. 配置的设置: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. // 1. 通过 BeanDefinitionBuilder 构建
  2. BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
  3. // 通过属性设置(挨个添加),此处可以使用「beanDefinitionBuilder.addPropertyValue("name","Steve").addPropertyValue("id",30);」
  4. beanDefinitionBuilder.addPropertyValue("name","Steve");
  5. beanDefinitionBuilder.addPropertyValue("id",30);
  6. // 获取 BeanDefinition 实例
  7. BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
  8. // beanDefinition 有好多 set 方法,BeanDefinition 并非 Bean 的终态,可以自定义修改

通过 AbstractBeanDefinition 以及派生类

  1. // 2. 通过 AbstractBeanDefinition 以及派生类
  2. GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
  3. // 设置 Bean 类型
  4. genericBeanDefinition.setBeanClass(User.class);
  5. // 通过 MutablePropertyValues 批量操作属性,此处可以使用 「propertyValues.add("name","Steve").add("id",31)」
  6. MutablePropertyValues propertyValues = new MutablePropertyValues();
  7. propertyValues.addPropertyValue("name","Steve");
  8. propertyValues.addPropertyValue("id",31);
  9. genericBeanDefinition.setPropertyValues(propertyValues);

命名Spring Bean

Bean 名称

推荐阅读:spring学习之bean的命名-segmentfault

每个 Bean 都有一个或者多个标识符,标识符要在 Bean 的所在容器唯一。通常情况下,一个 Bean 有一个标识符,如果需要额外的标识符则使用别名扩充。

基于 XML 的情况下,可以用 id 或者 name 属性规定 Bean 的标识符。如果想使用别名,在 name 属性使用「,」或者「;」分开。

Bean 的 id 或者 name 可以留空,留空后,容器会为 Bean 自动生成唯一的名称。推荐使用驼峰,符合 Java 命名规范。

Spring 中可查看BeanNameGenerator 的两个实现。

注解实现

具体看:AnnotationBeanNameGenerator

比如用到的 @component@Repository@Service@Controller等,其实后三者只是简单包了一层第一个

  1. @Target({ElementType.TYPE})
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Component
  5. public @interface Service {
  6. /**
  7. * The value may indicate a suggestion for a logical component name,
  8. * to be turned into a Spring bean in case of an autodetected component.
  9. * @return the suggested component name, if any (or empty String otherwise)
  10. */
  11. @AliasFor(annotation = Component.class)
  12. String value() default "";
  13. }

默认实现

具体看:DefaultBeanNameGenerator

Spring Bean 的别名

好处

  1. 可以复用现有的 BeanDefinitio
  2. 能够通过命名看出来使用场景(比如同一个 Bean 在 A 系统里叫 beanInA,在 B 系统里可以叫 beanInB)

    注册 Spring Bean

    基础

    XML 配置元信息

Java 注解

@Bean@Component@Import

Java API 配置元信息

  1. 命名方式:BeanDefinitionRegistry#registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
  2. 非命名方式:BeanDifinitionReaderUtils#registerWithGeneratedName(AbstractBeanDefinition definition, BeanDefinitionRegistry registry)
  3. 配置类方式: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) {

    1. // 创建 BeanFactory 容器
    2. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    3. // 注册 配置类
    4. // 方式 3:配置类方式;详细看:AnnotationConfigApplicationContext#register(Class<?>... componentClasses) -> AnnotatedBeanDefinitionReader#register(Class<?>... componentClasses)
    5. applicationContext.register(AnnotationBeanDefinitionDemo.class);
    6. registerUserBeanDefinition(applicationContext,"mindartisan-user");
    7. registerUserBeanDefinition(applicationContext);
    8. // 启动 Spring 应用上下文
    9. applicationContext.refresh();
    10. // 输出Config 类型的 Bean:{com.mindartisan.spring.geek.bean.definition.AnnotationBeanDefinitionDemo$Config=com.mindartisan.spring.geek.bean.definition.AnnotationBeanDefinitionDemo$Config@7f416310}
    11. System.out.println("Config 类型的 Bean:" + applicationContext.getBeansOfType(Config.class));
    12. // User 类型的 Bean:{user=User{id=1, name='Steve'}}
    13. System.out.println("User 类型的 Bean:" + applicationContext.getBeansOfType(User.class));
    14. // 关闭 Spring 应用上下文
    15. applicationContext.close();

    }

  1. /**
  2. * bean 的注册方式
  3. *
  4. * @param beanDefinitionRegistry
  5. * @param beanName
  6. */
  7. public static void registerUserBeanDefinition(BeanDefinitionRegistry beanDefinitionRegistry, String beanName) {
  8. BeanDefinitionBuilder beanDefinitionBuilder = genericBeanDefinition(User.class);
  9. beanDefinitionBuilder
  10. .addPropertyValue("id", 1L)
  11. .addPropertyValue("name", "Steve");
  12. if (StringUtils.hasText(beanName)) {
  13. // 命名方式注册 BeanDefinition
  14. beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition());
  15. } else {
  16. // 非命名方式
  17. BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinitionBuilder.getBeanDefinition(), beanDefinitionRegistry);
  18. }
  19. }
  20. public static void registerUserBeanDefinition(BeanDefinitionRegistry beanDefinitionRegistry) {
  21. registerUserBeanDefinition(beanDefinitionRegistry, null);
  22. }
  23. @Component// 通过 @Component 定义当前类作为 Spring Bean(组件)
  24. public static class Config {
  25. /**
  26. * 通过 Java 注解,定义 Bean
  27. *
  28. * @return
  29. */
  30. @Bean(name = {"user", "steve-user"})// 通过 @Bean,定义 Bean
  31. public User user() {
  32. User user = new User();
  33. user.setId(1L);
  34. user.setName("Steve");
  35. return user;
  36. }
  37. }

}

  1. <a name="UmRRd"></a>
  2. ## 扩展
  3. 通过外部单体对象注册,主要用到的是 `SingletonBeanRegistry#registerSingleton(String beanName, Object singletonObject);` 方法<br />SingtonBeanRegistrationDemo.class:
  4. ```java
  5. /**
  6. * 外部单体 Bean 注册实例
  7. * 外部 bean:不被 Spring 管理的类
  8. *
  9. * @author mindartisan.blog.csdn.net
  10. * @date
  11. */
  12. public class SingtonBeanRegistrationDemo {
  13. public static void main(String[] args) {
  14. // 创建 BeanFactory 容器
  15. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  16. // 这里的 userFactory 未被 Spring 管理
  17. UserFactory userFactory = new DefaultUserFactory();
  18. ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
  19. // 启动 Spring 应用上下文
  20. applicationContext.refresh();
  21. // 注册外部单例对象
  22. beanFactory.registerSingleton("userFactory", userFactory);
  23. // 通过依赖查找的方式获取 userFactory
  24. UserFactory userFactoryByLookup = beanFactory.getBean("userFactory", UserFactory.class);
  25. System.out.println("userFactory == userFactoryByLookup:" + (userFactory == userFactoryByLookup));
  26. // 关闭 Spring 应用上下文
  27. applicationContext.close();
  28. }
  29. }

实例化 Spring Bean

常规

通过构造器(配置元信息:XML、Java 注解、Java API)

通过静态工厂方法(配置元信息:XML、Java API)

通过 Bean 工厂方法(配置元信息:XML、Java API)

通过 FactoryBean 方式(配置元信息:XML、Java 注解、Java API)

代码

具体方式看 xml 中注释,和 main 方法中的命名

User.class:

  1. /**
  2. * 用户
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class User {
  8. private Long id;
  9. private String name;
  10. public Long getId() {
  11. return id;
  12. }
  13. public void setId(Long id) {
  14. this.id = id;
  15. }
  16. public String getName() {
  17. return name;
  18. }
  19. public void setName(String name) {
  20. this.name = name;
  21. }
  22. @Override
  23. public String toString() {
  24. return "User{" +
  25. "id=" + id +
  26. ", name='" + name + '\'' +
  27. '}';
  28. }
  29. /**
  30. * 通过静态方法实例化
  31. *
  32. * @return {@link User}
  33. */
  34. public static User createUser(){
  35. User user = new User();
  36. user.setId(1L);
  37. user.setName("Steve");
  38. return user;
  39. }
  40. }

bean-instantiation-context.xml:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <!--静态方法实例化 Bean-->
  6. <bean id="user-by-static-method" class="com.mindartisan.spring.geek.ioc.overview.domain.User"
  7. factory-method="createUser"/>
  8. <!--实例 Bean 方法实例化 bean-->
  9. <bean id="user-by-instance-method" factory-bean="userFactory" factory-method="createUser"/>
  10. <bean id="userFactory" class="com.mindartisan.spring.geek.bean.factory.DefaultUserFactory"/>
  11. <!--FactoryBean 实例化 bean-->
  12. <bean id="user-by-factory-bean" class="com.mindartisan.spring.geek.bean.factory.UserFactoryBean"/>
  13. </beans>

BeanInstantinationDemo.class:

  1. /**
  2. * Bean 实例化 demo
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class BeanInstantinationDemo {
  8. public static void main(String[] args) {
  9. BeanFactory beanFactory = new ClassPathXmlApplicationContext("META-INF/bean-instantiation-context.xml");
  10. User userByStaticMethod = beanFactory.getBean("user-by-static-method", User.class);
  11. // 输出「User{id=1, name='Steve'}」
  12. System.out.println(userByStaticMethod);
  13. User userByInstanceMethod = beanFactory.getBean("user-by-instance-method", User.class);
  14. // 输出「User{id=1, name='Steve'}」
  15. System.out.println(userByInstanceMethod);
  16. // 输出「false」
  17. System.out.println(userByStaticMethod == userByInstanceMethod);
  18. User userByFactoryBean = beanFactory.getBean("user-by-factory-bean", User.class);
  19. // 输出「User{id=1, name='Steve'}」
  20. System.out.println(userByFactoryBean);
  21. // 输出「false」
  22. System.out.println(userByStaticMethod == userByFactoryBean);
  23. // 输出「false」
  24. System.out.println(userByFactoryBean == userByInstanceMethod);
  25. }
  26. }

UserFactory.class:

  1. /**
  2. * 工厂类
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public interface UserFactory {
  8. default User createUser(){
  9. return User.createUser();
  10. }
  11. }

DefaultUserFactory.class:

  1. /**
  2. * 默认用户工厂
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class DefaultUserFactory implements UserFactory {
  8. }

UserFactoryBean.class:

  1. /**
  2. * 实现了 FactoryBean 的实现
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class UserFactoryBean implements FactoryBean {
  8. @Override
  9. public Object getObject() throws Exception {
  10. return User.createUser();
  11. }
  12. @Override
  13. public Class<?> getObjectType() {
  14. return User.class;
  15. }
  16. }

特殊

通过 ServiceLoaderFactoryBean(配置元信息:XML、Java 注解、Java API)

通过 AutowireCapableBeanFactory#createBean(Java.lang.Class,int,boolean)

通过 BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition)

参考:注册 Spring Bean -> Java API 配置元信息

代码

SpecialBeanInstantinationDemo.class:

  1. /**
  2. * 特殊的 Bean 实例化 demo
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class SpecialBeanInstantinationDemo {
  8. public static void main(String[] args) {
  9. // serviceloader
  10. BeanFactory beanFactory = new ClassPathXmlApplicationContext("META-INF/special-bean-instantiation-context.xml");
  11. // 从 ServiceLoaderFactoryBean 中创建一个 ServiceLoader,再通过遍历的方式获取所有该 ServiceLoader 的实现类
  12. // 在此代码中,创建一个「SecondUserFactory」的实现,displayServiceLoader 会输出两个「User{id=1, name='Steve'}」
  13. ServiceLoader<UserFactory> userFactoryServiceLoader = beanFactory.getBean("userFactoryServiceLoader", ServiceLoader.class);
  14. displayServiceLoader(userFactoryServiceLoader);
  15. // demoServiceLoader();
  16. System.out.println("---------------");
  17. // 通过 applicationContext 获取 autowireCapableBeanFactory
  18. ApplicationContext applicationContext = new ClassPathXmlApplicationContext("META-INF/special-bean-instantiation-context.xml");
  19. AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();
  20. // 通过 autowireCapableBeanFactory 创建 userFactory 对象
  21. // 注意:在 AutowireCapableBeanFactory#createBean(Class<T> beanClass) 的时候,beanClass 要具体的类,不能是接口或者抽象类
  22. UserFactory userFactory = autowireCapableBeanFactory.createBean(DefaultUserFactory.class);
  23. User user = userFactory.createUser();
  24. // 输出「User{id=1, name='Steve'}」
  25. System.out.println(user);
  26. }
  27. /**
  28. * serviceloader demo
  29. */
  30. public static void demoServiceLoader() {
  31. ServiceLoader<UserFactory> userFactoryServiceLoader = ServiceLoader.load(UserFactory.class,
  32. Thread.currentThread().getContextClassLoader());
  33. displayServiceLoader(userFactoryServiceLoader);
  34. }
  35. public static void displayServiceLoader(ServiceLoader<UserFactory> userFactoryServiceLoader) {
  36. Iterator<UserFactory> userFactoryIterator = userFactoryServiceLoader.iterator();
  37. while (userFactoryIterator.hasNext()) {
  38. UserFactory userFactory = userFactoryIterator.next();
  39. // 输出「User{id=1, name='Steve'}」
  40. System.out.println(userFactory.createUser());
  41. }
  42. }
  43. }

special-bean-instantiation-context.xml:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <bean id="userFactoryServiceLoader"
  6. class="org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean">
  7. <property name="serviceType" value="com.mindartisan.spring.geek.bean.factory.UserFactory"/>
  8. </bean>
  9. </beans>

SecondUserFactory.class:

  1. /**
  2. * 次要用户工厂
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class SecondUserFactory implements UserFactory {
  8. }

META-INF/services/com.mindartisan.spring.geek.bean.factory.UserFactory

与 ServiceLoader 有关

  1. com.mindartisan.spring.geek.bean.factory.DefaultUserFactory
  2. com.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 中下述代码:

  1. private static final String PREFIX = "META-INF/services/";

image.png

Spring 中的 「ServiceLoader」

在 Spring 中,也提供了适配 JDK 中ServiceLoader的实现:ServiceLoaderFactoryBean.class,其父类AbstractServiceLoaderBasedFactoryBean.class有三个子类,如下:
image.png
三个子类中对 AbstractServiceLoaderBasedFactoryBean#getObjectToExpose(ServiceLoader<?> serviceLoader)有三种不同的实现:

  1. ServiceFactoryBean:返回一个
  2. ServiceLoaderFactoryBean:
  3. ServiceListFactoryBean:返回所有

在使用时,还要注意设置 serviceType,xml 的配置方式如下:

  1. <bean id="userFactoryServiceLoader" class="org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean">
  2. <property name="serviceType" value="com.mindartisan.spring.geek.bean.factory.UserFactory"/>
  3. </bean>

初始化 Spring Bean

实现

  1. @PostConstruct 标注方法
  2. 实现 InitializingBean 接口的 afterPropertiesSet() 方法
  3. 自定义初始化方法

    1. XML 配置:
    2. Java 注解:@Bean(initMethod=”init”)
    3. Java API:AbstractBeanDefinition#setInitMethodName(String)

      代码

      BeanInitializationDemo.class

      1. @Configuration
      2. public class BeanInitializationDemo {
      3. public static void main(String[] args) {
      4. // 创建 BeanFactory 容器
      5. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
      6. applicationContext.register(BeanInitializationDemo.class);
      7. // 启动 Spring 应用上下文
      8. applicationContext.refresh();
      9. UserFactory userFactory = applicationContext.getBean(UserFactory.class);
      10. // 关闭 Spring 应用上下文
      11. applicationContext.close();
      12. }
      13. @Bean(initMethod = "initUserFactory")
      14. public UserFactory userFactory() {
      15. return new DefaultUserFactory();
      16. }
      17. }

      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 初始化中”); }

  1. public void initUserFactory() {
  2. System.out.println("自定义初始化方法 initUserFactory():UserFactory 初始化中");
  3. }
  4. @Override
  5. public void afterPropertiesSet() throws Exception {
  6. System.out.println("afterPropertiesSet:UserFactory 初始化中");
  7. }

}

  1. <a name="hPD77"></a>
  2. ## 顺序
  3. 参考:[Spring official](https://docs.spring.io/spring-framework/docs/5.2.2.RELEASE/spring-framework-reference/core.html#beans-factory-lifecycle-combined-effects)
  4. 1. 使用注解
  5. 1. 继承接口,重写方法
  6. 1. 手动配置的方法
  7. <a name="d4d8269c"></a>
  8. # 延迟初始化 Spring Bean
  9. <a name="UkUhu"></a>
  10. ## 实现
  11. 1. XML 配置<bean lazy-init = "true"/>
  12. 1. Java 注解:@Lazy
  13. <a name="rNM6J"></a>
  14. ## 代码:
  15. BeanInitializationDemo.class
  16. ```java
  17. @Configuration
  18. public class BeanInitializationDemo {
  19. public static void main(String[] args) {
  20. // 创建 BeanFactory 容器
  21. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  22. applicationContext.register(BeanInitializationDemo.class);
  23. // 启动 Spring 应用上下文
  24. applicationContext.refresh();
  25. // 非延迟初始化在 Spring 应用上下文启动完成后被初始化
  26. System.out.println("Spring 应用上下文已经启动");
  27. UserFactory userFactory = applicationContext.getBean(UserFactory.class);
  28. System.out.println("使用了 @Lazy 注解「当前为 true」:"+userFactory);
  29. // 关闭 Spring 应用上下文
  30. applicationContext.close();
  31. }
  32. @Bean(initMethod = "initUserFactory")
  33. @Lazy(value = true)
  34. public UserFactory userFactory() {
  35. return new DefaultUserFactory();
  36. }
  37. }

@Lazy(value = true) 时,输出以下内容:

Spring 应用上下文已经启动 @PostConstruct:UserFactory 初始化中 afterPropertiesSet:UserFactory 初始化中 自定义初始化方法 initUserFactory():UserFactory 初始化中 使用了 @Lazy 注解「当前为 true」:com.mindartisan.spring.geek.bean.factory.DefaultUserFactory@197d671

BeanInitializationDemo.class

  1. @Configuration
  2. public class BeanInitializationDemo {
  3. public static void main(String[] args) {
  4. // 创建 BeanFactory 容器
  5. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  6. applicationContext.register(BeanInitializationDemo.class);
  7. // 启动 Spring 应用上下文
  8. applicationContext.refresh();
  9. // 非延迟初始化在 Spring 应用上下文启动完成后被初始化
  10. System.out.println("Spring 应用上下文已经启动");
  11. UserFactory userFactory = applicationContext.getBean(UserFactory.class);
  12. System.out.println("使用了 @Lazy 注解「当前为 false」:"+userFactory);
  13. // 关闭 Spring 应用上下文
  14. applicationContext.close();
  15. }
  16. @Bean(initMethod = "initUserFactory")
  17. @Lazy(value = false)
  18. public UserFactory userFactory() {
  19. return new DefaultUserFactory();
  20. }
  21. }

@Lazy(value = fale) 时,输出以下内容:

@PostConstruct:UserFactory 初始化中 afterPropertiesSet:UserFactory 初始化中 自定义初始化方法 initUserFactory():UserFactory 初始化中 Spring 应用上下文已经启动 使用了 @Lazy 注解「当前为 false」:com.mindartisan.spring.geek.bean.factory.DefaultUserFactory@6b4a4e18

延迟初始化和非延迟初始化的主要区别是:延迟初始化在 Spring 应用上下文之后,非延迟在之前。

销毁Spring Bean

方式

  1. @PreDestory标注方法
  2. 实现 DisposableBean#destory()方法
  3. 自定义销毁方法

    1. XML 配置:<bean destroy = "xxx" … />
    2. Java 注解:@Bean(destroy = "xxx")
    3. Java API:AbstractBeanDefinition#setDestroyMethodName(String)

      代码

      BeanInitializationDemo.class

      1. @Configuration
      2. public class BeanInitializationDemo {
      3. public static void main(String[] args) {
      4. // 创建 BeanFactory 容器
      5. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
      6. applicationContext.register(BeanInitializationDemo.class);
      7. // 启动 Spring 应用上下文
      8. applicationContext.refresh();
      9. // 非延迟初始化在 Spring 应用上下文启动完成后被初始化
      10. System.out.println("Spring 应用上下文已经启动");
      11. UserFactory userFactory = applicationContext.getBean(UserFactory.class);
      12. System.out.println("使用了 @Lazy 注解「当前为 false」:"+userFactory);
      13. System.out.println("Spring 应用上下文准备关闭");
      14. // 关闭 Spring 应用上下文
      15. applicationContext.close();
      16. System.out.println("Spring 应用上下文已经关闭");
      17. }
      18. @Bean(initMethod = "initUserFactory",destroyMethod = "doDestroy")
      19. @Lazy(value = false)
      20. public UserFactory userFactory() {
      21. return new DefaultUserFactory();
      22. }
      23. }

      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 初始化中”); }

  1. public void initUserFactory() {
  2. System.out.println("自定义初始化方法 initUserFactory():UserFactory 初始化中");
  3. }
  4. @Override
  5. public void afterPropertiesSet() throws Exception {
  6. System.out.println("afterPropertiesSet:UserFactory 初始化中");
  7. }
  8. @PreDestroy
  9. public void preDestroy() {
  10. System.out.println("@PreDestroy:UserFactory 销毁中");
  11. }
  12. @Override
  13. public void destroy() throws Exception {
  14. System.out.println("DisposableBean#destroy():UserFactory 销毁中");
  15. }
  16. /**
  17. * 自定义销毁方法
  18. */
  19. public void doDestroy() {
  20. System.out.println("自定义销毁方法 doDestroy():UserFactory 销毁中");
  21. }

} `` 当@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 应用上下文已经关闭

顺序

参考:Spring official

  1. 使用注解
  2. 继承接口,重写方法
  3. 手动配置的方法

    源码分析

    @PreDestory 标注方法

    比较简单,直接 IDEA 搜 @PreDestory 的 usage:

  4. CommonAnnotationBeanPostProcessor.CommonAnnotationBeanPostProcessor();

  5. InitDestroyAnnotationBeanPostProcessor.setDestroyAnnotationType()

再在当前类下搜destroyAnnotationType,会发现buildLifecycleMetadata()方法中使用反射去找标注了注解的方法,有的话,就添加到销毁方法的集合中currDestroyMethods.add(new LifecycleElement(method));

实现 DisposableBean#destory()方法

首先看上文的输出,确定好是在 applicationContext.close() 将 Bean 销毁:

  1. AbstractApplicationContext.close();
  2. AbstractApplicationContext.doClose();
  3. AbstractApplicationContext.destroyBeans();
  4. ConfigurableBeanFactory.destroySingletons();
  5. DefaultListableBeanFactory.destroySingletons();
  6. DefaultSingletonBeanRegistry.destroySingletons();「这里通过遍历循环调用下一步」
  7. DefaultSingletonBeanRegistry.destroySingleton();
  8. DefaultSingletonBeanRegistry.destroyBean(String beanName, @Nullable DisposableBean bean);
  9. DisposableBean.destroy();

    垃圾回收 Spring Bean

  • 未理解,待办