Spring Bean 的實例化_02
你的贊是我最大的動力,期待與你共同進步
在上篇文章中提到 Object sharedInstance = getSingleton(beanName);
這一行代碼,在容器初始化的時候返回的對象爲null
。 但是,今天這篇文章中,我要先來處理 sharedInstance 不爲null
的情況,看看Spring做了什麼樣的處理。對應下述流程圖中的方法:
getObjectForBeanInstance
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
/**
* 如果指定的name是工廠相關(以 & 爲前綴)
* 且beanInstance又不是 FactoryBean類型 則驗證不通過
*/
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
}
/**
* 有了bean的實例,這個實例通常是 bean 或者是 FactoryBean
* 如果是 FactoryBean 使用它創建實例,如果用戶想要直接獲取工廠實例
* 而不是工廠的 getObject() 方法對應的實例,那麼傳入的name 應該加前綴 &
*/
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
// 加載 FactoryBean
Object object = null;
if (mbd == null) {
// 嘗試從緩存中加載bean
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// beanInstance 一定是 FactoryBean
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
/**
* 將存儲Xml配置文件的 GenericBeanDefinition 轉換爲 RootBeanDefinition
* 如果指定BeanName是子 Bean 的話同時會合並父類的相關屬性
*/
mbd = getMergedLocalBeanDefinition(beanName);
}
// 是否用戶定義的,而不是應用程序本身定義的
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
複製代碼
該方法是個高頻使用的方法,無論是存緩存中獲得bean
還是根據不同的 scope
策略加載bean
。總之得到bean
的實例之後要做的第一步就是 調用這個方法來檢測一下正確性,其實就是檢測當前的bean
是否是FactoryBean
類型的bean
,如果是,那麼需要調用該bean
對應的FactoryBean
實例中的getObject()
作爲返回值。
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
// 如果是單例模式
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
/** 通過FactoryBean獲取對象*/
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
beforeSingletonCreation(beanName);
try {
/**
* 調用 ObjectFactory的後置處理器
* AbstractAutowireCapableBeanFactory#postProcessObjectFromFactoryBean()
* 儘可能保證所有的bean初始化之後都會調用註冊的
* BeanPostProcessor 的 postProcessAfterInitialization 方法
*/
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
afterSingletonCreation(beanName);
}
}
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
複製代碼
通過FactoryBean 獲取對象
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
try {
// 這裏是權限驗證,不重要
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
// 直接調用 getObject()方法
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}
複製代碼
上述代碼中最重要的一行就是 object = factory.getObject();
。可以看到,這裏的 factory
就是我們傳入的 beanInstance
。 在 getObjectForBeanInstance
中做了轉換FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
。 回到最初的起點,getBean(beanName)
通過 beanName
獲取對象,最終得到的是調用 FactoryBean
的 getObject()
方法返回的對象。
何爲 FactoryBean
FactoryBean
是一個工廠Bean
,可以生成某一個類型Bean
實例。通過使用 FactoryBean
我們可以自定義 Bean
的創建。在Spring中 FactoryBean
支持泛型。當在IOC容器中的Bean
實現了FactoryBean
後,通過getBean(String BeanName)
獲取到的Bean
對象並不是FactoryBean
的實現類對象,而是這個實現類中的getObject()
方法返回的對象。要想獲取FactoryBean
的實現類,就要getBean(&BeanName)
,在BeanName之
前加上"&"。
public interface FactoryBean<T> {
/**
* 返回由FactoryBean創建的bean實例,如果 isSingleton返回true,則該實例會放置到spring容器中單實例緩存池中
*/
@Nullable
T getObject() throws Exception;
/**
* 返回FactoryBean 創建的實例Bean的類型
*/
@Nullable
Class<?> getObjectType();
/**
* 用來判斷有FactoryBean創建的是bean的作用域
*/
default boolean isSingleton() {
return true;
}
}
複製代碼
上述的 FactoryBean<T>
接口, 就是Spring中定義好的接口。從上述接口中的方法我們可以看出:FactoryBean
中定義了一個Spring Bean
的很重要的三個特性:是否單例、Bean
類型、Bean
實例。下面我們就簡單的使用一下 FactoryBean
。
FactoryBean接口的實現類
@Component
public class FactoryBeanTest implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
複製代碼
在上面的重寫方法getObject()
方法中,我採用了 new
的方式來控制 Bean
的創建過程。
對象類
public class User {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
複製代碼
測試方法
public class FactoryBeanTest {
public static void main(String[] args) {
ApplicationContext ann = new AnnotationConfigApplicationContext(MyConfig.class);
// 方式一
FactoryBeanTest beanTest = ann.getBean(FactoryBeanTest.class);
System.out.println(beanTest);
// 方式二
Object user = ann.getBean("factoryBeanTest");
System.out.println(user);
// 方式三
Object user2 = ann.getBean("&factoryBeanTest");
System.out.println(user2);
}
}
複製代碼
程序運行結果如下: 從結果我們可以看出,通過類型 FactoryBeanTest.class
與通過使用 "&"+beanName 的方式(&factoryBeanTest
);獲取到的對象 是同一個,這個對象是就是 FactoryBean
的實現類。而通過beanName
獲取到的對象,就是通過 FactoryBean
中 getObject()
方法返回的對象。