1. 程式人生 > 其它 >關於Spring Bean建立的一些問題

關於Spring Bean建立的一些問題

技術標籤:SpringspringSpring單例Bean建立

最近看到了邏輯大概像下面這樣的程式碼:

import org.springframework.stereotype.Component;
import vip.mycollege.spring.aware.ApplicationHolder;

@Component
public class DataComponent {

    private static DataComponent instance;

    public static DataComponent getInstance() {
        if
(instance == null) { createInstance(); } return instance; } private static synchronized void createInstance() { if (instance != null) { return; } instance = ApplicationHolder.getBean(DataComponent.class); } public void
initData() { System.out.println("init data"); } public void destroy() { System.out.println("destroy..."); } }

其中ApplicationHolder獲取bean是通過Spring的ApplicationContext。

看著是不是有點眼熟,是不是像建立類的單例模式,還是使用雙重檢查方式。

你能看出哪些問題?

最重要的問題是:從註解和程式碼邏輯我們可以看出,這個Bean是通過Spring管理的。

Spring建立Bean它本身預設就是單例,就是使用@Lazy懶載入也一樣,除非使用@Scope(“prototype”)。

所以完全沒有必要考慮是否為空的問題,直接使用ApplicationContext.getBean(DataComponent.class)就可以,如果為null,Spring自己會去建立,除非Bean不存在,可以通過ApplicationContextAware注入。

Spring建立Bean已經考慮了執行緒安全問題,下面是DefaultSingletonBeanRegistry通過三級快取獲取Bean的邏輯。

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // Quick check for existing instance without full singleton lock
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        singletonObject = this.earlySingletonObjects.get(beanName);
        if (singletonObject == null && allowEarlyReference) {
            synchronized (this.singletonObjects) {
                // Consistent creation of early reference within full singleton lock
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    singletonObject = this.earlySingletonObjects.get(beanName);
                    if (singletonObject == null) {
                        ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                        if (singletonFactory != null) {
                            singletonObject = singletonFactory.getObject();
                            this.earlySingletonObjects.put(beanName, singletonObject);
                            this.singletonFactories.remove(beanName);
                        }
                    }
                }
            }
        }
    }
    return singletonObject;
}

計算使用Spring管理Bean了,並且使用註解方式,那麼初始化方法、銷燬方法就加上註解,不要手動去呼叫。我之所以發現這個問題就是因為,他們沒有呼叫初始化方法,報空指標才注意到。

我們對這個類稍微改造一下:

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Component
public class DataComponent implements ApplicationContextAware {

    private static ApplicationContext applicationContext;
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        DataComponent.applicationContext = applicationContext;
    }

    public static DataComponent getInstance() {
        return applicationContext.getBean(DataComponent.class);
    }

    @PostConstruct
    public void initData() {
        System.out.println("init data");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("destroy...");
    }
}

@PostConstuct方法執行是在afterPropertiesSet之前,下面是相關初始化方法大致先後順序:

  1. @PostConstuct方法
  2. afterPropertiesSet
  3. init-method

如果,對這些還不太清楚可以看一下下面兩篇文章:

SpringBean生命週期
Spring核心流程梳理