
這是一篇長文,但是很自信的是我相信我講的已經非常透徹了,想必你讀完之后,一定對@Configuration有一個很透徹的理解,
@Configuration注解在實際的開發程序中,好像顯的不是那么的重要,因為使用的程序中,加他,不加他,貌似都沒有什么大的影響,那他存在到底有什么意義呢?我們來看一下下面的這段測驗實體,
// 測驗類A
public class A {
public A(){
System.out.println("create a");
}
}
// 測驗類B
public class B {
public B(){
System.out.println("create b");
}
}
// 配置類
@Component
@Configuration
@ComponentScan("com.lupf.configuration")
public class AppConfig {
@Bean
public A a() {
// 這里呼叫b()
b();
return new A();
}
@Bean
public B b(){
return new B();
}
}
// 啟動類
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
ac.register(AppConfig.class);
ac.refresh();
}
}
測驗代碼很簡單,就是很普通的A與B兩個類,然后通過@Bean的方式注入;我們在@Bean的a()方法中呼叫了b()方法,按方法的呼叫關系來看的話,這樣就違背了spring單例的原則,直接呼叫b()方法的時候會new一個B;a()方法執行b();這一行代碼的時候又會new一個B;那實際情況是不是這樣呢?
- 不加@Configuration的測驗
和我們所想的是一樣的,果然B被實體化了兩次,很顯然,他違背了單例原則;
- 加上@Configuration的測驗
wtf? 正常了,,,不過這才是應該有的樣子,那加了注解,他到底經歷了什么呢?
- 我們來看一下加與不加 spring生成的AppConfig是什么樣的?
// 以下代碼獲取AppConfig AppConfig bean = ac.getBean(AppConfig.class);
代理物件?這樣就可以解釋了,這兩個物件創建的程序被cglib代理了
圖示代理流程

原理分析
結合上面的流程圖,我們來一步步的分析;要關注的核心點就是這個代理物件如何產生的?長什么樣?起什么用?
- 偽代理物件原理分析
public class AppConfigProxy extends AppConfig{ //bean工廠 BeanFactory $$beanFactory; @Override public A a() { return super.a(); } @Override public B b(){ // 通過工廠去獲取一個B B b = (B)$$beanFactory.getBean("b"); // 如果拿到了,就直接回傳 if(null!=b){ return b; } // 如果沒有拿到,就呼叫父類的方法創建 return super.b(); } }代理物件重寫了b()方法;這個b()方法并不是直接去new一個物件,而是先去Bean工廠里面去取一遍,如果取到之后,就直接回傳,如果沒有取到,那么就呼叫目標物件(父類方法,因為cglib是基于繼承實作的)去實體化!原理是不是比較的容易理解!spring就是這么做的?對!他也是這么做的,只不過最終實作起來,并沒有這么簡單,因為我們是寫死的,但對于spring框架來說,他并不知道你是一個什么類,做了哪些邏輯;下面一起從原始碼的角度去分析一下他是如何去代理的,
原始碼決議@Configuration掃描
-
一,
Bean的掃描判斷是否是全注解類!
當spring通過Bean的后置處理器掃描類的時候,會去判斷當前類是否是一個全注解的類;何為全注解?加了@Configuration注解的類就是一個全注解類;在執行Bean注冊后置處理器BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法時,ConfigurationClassPostProcessor這個實作中會呼叫一個工具方法ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)),其中有一段代碼是用來校驗是否是全注解的/** * 確定是不是一個全配置類 判斷是否加了 @Configuration * @see AttributeAccessorSupport 保存到一個用于存盤元資料的list中 */ if (isFullConfigurationCandidate(metadata)) { // 往元素據的Map attributes中添加一個值為full的鍵值對 beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL); } else if (isLiteConfigurationCandidate(metadata)) { // 往元素據的Map attributes中添加一個值為lite的鍵值對 beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE); } else { return false; } //============================================================================ // isFullConfigurationCandidate工具類,很直觀,就時判斷是否加了@Configuration注解 public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) { return metadata.isAnnotated(Configuration.class.getName()); } //============================================================================ // isLiteConfigurationCandidate工具類 // 半注解的校驗也很簡單,就是看是否加了 // @Component、@ComponentScan、@Import、@ImportResource、@Bean這些注解 public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) { // Do not consider an interface or an annotation... // 如果是一個介面直接回傳false if (metadata.isInterface()) { return false; } /** * Any of the typical annotations found? * candidateIndicators包含以下四種注解 * Component.class.getName(); * ComponentScan.class.getName(); * Import.class.getName(); * ImportResource.class.getName(); */ for (String indicator : candidateIndicators) { if (metadata.isAnnotated(indicator)) { return true; } } // Finally, let's look for @Bean methods... try { // 查找是否有@Bean的方法 return metadata.hasAnnotatedMethods(Bean.class.getName()); } catch (Throwable ex) { if (logger.isDebugEnabled()) { logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex); } return false; } }其中最重要的一行判斷
metadata.isAnnotated(Configuration.class.getName())就確定了當前類是否是全注解,由于AppConfig是一個全注解的類,因此會在這個BeanDefinition的元資料Map中放一個值為full的鍵值對,作為一個標識,可是扯半天,又沒有去做啥實際的操作,這有啥用?有用!!!下面的操作就會用上,以下為AppConfig掃描時的程序,

-
二、
完成代理
當后置處理器執行完BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法之后;會執行BeanFactoryPostProcessor的postProcessBeanFactory方法;這個介面的實作類ConfigurationClassPostProcessor就去完成了全注解物件的代理,代碼如下:
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
this.factoriesPostProcessed.add(factoryId);
if (!this.registriesPostProcessed.contains(factoryId)) {
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
// 呼叫了該方法進行了屬性增強
enhanceConfigurationClasses(beanFactory);
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
//=============================================================================
// 繼續走enhanceConfigurationClasses,代碼如下
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
/**
* 判斷當前類是否是一個全注解的類
* 這個時候,前面添加的值為full的鍵值對就用上了
*/
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
}
}
if (configBeanDefs.isEmpty()) {
// nothing to enhance -> return immediately
return;
}
/**
* 如果是一個全注解的類 那么下面的代碼就會對全注解的類生成一個代理物件
* 目的是為了解決一個依賴呼叫的問題
*/
ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
AbstractBeanDefinition beanDef = entry.getValue();
// If a @Configuration class gets proxied, always proxy the target class
beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
try {
// Set enhanced subclass of the user-specified bean class
// 這里拿到目標物件(原始物件)的class
Class<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader);
if (configClass != null) {
// 這里實體化一個代理物件的class
// 注意這里只是一個class 如果得到的是一個物件,那么將無法通過spring去管理這個物件
// 拿到class之后,后續Bean的生命周期會將其實體化
Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
// 判斷是否成功獲取到代理物件的class
// 如果獲取成功,那么enhancedClass必定就是另外一個class物件了
if (configClass != enhancedClass) {
// 得到class之后 將這個class設定到對應的beanDefinition中
// 目的是為了后面spring實體化物件
beanDef.setBeanClass(enhancedClass);
}
}
} catch (Throwable ex) {
throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
}
}
}
為了篇幅,刪掉了原始碼中部分無用代碼;可以看出,方法一進來,就回圈所有的BD判斷當前類是不是一個全注解的類(判斷條件就是前面添加的值為full的鍵值對),如果是,就將他放到一個容器里面;回圈完沒有一個全注解的類,就直接回傳;如包含全注解的類,就通過
Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);生成了一個代理Class,然后通過beanDef.setBeanClass(enhancedClass);替換原有的Class;這樣就完成了下圖所示的部分功能,
為什么這里是一個Class而不是一個Object呢?
因為spring實體化物件的生命周期并不是在這里,如果這里直接創建一個Object,那這個Object是一個沒有走標準生命周期的Object,所以也就不會被spring進行管理;這里生成一個Class,后續的流程會將這個Class實體化一個標準的Bean,放置到容器中,
.
到此,一個被代理后的AppConfig對應的class就這么生成并回傳了;但是到這里還并沒有看到底褲,我們最終的目的可是要看到底褲,長驅直入!!!
代理類是如何產生的?
繼續深入enhance方法,,,,
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
/**
* 判斷當前類是否已經被代理過了
* 如果代理過了,cglib在生成代理物件的時候,會在代理類上面實作EnhancedConfiguration 方法
*/
if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
// 如果已經試代理物件了 就直接回傳就好了
return configClass;
}
/**
* newEnhancer(configClass, classLoader) 表示實體化一個Enhancer物件
* createClass 方法執行完 得到一個代理物件
*/
Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
// 回傳代理物件
return enhancedClass;
}
發現他只是個花架子,但是已經發現核心代碼了
createClass(newEnhancer(configClass, classLoader));newEnhancer原始碼如下,這里就是整個代理物件的關鍵:
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
// 實體化一個Enhancer物件
Enhancer enhancer = new Enhancer();
// 設定代理物件的父類 因為cglib代理是通過繼承的方式實作的
enhancer.setSuperclass(configSuperClass);
// 標示用于增強的介面 代理物件回實作這個介面
// 同時在代理物件生成的程序中 也會使用這個物件來判斷是否已經生成過代理物件了
enhancer.setInterfaces(new Class<?>[]{EnhancedConfiguration.class});
enhancer.setUseFactory(false);
// 設定代理物件的命名規則
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
/**
* 設定一個策略
* 當cglib生成一個代理物件的時候,會為這個物件添加一個$$beanFactory屬性
* 見代碼: declare_field(Constants.ACC_PUBLIC, BEAN_FACTORY_FIELD, Type.getType(BeanFactory.class), null);
*
* 該屬性是用來獲取bean物件的
*
* 這里只是添加了一個BeanFactory物件 會在后續的代碼中給實體化
*
*/
enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
/**
* 這里會添加回呼的過濾器
*/
enhancer.setCallbackFilter(CALLBACK_FILTER);
enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
return enhancer;
}

關鍵代碼說明!
-
設定代理物件實作的介面
enhancer.setInterfaces(new Class<?>[]{EnhancedConfiguration.class}); // ================================================= // 具體的EnhancedConfiguration介面類 public interface EnhancedConfiguration extends BeanFactoryAware { }這行代碼會讓最后生成的代理物件實作指定的
EnhancedConfiguration介面;上面代碼可以看出該介面是一個空介面,但是他的父類BeanFactoryAware有一個setBeanFactory(BeanFactory beanFactory)的介面;因此,實作EnhancedConfiguration介面的主要目的是為了后面給$$beanFactory賦值及賦值前生命周期流程中判斷是否是一個代理物件所用;如果不知道$$beanFactory是個啥可以跳過,下面一段就是介紹這個$$beanFactory是咋來的 -
設定策略
enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader)); // 以下為BeanFactoryAwareGeneratorStrateg物件 private static class BeanFactoryAwareGeneratorStrategy extends DefaultGeneratorStrategy { @Nullable private final ClassLoader classLoader; public BeanFactoryAwareGeneratorStrategy(@Nullable ClassLoader classLoader) { this.classLoader = classLoader; } @Override protected ClassGenerator transform(ClassGenerator cg) throws Exception { ClassEmitterTransformer transformer = new ClassEmitterTransformer() { @Override public void end_class() { declare_field(Constants.ACC_PUBLIC, BEAN_FACTORY_FIELD, Type.getType(BeanFactory.class), null); super.end_class(); } }; return new TransformingClassGenerator(cg, transformer); } @Override public byte[] generate(ClassGenerator cg) throws Exception { if (this.classLoader == null) { return super.generate(cg); } Thread currentThread = Thread.currentThread(); ClassLoader threadContextClassLoader; try { threadContextClassLoader = currentThread.getContextClassLoader(); } catch (Throwable ex) { // Cannot access thread context ClassLoader - falling back... return super.generate(cg); } boolean overrideClassLoader = !this.classLoader.equals(threadContextClassLoader); if (overrideClassLoader) { currentThread.setContextClassLoader(this.classLoader); } try { return super.generate(cg); } finally { if (overrideClassLoader) { // Reset original thread context ClassLoader. currentThread.setContextClassLoader(threadContextClassLoader); } } } }這里面有一段很關鍵的代碼
declare_field(Constants.ACC_PUBLIC, BEAN_FACTORY_FIELD, Type.getType(BeanFactory.class), null);
就是為這個代理物件添加一個名叫$$beanFactory的BeanFactory屬性(下圖為證),對應的實作為DefaultListableBeanFactory,其目的就是用來獲取Bean,是不是和最開始我們構想的偽代碼有異曲同工之妙!
可是那這玩兒動態加進去的,在哪里給$$beanFactory賦值的呢?您接著往后看


-
添加回呼過濾器
/** * 這里會添加回呼的過濾器 */ enhancer.setCallbackFilter(CALLBACK_FILTER); // CALLBACK_FILTER是啥? private static final ConditionalCallbackFilter CALLBACK_FILTER = new ConditionalCallbackFilter(CALLBACKS); // CALLBACKS是個啥? private static final Callback[] CALLBACKS = new Callback[]{ // 在這里,執行方法的時候,就會優先去判斷,物件是否已經創建 // 創建之后就回傳,沒有創建就呼叫父介面創建 new BeanMethodInterceptor(), // 在這里 會通過反射的方式 給$$beanFactory賦值 new BeanFactoryAwareMethodInterceptor(), NoOp.INSTANCE };從上面的代碼可以看出,其最終是添加了兩個方法執行的攔截器;這兩個方法執行的攔截器非常重要;
BeanFactoryAwareMethodInterceptor主要的職責就是為$$beanFactory物件賦值;BeanMethodInterceptor的主要功能是判斷Bean是否已經創建了;具體見下面的詳細分析 -
BeanFactoryAwareMethodInterceptor **
該MethodInterceptor的主要功能就是通過反射的方式,給上面添加的$$beanFactory賦值**,具體代碼如下:private static class BeanFactoryAwareMethodInterceptor implements MethodInterceptor, ConditionalCallback { @Override @Nullable public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { // 找到$$beanFactory對應的field Field field = ReflectionUtils.findField(obj.getClass(), BEAN_FACTORY_FIELD); Assert.state(field != null, "Unable to find generated BeanFactory field"); // 通過反射為$$beanFactory賦值 field.set(obj, args[0]); // Does the actual (non-CGLIB) superclass implement BeanFactoryAware? // If so, call its setBeanFactory() method. If not, just exit. if (BeanFactoryAware.class.isAssignableFrom(ClassUtils.getUserClass(obj.getClass().getSuperclass()))) { return proxy.invokeSuper(obj, args); } return null; } @Override public boolean isMatch(Method candidateMethod) { // 這里會去判斷是否是setBeanFactory方法,如果是,才會執行上面的intercept 方法 return isSetBeanFactory(candidateMethod); } public static boolean isSetBeanFactory(Method candidateMethod) { return (candidateMethod.getName().equals("setBeanFactory") && candidateMethod.getParameterCount() == 1 && BeanFactory.class == candidateMethod.getParameterTypes()[0] && BeanFactoryAware.class.isAssignableFrom(candidateMethod.getDeclaringClass())); } }isSetBeanFactory(candidateMethod);這個判斷需要注意一下,因為他的存在,約束了這個攔截器就只會去處理setBeanFactory這個方法的呼叫;具體的賦值其實已經很簡單了,找到Field,然后通過反射去賦值;但是又帶出了一個更重要的問題,這個方法什么時候呼叫的? -
setBeanFactory是什么時候呼叫的?
討論這個問題之前,我們需要往前回顧一點東西,就是ConfigurationClassPostProcessor的postProcessBeanFactory方法通過呼叫enhanceConfigurationClasses()去完成了代理物件的生成之后,還做了一些事情;如果不記得了,這里我在把代碼再貼一遍:public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { int factoryId = System.identityHashCode(beanFactory); this.factoriesPostProcessed.add(factoryId); if (!this.registriesPostProcessed.contains(factoryId)) { processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory); } // 呼叫了該方法進行了增強 enhanceConfigurationClasses(beanFactory); /** * 這里的后處理器的作用就是給實作了EnhancedConfiguration介面的bean設定BeanFactory物件 * 如果是全注解Bean,生成的代理Class都實作了EnhancedConfiguration介面 */ beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory)); }可以看到,當完成了代理class生成之后,就往Bean工廠里面添加了一個叫
ImportAwareBeanPostProcessor的后置處理器,這個后置處理器就是呼叫setBeanFactory的關鍵,其中postProcessProperties方法(其他的方法暫時不重要)的具體代碼如下:@Override public PropertyValues postProcessProperties(@Nullable PropertyValues pvs, Object bean, String beanName) { if (bean instanceof EnhancedConfiguration) { ((EnhancedConfiguration) bean).setBeanFactory(this.beanFactory); } return pvs; }代碼也很簡單明了,就是判斷bean是不是實作了EnhancedConfiguration介面,如果實作了就呼叫setBeanFactory方法,這樣也就和前面說的為什么要實作這個介面的原因呼應上了;現在是呼叫的地方找到了,那ImportAwareBeanPostProcessor這個后置處理器又是在哪里呼叫的呢? 這里就涉及到Bean生命周期了,詳細細節很難一兩句說清楚,那么這里就直接給個結論,后續會對spring bean生命周期進行詳細的介紹,如果讓你為一個物件去呼叫set方法賦值,你會在什么地方去做?當然是在物件創建之后撒!spring也是一樣,spring通過
doCreateBean方法創建Bean的時,物件創建完會通過populateBean方法去完成屬性注入,注入時有一段代碼就是來呼叫這個后置處理器的,詳情如下:for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; /** * 在這里通過bean的后置處理器去完成依賴注入 * 如果使用的是@Autowried進行注入的時候,使用的是 {@link AutowiredAnnotationBeanPostProcessor} 進行屬性的注入 * @see org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor * * 如果使用的xml配置的,那么就使用的是 CommonAnnotationBeanPostProcessor 進行屬性的注入 * @see org.springframework.context.annotation.CommonAnnotationBeanPostProcessor */ PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { if (filteredPds == null) { filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); } //自動注入 pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { return; } } pvs = pvsToUse; } }當AppConfig物件實體化成功之后,去注入屬性時,就會執行上面的for;而
ImportAwareBeanPostProcessor就是要執行的后置處理器的其中一個,自然也就會呼叫setBeanFactory完成了AppConfig代理物件中$$beanFactory的填充,

-
BeanMethodInterceptor
繼續回來介紹另外一個攔截器,他的主要職責就是通過$$beanFactory去判斷物件是否已經生成了,由于代碼比較多,這里只貼intercept的部分(無用代碼已經洗掉)public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs, MethodProxy cglibMethodProxy) throws Throwable { // 得到beanFactory ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance); // 拿到beanName String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod); // Determine whether this bean is a scoped-proxy if (BeanAnnotationHelper.isScopedProxy(beanMethod)) { String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName); if (beanFactory.isCurrentlyInCreation(scopedBeanName)) { beanName = scopedBeanName; } } /** * 這里是用來判斷當前的Bean是不是一個FactoryBean 如果是的話,那么就先創建FactoryBean * 然后再創建Bean */ if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) && factoryContainsBean(beanFactory, beanName)) { Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName); if (factoryBean instanceof ScopedProxyFactoryBean) { // Scoped proxy factory beans are a special case and should not be further proxied } else { // It is a candidate FactoryBean - go ahead with enhancement return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName); } } if (isCurrentlyInvokedFactoryMethod(beanMethod)) { // 如果回傳的是同一個方法,說明正在實體化 // 那么就呼叫目標物件的方法 return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs); } // 如果不是一個 那么就去獲取bean return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName); }- beanFactory獲取
ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance); // 核心代碼 通過反射獲取 Field field = ReflectionUtils.findField(enhancedConfigInstance.getClass(), BEAN_FACTORY_FIELD); Object beanFactory = ReflectionUtils.getField(field, enhancedConfigInstance); - beanName獲取
通過拿到Mathod上面的@Bean注解,從注解中取到name屬性 - beanFactory判斷
優先判斷是否是一個beanFactory,如果是,先創建beanFactory,再獲取Bean 核心判斷,校驗是否已經創建物件了
通過以下示例代碼講解這個判斷,注意,這里很重要,也是理解這塊兒東西的關鍵if (isCurrentlyInvokedFactoryMethod(beanMethod)) //==================================== private boolean isCurrentlyInvokedFactoryMethod(Method method) { // 獲取到當前是誰在呼叫對應的方法 Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod(); // 校驗method是否和currentlyInvoked為同一個方法 return (currentlyInvoked != null && method.getName().equals(currentlyInvoked.getName()) && Arrays.equals(method.getParameterTypes(), currentlyInvoked.getParameterTypes())); }
@Bean
public A a() {
// 這里呼叫b()
b();
return new A();
}@Bean
public B b(){
return new B();
}
```
> 當spring創建@Bean物件的時候,會直接呼叫對應的方法,如創建物件B,就會直接呼叫appConfig.b();上面的那個判斷的邏輯就是創建這個物件的方法和呼叫當前的方法是不是同一個;這里創建B物件的時候,創建物件的方法是b(),呼叫者也是b(),所以判斷回傳的為true,就是執行了cglibMethodProxy.invokeSuper呼叫目標方法去實體化一個物件;
> 當執行a()方法的時候,同樣會經歷上面的判斷,發現呼叫者和實體化的方法都是a();呼叫目標方法;但是(注意轉折了哈!),執行目標方法的時候,第一行就是去呼叫b();此時就來到了b()方法的呼叫,因為攔截器攔截的原因這里也會觸發這個intercept方法;但是現在就和之前不一樣了,現在的呼叫者是誰?是a()方法,執行實體化的是誰?是b()方法!這樣上面的if判斷回傳的就是false,就會讓流程走到resolveBeanReference方法去獲取Bean,如果有就直接從容器里面回傳,沒有就去實體化一個;就這樣,就算a()方法中會呼叫b();結果發現容器里面已經有一個了,就直接回傳了,如此騷操作,就可以保證物件只會創建一個,如果你們沒有想明白,麻煩把這一段話仔細讀幾遍,應該就能明白了

- beanFactory獲取
到這里,不過如此嘛!是吧!
碼字不易,感謝您的關注!點贊!評論!!!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/3658.html
標籤:Java


