夯實Spring系列|第六章:Spring Bean 註冊、實例化、初始化、銷燬

夯實Spring系列|第六章:Spring Bean 註冊、實例化、初始化、銷燬

本章說明

在上一章,我們知道如何來定義一個 Bean ,如何來構建 BeanDefinition;本章主要簡單演示 Spring Bean 剩下的生命週期,Bean 生命週期後續有專門的章節來討論,本章知識簡單的代碼演示,討論一些相關的細節。

由於本章內容聯繫比較緊密,所有並沒有分爲幾章,導致內容較多,讀者可以通過目錄跳轉到有興趣的議題即可。
在這裏插入圖片描述

1.項目環境

2.註冊 Spring Bean

BeanDefinition 註冊有以下方式

  • XML 配置元信息
    • <bean name="" …/>
  • Java 註解配置元信息
    • @Bean
    • @Component
    • @Import
  • Java API 配置元信息
    • 命名方式:BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition)
    • 非命名方式:BeanDefinitionReaderUtils#registerWithGeneratedName
    • 配置類方式:AnnotatedBeanDefinitionReader#register(Class<?>… componentClasses)

2.1 註冊示例

之前的章節都是 xml 的方式進行註冊,下面的例子演示剩下幾種註冊方式。

2.1.1 Java 註解配置元信息

  1. @Bean 方式定義
  2. @Component 方式定義
    //2.通過 @Component 方式定義    
    @Component //定義當前類最爲 Spring Bean 組件
    public static class Config {
        //1.通過 @Bean 方式定義
        @Bean(name = {"user", "xwf-user"})
        public User user() {
            User user = new User();
            user.setAge(18);
            user.setName("xwf");
            user.setId(123L);
            return user;
        }
    }
  1. 通過 @Import 來進行導入
@Import(AnnotationBeanDefinitionDemo.Config.class)
public class AnnotationBeanDefinitionDemo {
    ...

2.2.2 Java API 配置元信息

完整示例

@Import(AnnotationBeanDefinitionDemo.Config.class)
public class AnnotationBeanDefinitionDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(AnnotationBeanDefinitionDemo.class);
        //通過 BeanDefinition 註冊 API 實現
        // 1.通過命名方式註冊
        registerUserBeanDefinition(applicationContext,"definition-user");
        // 2.非命名方式註冊
        registerUserBeanDefinition(applicationContext);
        //啓動 Spring 應用上下文
        applicationContext.refresh();
        Map<String,Config> beansOfType = applicationContext.getBeansOfType(Config.class);
        printEach(beansOfType);

        Map<String, User> users = applicationContext.getBeansOfType(User.class);
        printEach(users);

        applicationContext.close();
    }

    private static void printEach(Map<String, ?> beansOfType) {
        System.out.println("=====");
        beansOfType.entrySet().stream().forEach(System.out::println);
        System.out.println("=====");
    }

    /**
     * 命名 Bean 的註冊方式
     *
     * @param registry
     * @param beanName
     */
    public static void registerUserBeanDefinition(BeanDefinitionRegistry registry, String beanName) {
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
        beanDefinitionBuilder.addPropertyValue("age", 18)
                .addPropertyValue("id", 1L)
                .addPropertyValue("name", "xwf");

        if (StringUtils.hasText(beanName)) {
            registry.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition());
        } else {
            //非命名方式
            BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinitionBuilder.getBeanDefinition(), registry);
        }
    }

    public static void registerUserBeanDefinition(BeanDefinitionRegistry registry) {
        registerUserBeanDefinition(registry, null);
    }

    @Component //定義當前類最爲 Spring Bean 組件
    public static class Config {

        @Bean(name = {"user", "xwf-user"})
        public User user() {
            User user = new User();
            user.setAge(18);
            user.setName("xwf");
            user.setId(123L);
            return user;
        }
    }
}

控制檯打印結果

=====
com.huajie.thinking.in.spring.bean.definition.AnnotationBeanDefinitionDemo$Config=com.huajie.thinking.in.spring.bean.definition.AnnotationBeanDefinitionDemo$Config@3bf7ca37
=====
=====
definition-user=User{id=1, name='xwf', age=18, configFileReource=null, city=null, cities=null}
com.huajie.thinking.in.spring.ioc.overview.domain.User#0=User{id=1, name='xwf', age=18, configFileReource=null, city=null, cities=null}
user=User{id=123, name='xwf', age=18, configFileReource=null, city=null, cities=null}
=====

Config.class 類型的有一個對象,通過@Component註冊的Config

User.class 類型的有三個對象

  • 通過命名方式註冊:definition-user
  • 通過非命名的方式註冊:com.huajie.thinking.in.spring.ioc.overview.domain.User#0
  • 通過@Bean註冊:user

疑問:爲啥之前配置在 xml 中的 User 類型相關定義沒有獲取到?

因爲本例子中的 Application 爲 AnnotationConfigApplicationContext ,只關注註解相關的內容。

3.實例化 Spring Bean

Bean 實例化(Instantiation)

  • 常規方式
    • 通過構造器(配置元信息: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)

3.1 常規方式

3.1.1 通過構造器

  • xml:<bean id=“user” …> 默認是通過構造器方式
  • @Bean 在上一章已經展示過了

3.1.2 通過靜態工廠方法

我們再新建一個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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 靜態方法實例化 Bean -->
    <bean id="user-static-method" class="com.huajie.thinking.in.spring.ioc.overview.domain.User"
          factory-method="createUser"></bean>
    
</beans>

User 類中增加 createUser 靜態方法,爲了演示方便多加一個參數帶 name 的方法。

/**
 * 用戶類
 */
public class User {
    ...
    public static User createUser() {
        User user = new User();
        user.setName("static-user");
        return user;
    }
    
    //爲了演示方便,我們多加一個方法
    public static User createUser(String name) {
        User user = new User();
        user.setName(name);
        return user;
    }
    ...
}

3.1.3 通過 Bean 工廠方法

bean-instantiation-context.xml增加

    <!-- 實例(Bean) 方法實例化 Bean -->
    <bean id="user-instance-method" factory-method="createUser" factory-bean="user-factory-bean"></bean>

    <bean id="user-factory-bean" class="com.huajie.thinking.in.spring.bean.factory.DefaultUserFactory"></bean>
</beans>

新建 UserFactory 接口

/**
 * {@link User} 工廠類
 */
public interface UserFactory {
    default User createUser(){
        return User.createUser("工廠Bean-user");
    }
}

新建 DefaultUserFactory 實現類,這裏我們用 default 實現,就不需要覆蓋了

public class DefaultUserFactory implements UserFactory {
    
}

3.1.4 通過 FactoryBean

bean-instantiation-context.xml增加

    <!-- FactoryBean實例化 Bean -->
    <bean id="user-by-factory-bean" class="com.huajie.thinking.in.spring.bean.factory.UserFactoryBean"></bean>

新建 UserFactoryBean

public class UserFactoryBean implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        return User.createUser("FactoryBean-user");
    }

    @Override
    public Class<?> getObjectType() {
        return User.class;
    }
}

3.1.5 演示示例

/**
 * Bean 實例化示例
 */
public class BeanInstantiationDemo {

    public static void main(String[] args) {
        BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-instantiation-context.xml");

        User xwfUser = (User) beanFactory.getBean("user-static-method");
        User instanceUser = (User) beanFactory.getBean("user-instance-method");
        User factoryUser = (User) beanFactory.getBean("user-by-factory-bean");

        System.out.println(xwfUser);
        System.out.println(instanceUser);
        System.out.println(factoryUser);
    }
}

控制檯打印結果

User{id=null, name='static-user', age=null, configFileReource=null, city=null, cities=null}
User{id=null, name='工廠Bean-user', age=null, configFileReource=null, city=null, cities=null}
User{id=null, name='FactoryBean-user', age=null, configFileReource=null, city=null, cities=null}

結果符合預期,爲了方便,三種方式底層都是複用了 User#createUser() 方法進行實例化,當然可以自行修改每種實現。

3.2 特殊方式

3.2.1 BeanDefinitionRegistry#registerBeanDefinition

在 本章 2.2.2 Java API 配置元信息 已經展示過了

3.2.2 ServiceLoaderFactoryBean

  • 我們需要在 resources/META-INF/下面建立services 目錄

    • 原因需要看 java.util.ServiceLoader 部分源碼

    • public final class ServiceLoader<S>
          implements Iterable<S>
      {
      
          private static final String PREFIX = "META-INF/services/";
          ...
      
  • 然後再建一個實現類全類名的文件
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-VnKkEb5p-1587303192925)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200419191637910.png)]

  • 文件中寫入實現類的全類名,可以寫多個實現類。

com.huajie.thinking.in.spring.bean.factory.DefaultUserFactory
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-UZCbrPEh-1587303192926)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200419191718848.png)]

  • 新建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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userFactoryServiceLoader" class="org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean">
        <property name="serviceType" value="com.huajie.thinking.in.spring.bean.factory.UserFactory"></property>
    </bean>

</beans>

爲什麼要這麼配置呢?

這裏需要看一下ServiceLoaderFactoryBean源碼

org.springframework.beans.factory.serviceloader.AbstractServiceLoaderBasedFactoryBean#createInstance 創建實例的方法

	/**
	 * Delegates to {@link #getObjectToExpose(java.util.ServiceLoader)}.
	 * @return the object to expose
	 */
	@Override
	protected Object createInstance() {
		Assert.notNull(getServiceType(), "Property 'serviceType' is required");
		return getObjectToExpose(ServiceLoader.load(getServiceType(), this.beanClassLoader));
	}

這裏調用了getServiceType()方法獲取 serviceType 屬性,我們通過 xml 的方法來設置這個屬性。

  • 調用示例
/**
 * Bean 特殊實例化示例
 */
public class SpecialBeanInstantiationDemo {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/special-bean-instantiation-context.xml");
        // 第一種方式:這種直接通過 ClassLoader 得到 ServiceLoader
        demoServiceLoader();
        // 第二種方式:通過 ServiceLoaderFactoryBean 
        ServiceLoader<UserFactory> load = beanFactory.getBean("userFactoryServiceLoader", ServiceLoader.class);
        displayServiceLoader(load);
    }

    /**
     * jdk中的反轉控制
     */
    public static void demoServiceLoader() {
        ServiceLoader<UserFactory> load = ServiceLoader.load(UserFactory.class, Thread.currentThread().getContextClassLoader());
        displayServiceLoader(load);
    }

    public static void displayServiceLoader(ServiceLoader<UserFactory> load) {
        Iterator<UserFactory> iterator = load.iterator();
        while (iterator.hasNext()) {
            UserFactory next = iterator.next();
            System.out.println(next.createUser());
        }
    }

}

3.2.3 AutowireCapableBeanFactory#createBean

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();
        UserFactory bean = beanFactory.createBean(DefaultUserFactory.class);
        System.out.println(bean.createUser());
    }
}

4.初始化 Spring Bean

Bean 初始化(Initialization)

  • @PostConstruct 標註方法
  • 實現 InitializingBean 接口的 afterPropertiesSet() 方法
  • 自定義初始化方法
    • XML 配置:<bean init-method=“init” …/>
    • Java 註解:@Bean(initMethod=“init”)
    • Java API:AbstractBeanDefinition#setInitMethodName(String)
      • @Bean(initMethod=“init”) 這種方式,最後方法執行的調用鏈也會進到這個 API 中
  • 如果上述方法在同一個Bean初始化,順序如下
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-7ezX1vW4-1587303192929)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200304205524604.png)]

4.1 @PostConstruct 標註方法

public class DefaultUserFactory implements UserFactory {
    //1.基於 @PostConstruct 註解
    @PostConstruct
    public void init() {
        System.out.println("@PostConstruct : UserFactory 初始化....");
    }
}

4.2 @Bean(initMethod=“init”)

DefaultUserFactory 加入初始化的方法initUserFactory()

public class DefaultUserFactory implements UserFactory {
    //1.基於 @PostConstruct 註解
    @PostConstruct
    public void init() {
        System.out.println("@PostConstruct : UserFactory 初始化....");
    }
    
    public void initUserFactory() {
        System.out.println("自定義初始化 : UserFactory 初始化....");
    }
}

初始化示例 BeanInitializationDemo

/**
 * Bean 初始化示例
 */
@Configuration
public class BeanInitializationDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(BeanInitializationDemo.class);
        //啓動應用上下文
        applicationContext.refresh();
        //依賴查找
        UserFactory bean = applicationContext.getBean(UserFactory.class);
        System.out.println(bean.createUser());
        //關閉
        applicationContext.close();
    }

    @Bean(initMethod = "initUserFactory")
    public UserFactory userFactory(){
        return new DefaultUserFactory();
    }
}

4.3 實現 InitializingBean 接口的 afterPropertiesSet() 方法

public class DefaultUserFactory implements UserFactory, InitializingBean {

    //1.基於 @PostConstruct 註解
    @PostConstruct
    public void init() {
        System.out.println("@PostConstruct : UserFactory 初始化....");
    }

    public void initUserFactory() {
        System.out.println("自定義初始化 : UserFactory 初始化....");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean : UserFactory 初始化....");
    }
}

執行結果:

@PostConstruct : UserFactory 初始化....
InitializingBean : UserFactory 初始化....
自定義初始化 : UserFactory 初始化....
User{id=null, name='工廠Bean-user', age=null, configFileReource=null, city=null, cities=null}

5.延遲初始化 Spring Bean

Bean 延遲初始化(Lazy Initialization)

  • XML 配置:<bean lazy-init=“true” …/>
  • Java 註解:@Lazy(true)

加上一個@Lazy註解

    @Bean(initMethod = "initUserFactory")
    @Lazy
    public UserFactory userFactory(){
        return new DefaultUserFactory();
    }

問題:當某個 Bean 定義爲延遲初始化,那麼 Spring 容器返回的對象與非延遲的對象存在怎樣的差異?

非延遲初始化在 Spring 應用上下文啓動完成後,已經被初始化。

如果不加@Lazy執行效果:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-gRAuDQUv-1587303192930)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200419202505169.png)]
加上之後
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-hEvxVEpg-1587303192932)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200419202539990.png)]
結論:

當 Bean 定義爲延遲初始化,初始化的過程是在 Spring 應用上下文啓動之後,在本例子中通過applicationContext.getBean(UserFactory.class) 觸發 Bean 的初始化。延遲初始化和非延遲初始化在 Bean 的定義上面沒有區別,但是在依賴查找或者依賴注入有所不同。

源碼分析:

在 AbstractApplicationContext 的 refresh() 方法中,會初始化所有非延遲初始化的 singletons

  • org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

6.銷燬 Spring Bean

Bean 銷燬(Destroy)

  • @PreDestroy 標註方法
  • 實現 DisposableBean 接口的 destory 方法
  • 自定義銷燬方法
    • XML 配置:<bean destroy=“destroy” …/>
    • Java 註解:@Bean(destroy=“init”)
    • Java API:AbstractBeanDefinition#setDestroyMethodName(String)

6.1 @PreDestroy 標註方法

public class DefaultUserFactory implements UserFactory, InitializingBean {

    //1.基於 @PostConstruct 註解
    @PostConstruct
    public void init() {
        System.out.println("@PostConstruct : UserFactory 初始化....");
    }

    public void initUserFactory() {
        System.out.println("自定義初始化 : UserFactory 初始化....");
    }

    public void destroyUserFactory() {
        System.out.println("自定義銷燬 : UserFactory 銷燬....");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean : UserFactory 初始化....");
    }

    @PreDestroy
    public void preDestroy() {
        System.out.println("@PreDestroy : UserFactory 銷燬....");
    }
}

6.2 @Bean(destroy=“init”)

    @Bean(initMethod = "initUserFactory",destroyMethod = "destroyUserFactory")
    @Lazy
    public UserFactory userFactory(){
        return new DefaultUserFactory();
    }

6.3 實現 DisposableBean 接口的 destory 方法

public class DefaultUserFactory implements UserFactory, InitializingBean, DisposableBean {

    //1.基於 @PostConstruct 註解
    @PostConstruct
    public void init() {
        System.out.println("@PostConstruct : UserFactory 初始化....");
    }

    public void initUserFactory() {
        System.out.println("自定義初始化 : UserFactory 初始化....");
    }

    public void destroyUserFactory() {
        System.out.println("自定義銷燬 : UserFactory 銷燬....");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean : UserFactory 初始化....");
    }

    @PreDestroy
    public void preDestroy() {
        System.out.println("@PreDestroy : UserFactory 銷燬....");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean  : UserFactory 銷燬....");
    }
}

示例

/**
 * Bean 初始化示例
 */
@Configuration
public class BeanInitializationDemo {
    public static void main(String[] args) throws InterruptedException {
        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());
        //關閉
        System.out.println("Spring 應用上下文準備關閉");
        applicationContext.close();
        System.out.println("Spring 應用上下文已經關閉");
    }

    @Bean(initMethod = "initUserFactory",destroyMethod = "destroyUserFactory")
    @Lazy
    public UserFactory userFactory(){
        return new DefaultUserFactory();
    }
}

控制執行結果:

Spring 應用上下文已啓動
@PostConstruct : UserFactory 初始化....
InitializingBean : UserFactory 初始化....
自定義初始化 : UserFactory 初始化....
User{id=null, name='工廠Bean-user', age=null, configFileReource=null, city=null, cities=null}
Spring 應用上下文準備關閉
@PreDestroy : UserFactory 銷燬....
DisposableBean  : UserFactory 銷燬....
自定義銷燬 : UserFactory 銷燬....
Spring 應用上下文已經關閉

說明applicationContext.close()應用上下文關閉的時候進行 Bean 的銷燬。

源碼實際調用的位置:

  • org.springframework.context.support.AbstractApplicationContext#destroyBeans

7.垃圾回收

Bean 垃圾回收(GC)

  • 關閉 Spirng 容器
  • 執行 GC
  • Spring Bean 覆蓋 finalize() 方法被回調
    • 垃圾回收時,此方法會被回調

7.1 DefaultUserFactory 重寫 finalize()方法

public class DefaultUserFactory implements UserFactory, InitializingBean, DisposableBean {

    //1.基於 @PostConstruct 註解
    @PostConstruct
    public void init() {
        System.out.println("@PostConstruct : UserFactory 初始化....");
    }

    public void initUserFactory() {
        System.out.println("自定義初始化 : UserFactory 初始化....");
    }

    public void destroyUserFactory() {
        System.out.println("自定義銷燬 : UserFactory 銷燬....");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean : UserFactory 初始化....");
    }

    @PreDestroy
    public void preDestroy() {
        System.out.println("@PreDestroy : UserFactory 銷燬....");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean  : UserFactory 銷燬....");
    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println("垃圾回收");
    }
}

7.2 將 bean 對象設置爲 null,手動調用System.gc()進行垃圾回收

/**
 * Bean 初始化示例
 */
@Configuration
public class BeanInitializationDemo {
    public static void main(String[] args) throws InterruptedException {
        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);
    }

    @Bean(initMethod = "initUserFactory",destroyMethod = "destroyUserFactory")
    @Lazy
    public UserFactory userFactory(){
        return new DefaultUserFactory();
    }
}

執行結果:

Spring 應用上下文已啓動
@PostConstruct : UserFactory 初始化....
InitializingBean : UserFactory 初始化....
自定義初始化 : UserFactory 初始化....
User{id=null, name='工廠Bean-user', age=null, configFileReource=null, city=null, cities=null}
@PreDestroy : UserFactory 銷燬....
DisposableBean  : UserFactory 銷燬....
自定義銷燬 : UserFactory 銷燬....
垃圾回收

8.面試

1.如何註冊一個 Spring Bean ?

通過 BeanDefinition 和外部單體對象來註冊

  • 外部單體對象註冊
/**
 * 單體 Bean 註冊實例
 */
public class SingletonBeanRegistrationDemo {
    
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //註冊外部單例對象
        UserFactory userFactory = new DefaultUserFactory();
        ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
        //註冊外部單例對象
        beanFactory.registerSingleton("singleton-user-factory",userFactory);
        //啓動應用上下文
        applicationContext.refresh();
        //通過依賴查找的方式獲取 UserFactory
        UserFactory bean = beanFactory.getBean("singleton-user-factory", UserFactory.class);
        System.out.println(bean.createUser());
        System.out.println(userFactory==bean);
        //關閉
        applicationContext.close();
    }
    
}

2.什麼是 Spring BeanDefinition?

上一章:夯實Spring系列|第五章:Spring Bean 定義
什麼是 BeanDefinition? 和 元信息 兩個章節

簡單來說,BeanDefinition 是 Spring 中用來定義 Bean 的配置元信息接口,比如 xml 中定義 相關的信息和配置屬性,在該接口中都能找到對應的 set/get 方法。

3.Spring 容器是怎樣管理註冊 Bean?

答案在後續的章節進行詳細的討論,IoC 配置元信息的讀取和解析,依賴查找和注入,Bean生命週期管理等等。

9.參考

  • 極客時間-小馬哥《小馬哥講Spring核心編程思想》
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章