概要
これまでに、Spring による XML 構成ファイルの解析を分析し、分析された情報を BeanDefinition にまとめて、対応する BeanDefinitionRegistry に保存して登録しました。この時点で、Spring IOC の初期化が完了します。次に、Bean のロードについて調べます。
ビーンファクトリー
明示的または暗黙的に を呼び出すとgetBean()
、Bean のロードフェーズがトリガーされます。次のように:
public class AppTest {
@Test
public void MyTestBeanTest() {
BeanFactory bf = new XmlBeanFactory( new ClassPathResource("spring-config.xml"));
MyTestBean myTestBean = (MyTestBean) bf.getBean("myTestBean");
}
}
このメソッドは BeanFactory インターフェイスで定義されていることがわかります。次の図に示すように、BeanFactory アーキテクチャを見てみましょう。
上の図から次のことがわかります。
(1) BeanFactory はメインインターフェイスとしてインターフェイスを継承せず、一時的に第 1 レベルインターフェイスと呼ばれます。
(2) 3 つのサブインターフェースはそれを継承し、その機能を強化します。これら 3 つのサブインターフェイスはセカンダリ インターフェイスと呼ばれます。
(3) ConfigurableBeanFactory は、第 3 レベルのインターフェースと呼ぶことができます。第 2 レベルのインターフェース HierarchicalBeanFactory は再び拡張され、別の外部インターフェース SingletonBeanRegistry も継承しています。
(4) ConfigurableListableBeanFactory は、上記のすべてのインターフェイスを継承し、包括的な、第 4 レベルのインターフェイスと呼ばれる、より強力なインターフェイスです。(これらの 4 レベルのインターフェイスは、BeanFactory の基本的なインターフェイス システムです。
(5) AbstractBeanFactory は、抽象クラスとして、3 レベルのインターフェイス ConfigurableBeanFactory のほとんどの機能を実装します。
(6) AbstractAutowireCapableBeanFactory も抽象クラスであり、AbstractBeanFactory を継承し、さらに 2 番目のインターフェイス AutowireCapableBeanFactory を実装します。
(7) DefaultListableBeanFactory は AbstractAutowireCapableBeanFactory を継承し、最も強力な 4 レベル インターフェイス ConfigurableListableBeanFactory を実装し、抽象クラスではない外部インターフェイス BeanDefinitionRegistry を実装します。
(8) 最後に、最も強力な XmlBeanFactory があります。これは、DefaultListableBeanFactory から継承し、いくつかの関数を書き換えて、それ自体をより強力にします。
意味
Factory で終わる BeanFactory は、 Bean のファクトリーの生成と管理を担当するファクトリー クラス (インターフェイス) であることを示します。Spring では、BeanFactory は IOC コンテナのコア インターフェイスであり、その役割には、アプリケーション内のオブジェクトのインスタンス化、検索、構成、およびこれらのオブジェクト間の依存関係の確立が含まれます。BeanFactory は単なるインターフェイスであり、IOC コンテナの特定の実装ではありませんが、Spring コンテナは DefaultListableBeanFactory やオブジェクト間の依存関係など、多くの実装を提供します。XmlBeanFactory クラスは、この XML 構成メタデータを保持し、それを使用して完全に構成可能なシステムまたはアプリケーションを構築します。
BeanFactory は Spring IOC コンテナの元祖であり、IOC コンテナの基本インターフェースであり、すべてのコンテナはそれを継承して実装しています。これはそのステータスを示します。BeanFactory は、最も基本的な IOC コンテナ機能、つまりすべてのコンテナが少なくとも実装する必要がある標準を提供します。
XmlBeanFactory は、最も基本的な IOC コンテナー関数のみを提供します。XMLBeanFactory は、DefaultListableBeanFactory を継承します。DefaultListableBeanFactory には、実際には、基本的な IOC コンテナの重要な機能がすべて含まれており、完全な IOC コンテナです。
ApplicationContext には BeanFactory のすべての機能が含まれており、通常は BeanFactory よりも優先することが推奨されます。
BeanFactory アーキテクチャは、どのような工場でどのような製品が生産されるかという、ファクトリ メソッドの典型的なパターンです。BeanFactory は最も基本的な抽象ファクトリですが、他の IOC コンテナはそれぞれの Bean 定義メソッドに対応する特定のファクトリにすぎません。しかし同時に、他のコンテナも拡張され、さまざまな特定のシナリオに特定のサービスを提供しています。次のように:
Resource resource = new FileSystemResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);
ClassPathResource resource = new ClassPathResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {
"applicationContext.xml"});
BeanFactory factory = (BeanFactory) context;
それから、getBean(String beanName) メソッドを使用して Bean インスタンスを取得します。BeanFactory によって提供されるメソッドは非常に単純で、顧客が呼び出すことができるメソッドは 6 つだけです。
- boolean containsBean(String beanName) は、ファクトリに指定された名前の Bean 定義が含まれているかどうかを判断し、含まれている場合は true を返します。
- Object getBean(String) 指定された名前で登録された Bean インスタンスを返します。Bean の設定に従って、シングルトン モードの場合は共有インスタンスが返され、それ以外の場合は新しいインスタンスが返されます。指定された Bean が見つからない場合、このメソッドは例外をスローすることがあります。
- Object getBean(String, Class) 指定された名前で登録され、指定されたクラス タイプに変換された Bean インスタンスを返します。
- Class getType(String name) は、指定された名前の Bean のクラスを返します。指定された Bean インスタンスが見つからない場合、NoSuchBeanDefinitionException 例外は除去されます。
- boolean isSingleton(String) は、指定された名前の Bean 定義がシングルトン モードであるかどうかを判断します。
- String[] getAliases(String name) は、指定された Bean 名のすべてのエイリアスを返します。
package org.springframework.beans.factory;
import org.springframework.beans.BeansException;
public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
boolean containsBean(String name);
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException;
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
String[] getAliases(String name);
}
ファクトリービーン
通常の状況では、Spring は用<bean>
リフレクション機構で使用される class 属性を使用して、Bean をインスタンス化する実装クラスを指定します。場合によっては、Bean のインスタンス化プロセスがより複雑になります。従来の方法に従う場合は、<bean>
大量の構成情報。設定方法の自由度は限られていますが、この場合はコーディングすることで簡単に解決できる可能性があります。Springではこの目的のために org.springframework.bean.factory.FactoryBean というファクトリクラスのインターフェースを提供しており、ユーザーはこのインターフェースを実装することでBeanのインスタンス生成ロジックをカスタマイズすることができる。FactoryBean インターフェイスは Spring フレームワークで重要な位置を占めており、Spring 自体は 70 以上の FactoryBean 実装を提供します。これらは、一部の複雑な Bean のインスタンス化の詳細を隠し、上位層のアプリケーションに利便性をもたらします。Spring 3.0 から、FactoryBean はジェネリックスをサポートし始めます。つまり、インターフェイス宣言がFactoryBean<T>
フォームに変更されます。
末尾がBeanなのでBeanです。通常のBeanとの違いは、FactoryBeanインタフェースを実装したBeanであることです。BeanのIDに従ってBeanFactoryから取得するのは、実際にはFactoryBeanのgetObject()で返されるオブジェクトです。 FactoryBean 自体ではなく、FactoryBean オブジェクトを取得したい場合は、ID の前に & 記号を追加して取得してください。
package org.springframework.beans.factory;
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
boolean isSingleton();
}
次の 3 つのメソッドもこのインターフェイスで定義されています。
- T getObject() : FactoryBean によって作成された Bean インスタンスを返します。isSingleton() が true を返した場合、インスタンスは Spring コンテナ内の単一インスタンス キャッシュ プールに配置されます。
- boolean isSingleton() : FactoryBean によって作成された Bean インスタンスのスコープがシングルトンかプロトタイプかを返します。
- Class getObjectType() : FactoryBean によって作成された Bean タイプを返します。
<bean>
設定ファイルのclass属性で設定した実装クラスがFactoryBeanの場合、getBean()メソッドで返されるのはFactoryBeanそのものではなく、FactoryBean#と同等のFactoryBean#getObject()メソッドで返されるオブジェクトです。 getObject() は getBean (
例: 従来の方法を使用して次の Car を構成する場合<bean>
、 Car の各属性は<property>
要素タグに対応します。
public class Car {
private int maxSpeed ;
private String brand ;
private double price ;
//get//set 方法
}
FactoryBean を使用して実装すると、より柔軟になります。次の例では、カンマ区切りを使用して、Car のすべてのプロパティの設定値を一度に指定します。
import org.springframework.beans.factory.FactoryBean;
public class CarFactoryBean implements FactoryBean<Car> {
private String carInfo ;
public Car getObject() throws Exception {
Car car = new Car();
String[] infos = carInfo.split(",");
car.setBrand(infos[0]);
car.setMaxSpeed(Integer.valueOf(infos[1]));
car.setPrice(Double.valueOf(infos[2]));
return car;
}
public Class<Car> getObjectType(){
return Car.class ;
}
public boolean isSingleton(){
return false ;
}
public String getCarInfo(){
return this.carInfo;
}
//接受逗号分割符设置属性信息
public void setCarInfo (String carInfo){
this.carInfo = carInfo;
}
}
この CarFactoryBean を使用すると、次のカスタム構成メソッドを使用して、構成ファイルで CarBean を構成できます。
<bean d="car"class="com.dabin.spring.CarFactoryBean" P:carInfo="大奔,600,1000000"/>
getBean("car") を呼び出すと、Spring はリフレクション メカニズムを通じて CarFactoryBean が FactoryBean インターフェイスを実装していることを検出し、このとき Spring コンテナはインターフェイス メソッド CarFactoryBean#getObject() メソッドを呼び出して返します。CarFactoryBean のインスタンスを取得する場合は、getBean(beanName) メソッドを使用するときに、beanName の前に「&」プレフィックスを追加する必要があります。たとえば、getBean("&car"); のようになります。
豆を入手する
次に Bean の読み込みフェーズに戻ります。明示的または暗黙的に を呼び出すとgetBean()
、Bean の読み込みフェーズがトリガーされます。次のように:
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
内部呼び出しdoGetBean()
メソッド。このメソッドのコードは比較的長いため、辛抱強く読んでください。
@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
//获取 beanName,这里是一个转换动作,将 name 转换为 beanName
final String beanName = transformedBeanName(name);
Object bean;
/*
*检查缓存中的实例工程是否存在对应的实例
*为何要优先使用这段代码呢?
*因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖
*spring创建bean的原则是在不等bean创建完就会将创建bean的objectFactory提前曝光,即将其加入到缓存中,一旦下个bean创建时依赖上个bean则直接使用objectFactory
*直接从缓存中或singletonFactories中获取objectFactory
*就算没有循环依赖,只是单纯的依赖注入,如B依赖A,如果A已经初始化完成,B进行初始化时,需要递归调用getBean获取A,这是A已经在缓存里了,直接可以从这里取到
*/
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//返回对应的实例,有些时候并不是直接返回实例,而是返回某些方法返回的实例
//这里涉及到我们上面讲的FactoryBean,如果此Bean是FactoryBean的实现类,如果name前缀为"&",则直接返回此实现类的bean,如果没有前缀"&",则需要调用此实现类的getObject方法,返回getObject里面真是的返回对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
//只有在单例的情况下才会解决循环依赖
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
//尝试从parentBeanFactory中查找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 {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
//如果不是仅仅做类型检查,则这里需要创建bean,并做记录
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
//将存储XML配置文件的GenericBeanDefinition转换为RootBeanDefinition,同时如果存在父bean的话则合并父bean的相关属性
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
//如果存在依赖则需要递归实例化依赖的bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// 单例模式
// 实例化依赖的bean后对bean本身进行实例化
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 原型模式
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);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// 从指定的 scope 下创建 bean
else {
String scopeName = mbd.getScope();
final 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);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
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) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
コードが長く、処理ロジックもかなり複雑なので、以下に分解して説明します。
beanName を取得する
final String beanName = transformedBeanName(name);
ここで渡されるのは名前であり、必ずしも beanName であるとは限りません。aliasName または FactoryBean (「&」プレフィックス付き) の場合もあります。そのため、ここでは主に次のように、名前を変換するメソッドを呼び出す必要がありますtransformedBeanName()
。
protected String transformedBeanName(String name) {
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
// 去除 FactoryBean 的修饰符
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
String beanName = name;
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
return beanName;
}
// 转换 aliasName
public String canonicalName(String name) {
String canonicalName = name;
// Handle aliasing...
String resolvedName;
do {
resolvedName = this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
主な処理プロセスには 2 つのステップが含まれます。
- FactoryBean 修飾子を削除します。名前の先頭に「&」が付いている場合、「&」は削除され、たとえば に
name = "&studentService"
なりますname = "studentService"
。 - 指定された別名で表される最終的な BeanName を取得します。これは主に beanName を周期的に取得する処理で、たとえば、エイリアス A が B という名前の Bean を指している場合は B が返され、エイリアス A がエイリアス B を指していて、エイリアス B が C という名前の Bean を指している場合は C が返されます。
キャッシュからシングルトン Bean を取得する
シングルトンは、同じ Spring コンテナ内で 1 回だけ作成されます。その後の Bean の取得は、シングルトン キャッシュから直接取得されます。もちろん、ここではロードのみを試みます。最初はキャッシュからのロードを試み、次に、singletonFactory からのロードを試みます。単一の Bean を作成するときに依存関係の注入が行われるため、再度、依存関係を作成するときに循環依存関係を回避するために、Spring の Bean 作成原則では、Bean の ObjectFactory を作成し、Bean が作成される前の早い段階でそれをキャッシュに追加します。次の Bean が作成されます。作成時に前の Bean に依存する必要がある場合は、ObjectFactory を直接使用します。循環依存関係がなくても、単純な依存関係注入です。たとえば、B は A に依存します。A が初期化されている場合、 、B が初期化されるとき、A を取得するために getBean を再帰的に呼び出す必要があります。これは A です。これはすでにキャッシュ内にあるので、ここから直接取得できます。次に、シングルトン Bean を取得し、メソッド本体を入力するメソッド getSingleton(beanName) を見てみましょう。
@Override
@Nullable
public Object getSingleton(String beanName) {
//参数true是允许早期依赖
return getSingleton(beanName, true);
}
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//检查缓存中是否存在实例,这里就是上面说的单纯的依赖注入,如B依赖A,如果A已经初始化完成,B进行初始化时,需要递归调用getBean获取A,这是A已经在缓存里了,直接可以从这里取到
Object singletonObject = this.singletonObjects.get(beanName);
//如果缓存为空且单例bean正在创建中,则锁定全局变量,为什么要判断bean在创建中呢?这里就是可以判断是否循环依赖了。
//A依赖B,B也依赖A,A实例化的时候,发现依赖B,则递归去实例化B,B发现依赖A,则递归实例化A,此时会走到原点A的实例化,第一次A的实例化还没完成,只不过把实例化的对象加入到缓存中,但是状态还是正在创建中,由此回到原点发现A正在创建中,由此可以判断是循环依赖了
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//如果此bean正在加载,则不处理
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//当某些方法需要提前初始化的时候会直接调用addSingletonFactory把对应的ObjectFactory初始化策略存储在singletonFactory中
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//使用预先设定的getObject方法
singletonObject = singletonFactory.getObject();
记录在缓存中,注意earlySingletonObjects和singletonFactories是互斥的
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
次に、このメソッドをソースコードに基づいてわかりやすく整理していきます このメソッドは、まずsingletonObjectsからインスタンスを取得しようとしますが、取得できない場合は、earlySingletonObjectsから取得します。取得したら、singletonFactories. 対応する ObjectFactory から BeanName を取得しようとし、この ObjectFactory の getObject メソッドを呼び出して Bean を作成し、それを EarlySingletonObjects に配置し、singletonFactoryes から ObjectFactory を削除すると、後続のすべてのメモリ操作は、次の目的でのみ使用されます。循環依存関係の検出、つまり、allowEarlyReference は、true の場合にのみ使用されます。
これには、Bean を格納するためのさまざまなマップが関係します。簡単に説明しましょう。
1.singletonObjects: BeanName 間の関係を保存し、Bean インスタンスを作成するために使用されます (beanName –> bean Instance)
2.singletonFactories: BeanName と Bean を作成したファクトリの間の関係を保存するために使用されます (banName–>ObjectFactory)
3.earlySingletonObjects: BeanName の保存と Bean インスタンスの作成との関係でもあります。singletonObjects との違いは、シングルトン Bean がここに配置されるとき、Bean がまだ作成プロセスにあるときに getBean メソッドを使用できることです。 、その目的は循環参照を検出することです。
4.registeredSingletons: 現在登録されているすべての Bean を保存するために使用されます。
Bean インスタンスからオブジェクトを取得する
Beanを取得した後はインスタンスオブジェクトを取得する必要があり、ここではgetObjectForBeanInstanceメソッドを使用します。getObjectForBeanInstance は、キャッシュから Bean を取得するためでも、さまざまなスコープ戦略に従って Bean をロードするためでも、頻繁に使用されるメソッドです。つまり、Bean インスタンスを取得した後の最初のステップは、このメソッドを呼び出して正確性をチェックすることです。実際には、取得したBeanがFactoryBean型のBeanであるかどうかを確認し、そうであればそのBeanに対応するFactoryBeanインスタンスのgetObject()を戻り値として呼び出す必要があります。次に、このメソッドのソース コードを見てみましょう。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
//如果指定的name是工厂相关的(以&开头的)
if (BeanFactoryUtils.isFactoryDereference(name)) {
//如果是NullBean则直接返回此bean
if (beanInstance instanceof NullBean) {
return beanInstance;
}
//如果不是FactoryBean类型,则验证不通过抛出异常
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
}
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
//如果获取的beanInstance不是FactoryBean类型,则说明是普通的Bean,可直接返回
//如果获取的beanInstance是FactoryBean类型,但是是以(以&开头的),也直接返回,此时返回的是FactoryBean的实例
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
//到了这里说明获取的beanInstance是FactoryBean类型,但没有以"&"开头,此时就要返回factory内部getObject里面的对象了
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
次に、 getObjectFromFactoryBean(factory, beanName, !synthetic) メソッドに実装されている実際のコア関数を見て、コードに従い続けます。
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
// 为单例模式且缓存中存在
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
// 从缓存中获取指定的 factoryBean
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// 为空,则从 FactoryBean 中获取对象
object = doGetObjectFromFactoryBean(factory, beanName);
// 从缓存中获取
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
// 需要后续处理
if (shouldPostProcess) {
// 若该 bean 处于创建中,则返回非处理对象,而不是存储它
if (isSingletonCurrentlyInCreation(beanName)) {
return object;
}
// 前置处理
beforeSingletonCreation(beanName);
try {
// 对从 FactoryBean 获取的对象进行后处理
// 生成的对象将暴露给bean引用
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;
}
}
このメソッドは、Bean インスタンス オブジェクトを作成する際の中心となるメソッドの 1 つである必要があります。beforeSingletonCreation()
ここでは、 、afterSingletonCreation()
、の 3 つの方法に焦点を当てますpostProcessObjectFromFactoryBean()
。最初の 2 つのメソッドはそれほど重要ではないと考える人もいるかもしれませんが、LZ では、これら 2 つのメソッドは Bean のロード状態を記録し、現在の Bean が作成されているかどうかを検出する鍵となるため、非常に重要な操作であると断言できます。 Bean の循環依存関係を解決する上で重要な役割を果たします。before メソッドは現在の Bean が作成中であることをマークするために使用され、after メソッドはそれを削除するために使用されます。実際、このブログの冒頭で、isSingletonCurrentlyInCreation()
次のように現在の Bean が作成されているかどうかを検出するために使用されると述べました。
public boolean isSingletonCurrentlyInCreation(String beanName) {
return this.singletonsCurrentlyInCreation.contains(beanName);
}
beforeSingletonCreation()
これは、singletonsCurrentlyInCreation コレクションに beanName が含まれるかどうかに基づいており、次のようにコレクションの要素を追加する必要があります。
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
afterSingletonCreation()
削除するには、次のように、singletonsCurrentlyInCreation コレクションを削除する必要があります。
protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}
実際のコア メソッド doGetObjectFromFactoryBean を見てみましょう
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 {
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;
}
以前にFactoryBeanの呼び出しメソッドを紹介しましたが、BeanがFactoryBean型として宣言されている場合、Beanを抽出する際に抽出されるのはFactoryBeanではなく、FactoryBean内の対応するgetObjectメソッドによって返されるBeanであり、実際にこの関数を実装するのはdoGetObjectFromFactroyBeanです。 。
doGetObjectFromFactoryBean メソッドを呼び出した後、直接の戻りはありません。getObjectFromFactoryBean メソッドは、 object = postProcessObjectFromFactoryBean(object, beanName); メソッドも呼び出します。サブクラス AbstractAutowireCapableBeanFactory には、このメソッドの実装があります。
@Override
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
return applyBeanPostProcessorsAfterInitialization(object, beanName);
}
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
ポストプロセッサの使用については、まだ触れていません。フォローアップで多くのことを紹介します。ここでは、Spring の Bean 取得ルールに次のようなルールがあることを理解するだけで済みます。すべての Bean が初期化後に登録された BeanPostProcessor の postProcessAfterInitialization を呼び出すようにします。処理にはメソッドが使用されます。実際の開発プロセスでは、この機能用に独自のビジネス処理を設計できます。