日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

java 从一个容器获取对象,如何从 Spring IoC 容器中获取对象?

發布時間:2023/12/3 javascript 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 从一个容器获取对象,如何从 Spring IoC 容器中获取对象? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前面幾篇文章主要分析了 Spring IoC 容器如何初始化,以及解析和注冊我們定義的 bean 信息。

其中,「Spring 中的 IoC 容器」對 Spring 中的容器做了一個概述,「Spring IoC 容器初始化」和「Spring IoC 容器初始化(2)」分析了 Spring 如何初始化 IoC 容器,「Spring 是如何解析 標簽的? 」分析了 Spring 如何解析 標簽及其子標簽,并注冊到 BeanFactory。

主要流程如下:

IoC 容器已經建立,而且把我們定義的 bean 信息放入了容器,那么如何從容器中獲取對象呢?

本文繼續分析。

配置及測試代碼

為便于查看,這里再貼一下 bean 配置文件和測試代碼。

配置文件 application-ioc.xml

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">

測試代碼

public class IocTests {

@Test

public void test01() {

ApplicationContext context = new ClassPathXmlApplicationContext("application-ioc.xml");

System.out.println(context.getBean("person"));

System.out.println(context.getBean("dog"));

}

}

/*

* 輸出結果:

* Person{id=12, name='Jack-12'}

* Dog{age=1}

*/

如何從容器獲取對象?

從容器中獲取對象是通過 BeanFactory#getBean 方法,它有多個重載的方法,但最終都是通過

AbstractBeanFactory#doGetBean 方法來實現的。doGetBean 方法代碼如下:

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {

// ...

protected T doGetBean(

String name, @Nullable Class requiredType, @Nullable Object[] args, boolean typeCheckOnly)

throws BeansException {

String beanName = transformedBeanName(name);

Object bean;

// 從緩存中獲取單例 bean 對象

Object sharedInstance = getSingleton(beanName);

if (sharedInstance != null && args == null) {

// ...

// 處理 FactoryBean 的場景

bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);

}

// 緩存中不存在 bean 對象

else {

if (isPrototypeCurrentlyInCreation(beanName)) {

throw new BeanCurrentlyInCreationException(beanName);

}

// bean 對象在父容器中,則從父容器中獲取 bean 對象

BeanFactory parentBeanFactory = getParentBeanFactory();

if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {

// Not found -> check parent.

String nameToLookup = originalBeanName(name);

if (parentBeanFactory instanceof AbstractBeanFactory) {

return ((AbstractBeanFactory) parentBeanFactory).doGetBean(

nameToLookup, requiredType, args, typeCheckOnly);

}

else if (args != null) {

// Delegation to parent with explicit args.

return (T) parentBeanFactory.getBean(nameToLookup, args);

}

else if (requiredType != null) {

// No args -> delegate to standard getBean method.

return parentBeanFactory.getBean(nameToLookup, requiredType);

}

else {

return (T) parentBeanFactory.getBean(nameToLookup);

}

}

// 是否只做類型檢查

if (!typeCheckOnly) {

markBeanAsCreated(beanName);

}

try {

// 獲取 BeanDefinition

RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

checkMergedBeanDefinition(mbd, beanName, args);

// 獲取依賴的 bean 對象

// 若創建一個 bean 對象時依賴其他對象,則先創建被依賴對象

String[] dependsOn = mbd.getDependsOn();

if (dependsOn != null) {

for (String dep : dependsOn) {

if (isDependent(beanName, dep)) {

// ...

}

registerDependentBean(dep, beanName);

try {

getBean(dep);

}

catch (NoSuchBeanDefinitionException ex) {

// ...

}

}

}

// 創建 scope 為 singleton(單例)的對象

if (mbd.isSingleton()) {

sharedInstance = getSingleton(beanName, () -> {

try {

return createBean(beanName, mbd, args);

}

catch (BeansException ex) {

// ...

}

});

// 處理 FactoryBean 的場景

bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

}

// 創建 scope 為 prototype 的對象

else if (mbd.isPrototype()) {

// It's a prototype -> create a new instance.

Object prototypeInstance = null;

try {

beforePrototypeCreation(beanName);

prototypeInstance = createBean(beanName, mbd, args);

}

finally {

afterPrototypeCreation(beanName);

}

// 處理 FactoryBean 的場景

bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);

}

// 創建其他類型對象

else {

String scopeName = mbd.getScope();

if (!StringUtils.hasLength(scopeName)) {

throw new IllegalStateException("No scope name defined for bean ′" + beanName + "'");

}

Scope scope = this.scopes.get(scopeName);

if (scope == null) {

throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");

}

try {

Object scopedInstance = scope.get(beanName, () -> {

beforePrototypeCreation(beanName);

try {

return createBean(beanName, mbd, args);

}

finally {

afterPrototypeCreation(beanName);

}

});

// 處理 FactoryBean 的場景

bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);

}

catch (IllegalStateException ex) {

// ...

}

}

}

catch (BeansException ex) {

cleanupAfterBeanCreationFailure(beanName);

throw ex;

}

}

// 類型檢查

if (requiredType != null && !requiredType.isInstance(bean)) {

try {

T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);

if (convertedBean == null) {

throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());

}

return convertedBean;

}

catch (TypeMismatchException ex) {

// ...

}

}

return (T) bean;

}

}

獲取 bean 對象主要就是通過這個 doGetBean 方法實現的。

該方法雖然看起來稍微有點長,但是呢,它內部的實現更長、更復雜。不過也是有跡可循的,莫慌。

本文先看下這個方法的整體流程,內部邏輯后面再慢慢研究。先上流程圖:

代碼雖然有點長,但梳理下來其實也沒那么復雜了。

這個方法主要做了什么呢?

當從容器中獲取 bean 對象時,首先從緩存中獲取。如果緩存中存在,處理 FactoryBean 的場景。

BeanFactory 和 FactoryBean,這哥倆長得很像,也有個別面試題可能會問到。

嗯……以后有機會單獨分析?

如果緩存中沒有,先去父容器獲取,前面創建 BeanFactory 時可以指定 parent 參數,就是那個。

不在父容器中,若 bean 對象依賴了其他對象,則先創建被依賴的 bean 對象,再根據 標簽的 scope 屬性去創建相應的 bean 對象。

是不是有點像我們平時寫查詢接口時、先從緩存查詢,緩存中沒的話再查詢 DB?

道理是一樣的,空間換時間。

小結

先整體,后細節。

本文先從整體上分析了如何從 Spring IoC 容器中獲取 bean 對象,內容不多,后文再詳細分解吧。

總結

以上是生活随笔為你收集整理的java 从一个容器获取对象,如何从 Spring IoC 容器中获取对象?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。