Spring註解 @Configurationhtml
一.@Configuration的做用 java
二.@Configuration的Spring容器啓動方式數組
三.不加@Configuration的@Bean的解析app
五.總結與疑問函數
一.註解做用.post
標註在類上,該類會被CGLIB動態代理生成子類,能夠達到這樣的效果:在某@Bean方法下調用另外一個標註了@Bean的方法,獲得的會是同一個Bean對象;測試
@Configuration註解注意點:ui
1.能夠做爲Component標籤使用; this
2.標註的類不能是final類型的(final類沒法動態代理生成子類);
3.註解類裏的@Bean對象的id默認是方法名,若是設置了@Bean的name或者value屬性,取第一個做爲beanId,name中其餘的做爲別名使用;
4. 標註了@Configuration的類不能是普通內部類,若是非要是個內部類,那就靜態內部類也是能夠的; 由於普通內部類依賴於外部類的存在;
達到的效果就是這樣: 回到解析@Configuration的地方四
獲取bean會發現getMan和getMan2對象是同一個對象,去掉Configuration的話就是兩個不一樣的對象
二. 註解形式的Spring容器的啓動方式(非Web項目)
方式1. 啓動時候將配置類做爲參數傳入容器,多個配置類也能夠一塊兒傳入,參數是可變參數類型能夠接收多個;
public class AppConfig1 { @Bean public Man getMan() { Man man = new Man(); man.setName("呂彬彬"); man.setAge(23); return man; } @Bean public Man getMan2() { return getMan(); } public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig1.class);
//傳入的AppConfig1就是配置類,能夠不標註@Configuration也能使用 String[] names = ac.getBeanDefinitionNames(); for (String string : names) { System.out.println(string+"==="+ac.getBean(string)); } ac.close(); }
方式2. 空的構造器,以後手動註冊配置類,可是記得要調用其refresh方法啓動容器;
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(); ac.register(AppConfig1.class); ac.refresh(); String[] names = ac.getBeanDefinitionNames(); for (String string : names) { System.out.println(string+"==="+ac.getBean(string)); } ac.close();
三. 分析不加@Configuration 只是一個啓動類就能夠解析@Bean註解
3.1 簡單繪製下我理解的Spring容器bean的初始化流程:1-2是Spring容器初始化經歷的過程,而3-9則是每個bean建立必經的過程;InstantiationAwareBeanPostProcessor這些特殊的bean處理器若是有就會執行相應的方法;
若是沒有 也不影響Bean初始化流程 ;這也是Spring能夠豐富擴展的一個點,Spring不少功能Aop、Tx底層就爲咱們添加了不少這種BFPP、BPP;
AnnotationConfigApplicationContext就爲咱們添加了這樣一個BFPP ConfigurationClassPostProcessor;一樣還有不少其餘的BFPP、BPP,方法位於AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
ConfigurationClassPostProcessor的類結構圖以下,咱們只須要看生命週期一、2中的方法便可;
3.2.ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法幹了什麼呢?
1 public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { //registry就是傳入的Spring的基本容器BeanFactory對象,最多見的是DefaultListableBeanFactory 2 int registryId = System.identityHashCode(registry); 3 if (this.registriesPostProcessed.contains(registryId)) { 4 throw new IllegalStateException( 5 "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry); 6 } 7 if (this.factoriesPostProcessed.contains(registryId)) { 8 throw new IllegalStateException( 9 "postProcessBeanFactory already called on this post-processor against " + registry); 10 } 11 this.registriesPostProcessed.add(registryId); 12
13 processConfigBeanDefinitions(registry);
//Spring給的解釋該方法是Build and validate a configuration model based on the registry of Configuration classes. 14 }
查看processConfigBeanDefinitions方法
1 public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { 2 List<BeanDefinitionHolder> configCandidates = new ArrayList<>(); 3 String[] candidateNames = registry.getBeanDefinitionNames(); //遍歷現有註冊的全部bean, 包括了以前的配置類AppConfig1,類型是AnnotatedGenericBeanDefinition
4
5 for (String beanName : candidateNames) { 6 BeanDefinition beanDef = registry.getBeanDefinition(beanName); 7 if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
8 ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
//判斷beanDef有沒有CONFIGURATION_CLASS_FULL屬性(表明有Configuration註解) CONFIGURATION_CLASS_LITE屬性表明有@Bean註解
//只有解析過的beanDef纔會有這兩種屬性
9 if (logger.isDebugEnabled()) { 10 logger.debug("Bean definition has already been processed as a configuration class: " + beanDef); 11 } 12 } 13 else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
//checkConfigurationClassCandidate方法作了如下操做:
// 有@Configuration註解我就給beanDef添加屬性CONFIGURATION_CLASS_FULL
// 有@Bean註解我就給beanDef添加屬性CONFIGURATION_CLASS_LITE
// 若是兩種註解都沒有直接返回false,相反有一種都能爲true, 就會添加到config候選集合中
14 configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
15 } 16 } 17
18 // config候選集合爲空直接返回
19 if (configCandidates.isEmpty()) { 20 return; 21 } 46 ....省略代碼
47 // Configuration類解析器
48 ConfigurationClassParser parser = new ConfigurationClassParser( 49 this.metadataReaderFactory, this.problemReporter, this.environment, 50 this.resourceLoader, this.componentScanBeanNameGenerator, registry); 51
52 Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates); // config候選集合candidates 53 Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size()); 54 do { 55 parser.parse(candidates);
// 開始解析Configuration類,解析過程較爲複雜, 簡單的針對@Bean對象, parser的configurationClasses集合中添加的ConfigurationClass中持有BeanMethod對象,就是含有@Bean標籤的方法
56 parser.validate(); //驗證config配置類不能爲final類型,還有@Bean方法若是是static的也無需驗證
57
58 Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses()); 59 configClasses.removeAll(alreadyParsed); 60
62 if (this.reader == null) { 63 this.reader = new ConfigurationClassBeanDefinitionReader( 64 registry, this.sourceExtractor, this.resourceLoader, this.environment, 65 this.importBeanNameGenerator, parser.getImportRegistry()); 66 } 67 this.reader.loadBeanDefinitions(configClasses);
//讀取ConfigurationClass的集合,根據BeanMethod來建立ConfigurationClassBeanDefinition,也是一種BeanDefinition對象,不一樣之處是建立的使用的是factory-method工廠方式建立的
//每一個ConfigurationClassBeanDefinition的工廠名就是配置類的ID,工廠方法就是@Bean得方法名;
//一樣還有不少處理,好比@Bean的屬性設置、init-Method、destroy-Method ; Lazy 、DependsOn等註解的解析 , 還有不少額外的註解的解析就不介紹了;最後解析完成會註冊到registry中 68 alreadyParsed.addAll(configClasses); 69
70 candidates.clear(); 71 if (registry.getBeanDefinitionCount() > candidateNames.length) { 72 String[] newCandidateNames = registry.getBeanDefinitionNames(); 73 Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames)); 74 Set<String> alreadyParsedClasses = new HashSet<>(); 75 for (ConfigurationClass configurationClass : alreadyParsed) { 76 alreadyParsedClasses.add(configurationClass.getMetadata().getClassName()); 77 } 78 for (String candidateName : newCandidateNames) { 79 if (!oldCandidateNames.contains(candidateName)) { 80 BeanDefinition bd = registry.getBeanDefinition(candidateName); 81 if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
82 !alreadyParsedClasses.contains(bd.getBeanClassName())) { 83 candidates.add(new BeanDefinitionHolder(bd, candidateName)); 84 } 85 } 86 } 87 candidateNames = newCandidateNames; 88 } 89 } 90 while (!candidates.isEmpty());
93 if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) { 94 sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry()); 95 }
97 if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
100 ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache(); 101 } 102 }
到這裏postProcessBeanDefinitionRegistry方法就解析完畢,能夠看到沒有@Configuration註解的AppConfig1類的@Bean註解的@Bean也註冊到Spring容器中了;
結束postProcessBeanDefinitionRegistry 方法時候打印下已經註冊的BeanDefinition,能夠看到最後兩個Bean定義 主要是factoryBeanName以及factoryMethodName屬性設置上了
3.3 ConfigurationClassPostProcessor的postProcessBeanFactory方法幹了什麼呢?
Spring初始化流程圖步驟2執行postProcessBeanFactory方法: 其中enhanceConfigurationClasses方法會遍歷全部的bean發現沒有Configuration註解的bean就結束方法了,因此在這裏不分析該方法,後面也會分析的 :)
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { int factoryId = System.identityHashCode(beanFactory); if (this.factoriesPostProcessed.contains(factoryId)) { throw new IllegalStateException( "postProcessBeanFactory already called on this post-processor against " + beanFactory); } this.factoriesPostProcessed.add(factoryId); if (!this.registriesPostProcessed.contains(factoryId)) { // BeanDefinitionRegistryPostProcessor hook apparently not supported... // Simply call processConfigurationClasses lazily at this point then.
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory); } enhanceConfigurationClasses(beanFactory); beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory)); }
下面敘述下這種@Bean轉換的ConfigurationClassBeanDefinition怎麼實例化: AbstractAutowireCapableBeanFactory的doCreateBean方法 ===> 調用createBeanInstance ===> 發現factoryMethodName不爲空,調用instantiateUsingFactoryMethod ===> 最後調用SimpleInstantiationStrategy的instantiate方法;
3.4 沒有@Configuration註解下@Bean的實例化
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner, @Nullable Object factoryBean, final Method factoryMethod, Object... args) { try { if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { ReflectionUtils.makeAccessible(factoryMethod); return null; }); } else { ReflectionUtils.makeAccessible(factoryMethod); } Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get(); //currentlyInvokedFactoryMethod爲ThreadLocal對象,實例化Bean的時候會記錄當前的factoryMethod try { currentlyInvokedFactoryMethod.set(factoryMethod); Object result = factoryMethod.invoke(factoryBean, args); //調用反射實例化該@Bean對象 if (result == null) { result = new NullBean(); } return result; } finally { //實例化完成後恢復currentlyInvokedFactoryMethod爲以前的值 if (priorInvokedFactoryMethod != null) { currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod); } else { currentlyInvokedFactoryMethod.remove(); } } } catch (IllegalArgumentException ex) { throw new BeanInstantiationException(factoryMethod, "Illegal arguments to factory method '" + factoryMethod.getName() + "'; " +
"args: " + StringUtils.arrayToCommaDelimitedString(args), ex); } catch (IllegalAccessException ex) { throw new BeanInstantiationException(factoryMethod, "Cannot access factory method '" + factoryMethod.getName() + "'; is it public?", ex); } catch (InvocationTargetException ex) { String msg = "Factory method '" + factoryMethod.getName() + "' threw exception"; if (bd.getFactoryBeanName() != null && owner instanceof ConfigurableBeanFactory && ((ConfigurableBeanFactory) owner).isCurrentlyInCreation(bd.getFactoryBeanName())) { msg = "Circular reference involving containing bean '" + bd.getFactoryBeanName() + "' - consider " +
"declaring the factory method as static for independence from its containing instance. " + msg; } throw new BeanInstantiationException(factoryMethod, msg, ex.getTargetException()); } }
到這裏@Bean最簡單的建立過程已經分析完成。
四.@Configuration註解下爲啥 一 裏面獲得的@Bean就是同一個對象呢? 回到效果圖地方
前面幫助:其中3.2processConfigBeanDefinitions給標註了@Configuration的配置類設置了屬性CONFIGURATION_CLASS_FULL
4.1 查看3.3中沒有解析的postProcessBeanFactory的enhanceConfigurationClasses方法
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) { Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>(); for (String beanName : beanFactory.getBeanDefinitionNames()) { BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName); if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
//遍歷了全部的BeanDefinition對象,沒有CONFIGURATION_CLASS_FULL就是空的configBeanDefs,方法以前直接返回了; if (!(beanDef instanceof AbstractBeanDefinition)) { throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" + beanName + "' since it is not stored in an AbstractBeanDefinition subclass"); } else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) { logger.info("Cannot enhance @Configuration bean definition '" + beanName +
"' since its singleton instance has been created too early. The typical cause " +
"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
"return type: Consider declaring such methods as 'static'."); } configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef); //存放標註了Configuration註解的beanDefinition } } if (configBeanDefs.isEmpty()) {
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 {
Class<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader); if (configClass != null) { Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
//生成AppConfig1的子類CGLIB代理Class 而且在下面將beanDef類型更改成了該CGLIB class if (configClass != enhancedClass) { if (logger.isTraceEnabled()) { logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
"enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName())); } beanDef.setBeanClass(enhancedClass); } } } catch (Throwable ex) { throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex); } } }
4.2 既然知道了是採用CGLIB動態代理,那有不少屬性須要設置,代理哪些接口,代理的父類類型已經知道了,回調函數、回調函數過濾器設置了哪些?
1 private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) { 2 Enhancer enhancer = new Enhancer(); 3 enhancer.setSuperclass(configSuperClass); //被代理的父類類型設置上去就是AppConfig1 4 enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
//被代理的接口只設置了EnhancedConfiguration,只是爲了給CGLIB子類可以設置上BeanFactory屬性 5 enhancer.setUseFactory(false); 6 enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); 7 enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader)); 8 enhancer.setCallbackFilter(CALLBACK_FILTER); 9 enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes()); 10 return enhancer; 11 }
CALLBACK_FILTER對象以下:
接着利用enhancer對象生成代理子類
1 private Class<?> createClass(Enhancer enhancer) { 2 Class<?> subclass = enhancer.createClass(); 3 // Registering callbacks statically (as opposed to thread-local) 4 // is critical for usage in an OSGi environment (SPR-5932)...
5 Enhancer.registerStaticCallbacks(subclass, CALLBACKS); //CALLBACKS對象在上面圖片裏 6 return subclass; 7 }
4.3 這樣就生成的CGLIB代理的AppConfig對象,至關於AOP加強了該對象,原本AOP加強內的方法調用自身的方法是不能直接加強自身的,那Spring是怎麼作的呢?
簡單介紹下,Spring CGLIB CallBackFilter的做用; Callback咱們都知道是回調方法,CGLIB對象調用方法就會調用回調方法,可是添加了CallBackFilter,他有個方法accpet(Method method)方法用來判斷調用的方法,返回值爲int類型,表明着走哪一個Callback的下標,傳入的是個Callback的數組嘛 :)
1 public int accept(Method method) { 2 for (int i = 0; i < this.callbacks.length; i++) { 3 Callback callback = this.callbacks[i]; 4 if (!(callback instanceof ConditionalCallback) || ((ConditionalCallback) callback).isMatch(method)) { 5 return i; 6 } 7 } 8 throw new IllegalStateException("No callback available for method " + method.getName()); 9 }
4.3.1先查看第一個Callback BeanMethodInterceptor
查看其isMatch方法
@Override public boolean isMatch(Method candidateMethod) { return (candidateMethod.getDeclaringClass() != Object.class &&
!BeanFactoryAwareMethodInterceptor.isSetBeanFactory(candidateMethod) && BeanAnnotationHelper.isBeanAnnotated(candidateMethod));
//方法不是Object中定義的,且不是setBeanFactory方法,且該方法包含@Bean註解就返回true }
能夠發現,只要調用自身的@Bean註解的方法都會走這個BeanMethodInterceptor回調,那咱們就不看剩下兩個回調函數了,另一個不作任何操做,一個只是負責給CGLIB對象設置上BeanFactory對象,你說怎麼設置,以前CGLIB中就添加了一個實現的接口EnhancedConfiguration,這個接口實現了BeanFactoryAware接口,能夠注入BeanFactory對象;
4.3.2 查看 BeanMethodInterceptor的intercept方法
何時調用getMan、getMan2方法呢?看到3.4 這樣一行 Object result = factoryMethod.invoke(factoryBean, args) 調用反射實例化Bean對象,這個時候不就會走回調方法了嗎 :)
1 public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs, 2 MethodProxy cglibMethodProxy) throws Throwable { 3
4 ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
// 經過反射從CGLIB加強的對象獲取beanFactory對象
5 String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod); // 獲得beanName值,默認爲方法名字,能夠經過@Bean註解指定 6
8 if (BeanAnnotationHelper.isScopedProxy(beanMethod)) { // 解析Scope註解
9 String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName); 10 if (beanFactory.isCurrentlyInCreation(scopedBeanName)) { 11 beanName = scopedBeanName; 12 } 13 }
//FactoryBean類型的Bean解析方式,暫不分析
22 if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
23 factoryContainsBean(beanFactory, beanName)) { 24 Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName); 25 if (factoryBean instanceof ScopedProxyFactoryBean) { 26 // Scoped proxy factory beans are a special case and should not be further proxied
27 } 28 else { 29 // It is a candidate FactoryBean - go ahead with enhancement
30 return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName); 31 } 32 } 33
34 if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
//判斷當前執行的方法是不是正在執行的@Bean的方法,getMan2中調用getMan方法,getMan含有@Bean 這時候就返回false
38 if (logger.isInfoEnabled() &&
39 BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) { 40 logger.info(String.format("@Bean method %s.%s is non-static and returns an object " +
41 "assignable to Spring's BeanFactoryPostProcessor interface. This will " +
42 "result in a failure to process annotations such as @Autowired, " +
43 "@Resource and @PostConstruct within the method's declaring " +
44 "@Configuration class. Add the 'static' modifier to this method to avoid " +
45 "these container lifecycle issues; see @Bean javadoc for complete details.", 46 beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName())); 47 } 48 return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs); //getMan方法直接反射能夠獲得對象 49 } 50
51 return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName); //在getMan2中調用getMan方法就會執行這段邏輯
52
一般狀況下,好比getMan方法下,會返回true,而後調用反射直接獲得Bean對象;而getMan2方法執行的時候調用getMan方法,this對象就是CGLIB對象,就會在走一次這個方法,ThreadLocal對象裏存儲的是getMan2,當前方法是getMan,就會返回false了,執行resolveBeanReference方法;
1 private boolean isCurrentlyInvokedFactoryMethod(Method method) { 2 Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
//獲取ThreadLocalcurrentlyInvokedFactoryMethod對象currentlyInvokedFactoryMethod中當前的Method 3 return (currentlyInvoked != null && method.getName().equals(currentlyInvoked.getName()) && 4 Arrays.equals(method.getParameterTypes(), currentlyInvoked.getParameterTypes())); 5 }
4.3.3 查看resolveBeanReference方法
1 private Object resolveBeanReference(Method beanMethod, Object[] beanMethodArgs, 2 ConfigurableBeanFactory beanFactory, String beanName) { 3
8 boolean alreadyInCreation = beanFactory.isCurrentlyInCreation(beanName); //getMan並非正在建立的bean,false 9 try { 10 if (alreadyInCreation) { 11 beanFactory.setCurrentlyInCreation(beanName, false); 12 } 13 boolean useArgs = !ObjectUtils.isEmpty(beanMethodArgs); 14 if (useArgs && beanFactory.isSingleton(beanName)) {
18 for (Object arg : beanMethodArgs) { 19 if (arg == null) { 20 useArgs = false; 21 break; 22 } 23 } 24 } 25 Object beanInstance = (useArgs ? beanFactory.getBean(beanName, beanMethodArgs) : 26 beanFactory.getBean(beanName)); //沒有參數的狀況下,直接getBean獲取就能夠了 27 if (!ClassUtils.isAssignableValue(beanMethod.getReturnType(), beanInstance)) { 28 if (beanInstance.equals(null)) { 29 if (logger.isDebugEnabled()) { 30 logger.debug(String.format("@Bean method %s.%s called as bean reference " +
31 "for type [%s] returned null bean; resolving to null value.", 32 beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(), 33 beanMethod.getReturnType().getName())); 34 } 35 beanInstance = null; 36 } 37 else { 38 String msg = String.format("@Bean method %s.%s called as bean reference " +
39 "for type [%s] but overridden by non-compatible bean instance of type [%s].", 40 beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(), 41 beanMethod.getReturnType().getName(), beanInstance.getClass().getName()); 42 try { 43 BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(beanName); 44 msg += " Overriding bean of same name declared in: " + beanDefinition.getResourceDescription(); 45 } 46 catch (NoSuchBeanDefinitionException ex) { 47 // Ignore - simply no detailed message then.
48 } 49 throw new IllegalStateException(msg); 50 } 51 } 52 Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod(); //當前ThreadLocal中的是getMan2 53 if (currentlyInvoked != null) { 54 String outerBeanName = BeanAnnotationHelper.determineBeanNameFor(currentlyInvoked); 55 beanFactory.registerDependentBean(beanName, outerBeanName); //設置依賴關係 56 } 57 return beanInstance; 58 } 59 finally { 60 if (alreadyInCreation) { 61 beanFactory.setCurrentlyInCreation(beanName, true); 62 } 63 } 64 }
五.總結與疑問
查看CGLIB代理的AppConfig1對象
1 AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig1.class); 2 AppConfig1 config = ac.getBean(AppConfig1.class); 3 Field[] fs = config.getClass().getFields(); 4 for (Field field : fs) { 5 System.out.println(field.getName()); 6 }
查看輸出:)
總結:@Configuration 可使 該配置類中 @Bean下方法中若是調用同類的方法 返回的是同一個對象!
疑問? 忽然之間懵逼了,測試一下,會發現@Configuration標註的狀況下,this對象指代的是CGLIB代理對象, 我記得Spring Aop的代理對象的this對象不是CGLIB代理對象啊?
因此望知悉的人告知,是this就是CGLIB代理對象仍是 SpringAop 做了不透明的封裝,this方法調用的時候走父類的方法呢?
解決方法,也算找到問題出在哪裏,搞明白其中的道道了 ; 點我查看解決