溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Spring容器怎么配置

發(fā)布時(shí)間:2021-12-07 13:39:18 來(lái)源:億速云 閱讀:152 作者:iii 欄目:大數(shù)據(jù)

這篇文章主要講解了“Spring容器怎么配置”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“Spring容器怎么配置”吧!

1.容器概覽

Spring 中的 Ioc 容器,我們可以大致上分為兩種:

  • BeanFactory
  • ApplicationContext
 

1.1 BeanFactory

BeanFactory 是最最基礎(chǔ)的 IoC 容器,它提供了一個(gè) IoC 容器所需的基本功能。在本系列前面文章中我們所用到的 XmlBeanFactory 就是它的實(shí)現(xiàn)之一。

BeanFactory 默認(rèn)采用延遲初始化策略,即當(dāng)容器啟動(dòng)時(shí),并未完成 Bean 的初始化,只有當(dāng)調(diào)用到該 Bean 的實(shí)例時(shí),才會(huì)完成其初始化操作,并進(jìn)行依賴注入。

例如如下代碼:

XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
User user = factory.getBean(User.class);
 

當(dāng)?shù)谝恍写a執(zhí)行的時(shí)候,beans.xml 中配置的 User 對(duì)象并未進(jìn)行初始化,只有當(dāng)?shù)诙?getBean 方法調(diào)用時(shí),User 對(duì)象才進(jìn)行了初始化操作。

這樣設(shè)計(jì)的好處是容器啟動(dòng)速度快,因?yàn)橐龅氖虑楸容^少。

 

1.2 ApplicationContext

ApplicationContext 是在 BeanFactory 的基礎(chǔ)上實(shí)現(xiàn)的,BeanFactory 的功能它都有,算是一種高級(jí)容器。

ApplicationContext 在 BeanFactory 的基礎(chǔ)上提供了事件發(fā)布、國(guó)際化等功能。

同時(shí),ApplicationContext 和 BeanFactory 還有一個(gè)很大的不同在于 ApplicationContext 在容器啟動(dòng)時(shí),就會(huì)完成所有 Bean 的初始化,這也就以為著容器啟動(dòng)時(shí)間較長(zhǎng),并且對(duì)系統(tǒng)資源要求也較高。

例如如下一段代碼:

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
 

當(dāng)這段代碼執(zhí)行時(shí),beans.xml 中配置的 User 對(duì)象就會(huì)完成初始化操作。

 

2.BeanFactory

BeanFactory 的繼承關(guān)系圖太大了,放在文章里顯示不全。小伙伴們可以在 IDEA 中自行查看,我這里就不貼圖出來(lái)了。

我們來(lái)看下 BeanFactory 的源碼:

public interface BeanFactory {
 String FACTORY_BEAN_PREFIX = "&";
 Object getBean(String name) throws BeansException;
 <T> T getBean(String name, Class<T> requiredType) throws BeansException;
 Object getBean(String name, Object... args) throws BeansException;
 <T> T getBean(Class<T> requiredType) throws BeansException;
 <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
 <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
 <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
 boolean containsBean(String name);
 boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
 boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
 boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
 boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
 @Nullable
 Class<?> getType(String name) throws NoSuchBeanDefinitionException;
 @Nullable
 Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;
 String[] getAliases(String name);
}
 

可以看到,BeanFactory 主要提供了一些和 Bean 相關(guān)的查詢方法。

FACTORY_BEAN_PREFIX

這是定義的 FactoryBean 前綴,具體參考Spring 源碼第 9 篇,深入分析 FactoryBean。

getBean

getBean 方法一共有五個(gè)。

在獲取一個(gè) Bean 的時(shí)候,可以指定 Bean 的名字,也可以指定 Bean 的類型,也可以同時(shí)指定,這個(gè)好理解。

還有兩個(gè)重載的方法里邊有一個(gè) args 參數(shù),這個(gè)可能有的小伙伴們沒(méi)怎么用過(guò),我這里稍微解釋下。

其實(shí)我們大概能猜出來(lái) args 是獲取 Bean 時(shí)所需要的參數(shù),如果使用該方法給 Bean 配置參數(shù),需要將 Bean 的 scope 設(shè)置為 prototype,這就意味著每次獲取 Bean 的時(shí)候,才去進(jìn)行 Bean 的初始化(否則配置的參數(shù)無(wú)法生效)。

松哥通過(guò)一個(gè)例子來(lái)給大家演示下。

首先我們提供一個(gè) User 類:

public class User {
    private String username;
    private Integer age;

    public User(String username, Integer age) {
        this.username = username;
        this.age = age;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", age=" + age +
                '}';
    }
}
 

可以看到,User 類只有一個(gè)有參的構(gòu)造方法。

接下來(lái)我們?cè)?XML 文件中進(jìn)行配置,XML 文件中需要配置 User 類的構(gòu)造方法參數(shù),我們可以配置為 null,同時(shí)記得設(shè)置 scope 屬性為 prototype。

<bean class="org.javaboy.spring_demo04.User" id="user1" scope="prototype">
    <constructor-arg name="username"><null></null></constructor-arg>
    <constructor-arg name="age"><null></null></constructor-arg>
</bean>
 

最后再通過(guò)如下方式加載 Bean:

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
User user = ctx.getBean(User.class,new Object[]{"javaboy",99});
System.out.println("user = " + user);
 

最終打印結(jié)果如下:

user = User{username='javaboy', age=99}
 

可以看到,為 Bean 配置的參數(shù)都生效了。

getBeanProvider

方法用于獲取指定 Bean 的提供者,可以看到它返回的是一個(gè) ObjectProvider,該類擴(kuò)展自 ObjectFactory,從 Spring4.3 時(shí)開(kāi)始提供。

可能大家對(duì) ObjectProvider 接觸較少,這里我也稍微說(shuō)一下。

先來(lái)看 ObjectFactory:

@FunctionalInterface
public interface ObjectFactory<T> {
 T getObject() throws BeansException;
}
 

ObjectFactory 有點(diǎn)類似于我們?cè)?Spring 源碼第 9 篇,深入分析 FactoryBean 一文中所講的 FactoryBean。

不同的是,ObjectFactory 中只有一個(gè) getObject 方法,該方法可以返回 Object 實(shí)例。ObjectFactory 與 FactoryBean 相似,但是后者的實(shí)現(xiàn)通常是在 BeanFactory 中定義為 SPI 實(shí)例,而此類的實(shí)現(xiàn)通常是作為 API 注入給其他 Bean。

再來(lái)看 ObjectProvider(部分):

public interface ObjectProvider<T> extends ObjectFactory<T>, Iterable<T> {
    //返回指定類型的 bean, 如果容器中不存在, 拋出 NoSuchBeanDefinitionException 異常;如果容器中有多個(gè)此類型的 bean, 拋出 NoUniqueBeanDefinitionException 異常
 T getObject(Object... args) throws BeansException;
    //如果指定類型的 bean 注冊(cè)到容器中, 返回 bean 實(shí)例, 否則返回 null
 @Nullable
 T getIfAvailable() throws BeansException;
    //如果指定類型的 bean 在容器中只有一個(gè) bean, 返回 bean 實(shí)例, 如果不存在則返回 null;如果容器中有多個(gè)此類型的 bean, 拋出 NoUniqueBeanDefinitionException 異常
 @Nullable
 T getIfUnique() throws BeansException;
    // Spring5.0 之后提供,返回指定類型 Bean 的迭代器
 @Override
 default Iterator<T> iterator() {
  return stream().iterator();
 }
    //轉(zhuǎn)為 Stream
 default Stream<T> stream() {
  throw new UnsupportedOperationException("Multi element access not supported");
 }
 default Stream<T> orderedStream() {
  throw new UnsupportedOperationException("Ordered element access not supported");
 }
}
 

這是 ObjectProvider 的源碼,那么它有什么用呢?松哥舉個(gè)簡(jiǎn)單例子。

在 Spring4.3 之前。

假設(shè)我有一個(gè) UserDao,如下:

@Repository
public class UserDao {
}
 

還有一個(gè) UserService,如下:

@Service
public class UserService {
    private UserDao userDao;

    @Autowired
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public String toString() {
        return "UserService{" +
                "userDao=" + userDao +
                '}';
    }
}
 

在 UserService 中注入 UserDao 時(shí),必須明確給出 @Autowired 注解。

這看起來(lái)不夠優(yōu)雅!

從 Spring4.3 開(kāi)始,在 UserService 中注入 UserDao 時(shí),如果構(gòu)造方法只有一個(gè)參數(shù),可以不用添加 @Autowired 注解,像下面這樣:

@Service
public class UserService {
    private UserDao userDao;

    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public String toString() {
        return "UserService{" +
                "userDao=" + userDao +
                '}';
    }
}
 

但是如果 UserDao 為 null,則會(huì)導(dǎo)致 UserService 初始化失敗,通過(guò) ObjectProvider 可以解決,如下:

@Service
public class UserService {
    private UserDao userDao;

    public UserService(ObjectProvider<UserDao> userDao) {
        this.userDao = userDao.getIfUnique();
    }

    @Override
    public String toString() {
        return "UserService{" +
                "userDao=" + userDao +
                '}';
    }
}
 

這就是 ObjectProvider。好啦,扯遠(yuǎn)了,我們回到 BeanFactory 繼續(xù)看它里邊的方法。

containsBean

判斷容器中是否包含某個(gè) Bean。

isSingleton

判斷某個(gè) Bean 是否是單例的。

isPrototype

判斷某個(gè) Bean 是否是 prototype。

isTypeMatch

返回指定名稱的 Bean 是否匹配指定的類型。

getType

返回指定名稱的 Bean 對(duì)應(yīng)的數(shù)據(jù)類型。

getAliases

返回 Bean 的別名。

這就是 BeanFactory 中定義的所有方法,可以看到,基本上都是容器相關(guān)的查詢方法,接下來(lái)將在 BeanFactory 的各種實(shí)現(xiàn)類中,對(duì)其進(jìn)行實(shí)現(xiàn)。

 

3.二級(jí)接口

BeanFactory 作為 IoC 容器中最頂層的定義,沒(méi)有繼承任何接口,我們可以稱之為一級(jí)接口,直接繼承自 BeanFactory 的接口有三個(gè),我們稱之為二級(jí)接口。

 

3.1 HierarchicalBeanFactory

HierarchicalBeanFactory 繼承自 BeanFactory,定義了工廠分層,在其基礎(chǔ)上又?jǐn)U展了兩個(gè)方法:

public interface HierarchicalBeanFactory extends BeanFactory {
 BeanFactory getParentBeanFactory();
 boolean containsLocalBean(String name);
}
 
  • getParentBeanFactory 方法返回 Bean 工廠的父工廠,實(shí)現(xiàn)了工廠分層。
  • containsLocalBean 方法則判斷本地工廠是否包含這個(gè) Bean。

HierarchicalBeanFactory 有一個(gè)接口 ConfigurableBeanFactory,ConfigurableBeanFactory 接口繼承自 HierarchicalBeanFactory 和 SingletonBeanRegistry,其中 SingletonBeanRegistry 這個(gè)接口定義了對(duì)單例 Bean 的定義以及獲取方法。也就是說(shuō),ConfigurableBeanFactory 中兼具工廠分層和單例處理功能。同時(shí),在 HierarchicalBeanFactory 中 getParentBeanFactory 所 get 到的對(duì)象,也是在 ConfigurableBeanFactory 中完成配置。

 

3.2 AutowireCapableBeanFactory

AutowireCapableBeanFactory 繼承自 BeanFacotory,它擴(kuò)展了自動(dòng)裝配的功能。

public interface AutowireCapableBeanFactory extends BeanFactory {
 int AUTOWIRE_NO = 0;
 int AUTOWIRE_BY_NAME = 1;
 int AUTOWIRE_BY_TYPE = 2;
 int AUTOWIRE_CONSTRUCTOR = 3;
 @Deprecated
 int AUTOWIRE_AUTODETECT = 4;
 String ORIGINAL_INSTANCE_SUFFIX = ".ORIGINAL";
 <T> T createBean(Class<T> beanClass) throws BeansException;
 Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
 void autowireBean(Object existingBean) throws BeansException;
 Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
 void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck) throws BeansException;
 Object configureBean(Object existingBean, String beanName) throws BeansException;
 Object initializeBean(Object existingBean, String beanName) throws BeansException;
 void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException;
 Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException;
 Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException;
 void destroyBean(Object existingBean);
 <T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType) throws BeansException;
 Object resolveBeanByName(String name, DependencyDescriptor descriptor) throws BeansException;
 @Nullable
 Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException;
 @Nullable
 Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
   @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;
}
 

首先通過(guò)五個(gè)常量定義了五種不同的裝配策略,分別是:不自動(dòng)裝配、通過(guò)名稱自動(dòng)裝配、通過(guò)類型自動(dòng)裝配、通過(guò)構(gòu)造方法自動(dòng)裝配,還有一個(gè)過(guò)期的常量。

ORIGINAL_INSTANCE_SUFFIX 則是初始化實(shí)例給定名稱時(shí)約定的后綴,該后綴會(huì)添加到類的全路徑后面,例如:com.mypackage.MyClass.ORIGINAL

createBean 方法用來(lái)創(chuàng)建 Bean 實(shí)例;autowire* 方法則用來(lái)完成自動(dòng)裝配;configureBean 用來(lái)配置 Bean;initializeBean 用來(lái)初始化 BeanapplyBeanPropertyValues 將指定 beanBeanDefinition 應(yīng)用到一個(gè)已經(jīng)存在的 Bean 上;applyBeanPostProcessorsBeforeInitialization/applyBeanPostProcessorsAfterInitialization 調(diào)用 Bean 的后置處理器;destroyBean 方法用來(lái)銷毀 Beanresolve* 方法用來(lái)解析 Bean。

 

3.3 ListableBeanFactory

ListableBeanFactory 繼承自 BeanFacotory,該接口可以列出工廠可以生產(chǎn)的所有實(shí)例。

public interface ListableBeanFactory extends BeanFactory {
 boolean containsBeanDefinition(String beanName);
 int getBeanDefinitionCount();
 String[] getBeanDefinitionNames();
 String[] getBeanNamesForType(ResolvableType type);
 String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit);
 String[] getBeanNamesForType(@Nullable Class<?> type);
 String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit);
 <T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException;
 <T> Map<String, T> getBeansOfType(@Nullable Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException;
 String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType);
 Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;
 @Nullable
 <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType) throws NoSuchBeanDefinitionException;
}
 
  • containsBeanDefinition:判斷容器是否包含某一個(gè) Bean 的定義。
  • getBeanDefinitionCount:獲取 BeanDefinition 數(shù)量。getBeanDefinitionCount 和 containsBeanDefinition 執(zhí)行效率較低,慎用。
  • getBeanDefinitionNames:獲取所有 Bean 的名字。
  • getBeanNamesForType:返回指定類型的 BeanName。
  • getBeansOfType:返回指定類的名稱和 Bean Map(相同類型的 Bean 可能存在多種實(shí)例)。
  • getBeanNamesForAnnotation:根據(jù)注解獲取指定的 BeanName。
  • getBeansWithAnnotation:根據(jù)注解獲取指定的 BeanName 以及 Bean Map。
  • findAnnotationOnBean:根據(jù)指定 beanName 和注解類型查找指定的 Bean。

ListableBeanFactory 有一個(gè)實(shí)現(xiàn)接口 ConfigurableListableBeanFactory,這是以上所介紹接口的集大成者,ConfigurableListableBeanFactory 繼承自 ListableBeanFactory、AutowireCapableBeanFactory 以及 ConfigurableBeanFactory,可以看到,三個(gè)二級(jí)接口功能集于一身,它包含了 BeanFactory 體系目前的所有方法。這些方法都在 DefaultListableBeanFactory 中進(jìn)行實(shí)現(xiàn),也就是我們前面所講的 Spring 源碼第六彈!松哥和大家聊聊容器的始祖 DefaultListableBeanFactory。

這就是直接繼承自 BeanFactory 的三個(gè)接口。

感謝各位的閱讀,以上就是“Spring容器怎么配置”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)Spring容器怎么配置這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI