@[TOC]
1.常用的注解婚度,以及@Configuration
的特殊性
?Spring中提供了很多將對(duì)象注入到容器中的注解秸仙,這里將這些注解列舉出來(lái)飞蚓。@Component
踱稍,@Indexed
弟跑,@Controller
灾前,@Repository
,@Service
孟辑,@Configuration
哎甲。另外還有一個(gè)需要跟@Configuration
蔫敲,@Component
以及派生注解一起使用的注解@Bean
。
?雖然我們經(jīng)常使用這些注解中的炭玫,但是其實(shí)@Configuration
跟其他的注解有點(diǎn)不一樣奈嘿,這個(gè)注解在默認(rèn)情況下Spring會(huì)通過(guò)CGLIB的方式對(duì)貼有這個(gè)注解的對(duì)象進(jìn)行增強(qiáng)。而這個(gè)決定是否進(jìn)行增強(qiáng)的關(guān)鍵吞加,在于@Configuration
注解中的proxyBeanMethods
屬性裙犹。當(dāng)這個(gè)屬性為true
的時(shí)候會(huì)進(jìn)行增強(qiáng),而默認(rèn)情況這個(gè)屬性值就是true
衔憨。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@AliasFor(annotation = Component.class)
String value() default "";
boolean proxyBeanMethods() default true;
}
&esmp;從上面其實(shí)能看到@Configuration
注解本身也是@Component
注解的一個(gè)派生注解叶圃,但是為什么Spring會(huì)對(duì)其進(jìn)行增強(qiáng)呢,接下來(lái)進(jìn)行分析践图。
2. @Configuration
特殊性的源碼解析
2.1 貼有@Configuration
的bean的獲取
?spring對(duì)于@Configuration
注解的解析掺冠,跟@Conditional
注解的解析大部分過(guò)程一樣都是在ConfigurationClassPostProcessor
中進(jìn)行的,可以通過(guò)@Conditional
注解解析的文章看看前面的過(guò)程码党。Spring擴(kuò)展------基于@Conditional
注解以及Condition
接口的擴(kuò)展
德崭。這里天過(guò)前面的步驟,直接進(jìn)入到此類中進(jìn)行分析闽瓢。
2.1.1 bean注冊(cè)前進(jìn)行分類的方法checkConfigurationClassCandidate
?在這個(gè)類中有一個(gè)方法checkConfigurationClassCandidate
用來(lái)檢查當(dāng)前注冊(cè)的類是不是候選configuration class
也就是需要進(jìn)行代理的類接癌。這個(gè)方法的調(diào)用的位置都是在,將對(duì)應(yīng)的候選bean放入到需要注冊(cè)的候選bean的集合這個(gè)步驟前扣讼。這個(gè)貼代碼看看
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
......
for (String beanName : candidateNames) {
//獲取對(duì)應(yīng)的BeanDefinition
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
//檢查BeanDefinition是不是Configuration類型的候選bean缺猛,
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
......
//檢查BeanDefinition是不是Configuration類型的候選bean,并且這沒(méi)有被解析過(guò)
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
......
}
?可以看到在將候選bean放入到需要注冊(cè)的候選bean集合之前都會(huì)對(duì)bean進(jìn)行的檢查椭符,這也可以看成是一個(gè)過(guò)濾 的過(guò)程荔燎,將那些需要進(jìn)行代理的bean進(jìn)行分類。分類的過(guò)程就在checkConfigurationClassCandidate
方法中销钝。這個(gè)方法在ConfigurationClassUtils
類中有咨,現(xiàn)在看看這個(gè)方法的主要步驟
public static boolean checkConfigurationClassCandidate(
BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
......
//獲取源數(shù)據(jù)中包含Configuration注解的信息
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
//如果存在Configuration注解,并且proxyBeanMethods是true蒸健,則表示需要進(jìn)行代理
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
//如果存在Configuration注解座享,但是proxyBeanMethods是false,則表示不需要進(jìn)行代理
//如果不存在Configuration注解似忧,但是如果bean中包含Component渣叛,ComponentScan,Import盯捌,ImportResource或者Bean注解淳衙,則也不需要代理,但是是候選bean
else if (config != null || isConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
//如果滿足上面判斷條件則表示不是候選bean
else {
return false;
}
......
}
?這里做的就是獲取傳進(jìn)來(lái)的候選bean上面的@Configuration
注解,然后進(jìn)行判斷箫攀,主要有以下幾種判斷肠牲。
貼有@Configuration 注解 |
@Configuration 注解的proxyBeanMethods 為true
|
是否需要代理 |
---|---|---|
滿足 | 滿足 | 需要 |
滿足 | 不滿足 | 不需要 |
不滿足 | - | 不需要 |
?上面滿足條件需要代理的bean,會(huì)在封裝其信息的BeanDefinition
對(duì)象中加上一個(gè)屬性CONFIGURATION_CLASS_ATTRIBUTE
值為CONFIGURATION_CLASS_FULL
靴跛。這里需要注意這個(gè)屬性有兩種值缀雳,需要進(jìn)行區(qū)分。
值 | 說(shuō)明 | 情況 |
---|---|---|
CONFIGURATION_CLASS_FULL | 需要對(duì)bean進(jìn)行代理 | 貼有@Configuration 注解的對(duì)象的內(nèi)部所有的注入到容器的對(duì)象(貼有@Bean 注解的對(duì)象) |
CONFIGURATION_CLASS_LITE | 不需要對(duì)bean進(jìn)行代理 | 沒(méi)有貼有@Configuration 注解的對(duì)象汤求,即使內(nèi)部存在注入到容器的對(duì)象 |
?在上面將bean進(jìn)行分類之后俏险,后面就是對(duì)bean進(jìn)行代理增強(qiáng)的階段了。對(duì)bean進(jìn)行代理增強(qiáng)的過(guò)程的起始調(diào)用也是在ConfigurationClassPostProcessor
類中扬绪。
2.2 對(duì)bean進(jìn)行增強(qiáng)
2.2.1 獲取需要代理增強(qiáng)的bean
?增強(qiáng)的初始過(guò)程在ConfigurationClassPostProcessor
類的enhanceConfigurationClasses
方法中。這個(gè)方法的調(diào)用在spring上下文初始化之后會(huì)調(diào)用裤唠。
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
//從容器中獲取BeanDefinition
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
//獲取BeanDefinition中的CONFIGURATION_CLASS_ATTRIBUTE屬性
Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
MethodMetadata methodMetadata = null;
if (beanDef instanceof AnnotatedBeanDefinition) {
methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
}
//從加載了@Configuration注解的BeanDefinition的beanClassLoader中獲取對(duì)應(yīng)的beanClass挤牛,因?yàn)槭沁@個(gè)類加載的@Configuration注解的BeanDefinition
if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
// Configuration class (full or lite) or a configuration-derived @Bean method
// -> resolve bean class at this point...
AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
if (!abd.hasBeanClass()) {
try {
//從beanClassLoader中獲取到真正加載的bean的Classes對(duì)象
abd.resolveBeanClass(this.beanClassLoader);
}
catch (Throwable ex) {
throw new IllegalStateException(
"Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
}
}
}
//如果CONFIGURATION_CLASS_ATTRIBUTE屬性是CONFIGURATION_CLASS_FULL
if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
if (!(beanDef instanceof AbstractBeanDefinition)) {
throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
}
//如果是AbstractBeanDefinition類型的BeanDefinition需要檢查這個(gè)bean是不是已經(jīng)被實(shí)例化了,如果是的則不能進(jìn)行代理
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'.");
}
//放到需要進(jìn)行代理的對(duì)象中
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
AbstractBeanDefinition beanDef = entry.getValue();
// If a @Configuration class gets proxied, always proxy the target class
//如果一個(gè)bean已經(jīng)代理過(guò)了种蘸,則設(shè)置這個(gè)狀態(tài)未true
beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
// Set enhanced subclass of the user-specified bean class
//進(jìn)行代理
Class<?> configClass = beanDef.getBeanClass();
Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
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);
}
}
}
?總結(jié)以下上面的步驟:
- 從當(dāng)前的容器中獲取所有的需要注冊(cè)的bean集合墓赴,然后循環(huán)開(kāi)始2-3步驟,直到結(jié)束
- 獲取
BeanDefinition
中的CONFIGURATION_CLASS_ATTRIBUTE
屬性航瞭,然后獲取需要代理的bean的真實(shí)的Class對(duì)象 - 檢查
CONFIGURATION_CLASS_ATTRIBUTE
屬性是不是CONFIGURATION_CLASS_FULL
诫硕,不是則跳過(guò)進(jìn)入下一個(gè)bean然后到步驟2。是的則將bean放到需要代理的bean的集合中刊侯,然后進(jìn)入2步驟 - 迭代需要代理的bean的集合進(jìn)行代理增強(qiáng)章办。
2.2.2 對(duì)bean進(jìn)行代理增強(qiáng)
&esmp;代理增強(qiáng)的邏輯在ConfigurationClassEnhancer
類的enhance
方法中。
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
//如果當(dāng)前的configClass已經(jīng)是EnhancedConfiguration的子類滨彻,說(shuō)明這個(gè)類已經(jīng)被代理了藕届,因?yàn)楹竺娲淼念悤?huì)設(shè)置接口是EnhancedConfiguration
if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Ignoring request to enhance %s as it has " +
"already been enhanced. This usually indicates that more than one " +
"ConfigurationClassPostProcessor has been registered (e.g. via " +
"<context:annotation-config>). This is harmless, but you may " +
"want check your configuration and remove one CCPP if possible",
configClass.getName()));
}
return configClass;
}
//創(chuàng)建一個(gè)Enhancer然后進(jìn)行代理
Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
if (logger.isTraceEnabled()) {
logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s",
configClass.getName(), enhancedClass.getName()));
}
//返回代理類
return enhancedClass;
}
?可以看到上面的就是用CGILB進(jìn)行代理的,在其創(chuàng)建Enhancer
的時(shí)候亭饵,會(huì)設(shè)置一些參數(shù)休偶,這些參數(shù)就是用來(lái)與普通的CGLIB進(jìn)行區(qū)分的。
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
Enhancer enhancer = new Enhancer();
//設(shè)置父類或者接口類為需要代理的目標(biāo)類
enhancer.setSuperclass(configSuperClass);
//設(shè)置實(shí)現(xiàn)的接口EnhancedConfiguration
enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
//是否需要實(shí)現(xiàn)Factory接口
enhancer.setUseFactory(false);
//設(shè)置命名規(guī)則為了避免Spring的CGLIB版本與常規(guī)的CGLIB之間的沖突
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
//設(shè)置生成策略
enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
//設(shè)置回調(diào)
enhancer.setCallbackFilter(CALLBACK_FILTER);
//設(shè)置回調(diào)類型
enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
return enhancer;
}
?在這里需要關(guān)注一下setCallbackFilter
這個(gè)方法設(shè)置的CALLBACK_FILTER
辜羊。CALLBACK_FILTER
是一個(gè)對(duì)象的數(shù)組踏兜。
private static final Callback[] CALLBACKS = new Callback[] {
new BeanMethodInterceptor(),
new BeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
};
private static final ConditionalCallbackFilter CALLBACK_FILTER = new ConditionalCallbackFilter(CALLBACKS);
?這里包含四個(gè)類BeanMethodInterceptor
,BeanFactoryAwareMethodInterceptor
八秃,NoOp
的空實(shí)現(xiàn)類SerializableNoOp
碱妆,ConditionalCallbackFilter
,其中第三個(gè)NoOp
在spring中是空實(shí)現(xiàn)不用管喜德。主要看ConditionalCallbackFilter
山橄,BeanFactoryAwareMethodInterceptor
跟BeanMethodInterceptor
這三個(gè)類。
2.2.3 方法回調(diào)的過(guò)濾處理ConditionalCallbackFilter
?CallbackFilter
在CGLIB 中起到回調(diào)的作用,就是一個(gè)方法的執(zhí)行時(shí)候的攔截過(guò)濾的作用航棱。spring實(shí)現(xiàn)了自己的ConditionalCallbackFilter
睡雇。在這個(gè)里面會(huì)對(duì)方法進(jìn)行過(guò)濾。
private static class ConditionalCallbackFilter implements CallbackFilter {
private final Callback[] callbacks;
private final Class<?>[] callbackTypes;
public ConditionalCallbackFilter(Callback[] callbacks) {
//設(shè)置Callback饮醇,這里就是BeanMethodInterceptor, BeanFactoryAwareMethodInterceptor, NoOp的空實(shí)現(xiàn)類SerializableNoOp這三個(gè)類
this.callbacks = callbacks;
this.callbackTypes = new Class<?>[callbacks.length];
for (int i = 0; i < callbacks.length; i++) {
this.callbackTypes[i] = callbacks[i].getClass();
}
}
@Override
public int accept(Method method) {
//進(jìn)行循環(huán)處理
for (int i = 0; i < this.callbacks.length; i++) {
Callback callback = this.callbacks[i];
//如果是ConditionalCallback的實(shí)現(xiàn)類它抱,并且isMatch方法通過(guò)則返回對(duì)應(yīng)的callback所在的順序
if (!(callback instanceof ConditionalCallback) || ((ConditionalCallback) callback).isMatch(method)) {
return i;
}
}
throw new IllegalStateException("No callback available for method " + method.getName());
}
?可以看到這里最主要的作用就是設(shè)置自己的Callback
,也就是BeanMethodInterceptor
朴艰,BeanFactoryAwareMethodInterceptor
观蓄,NoOp
。然后進(jìn)行過(guò)濾這些Callback
祠墅,其中ConditionalCallback
也是ConfigurationClassEnhancer
類的內(nèi)部類侮穿。只定義了一個(gè)方法isMatch
,作用是檢查對(duì)應(yīng)的攔截方法是否需要進(jìn)行攔截毁嗦。
private interface ConditionalCallback extends Callback {
boolean isMatch(Method candidateMethod);
}
?其中isMatch
方法由BeanFactoryAwareMethodInterceptor
跟BeanMethodInterceptor
實(shí)現(xiàn)亲茅。接下來(lái)就是這兩個(gè)類
2.2.4 將容器設(shè)置到代理對(duì)象中的BeanFactoryAwareGeneratorStrategy
?BeanFactoryAwareGeneratorStrategy
實(shí)現(xiàn)了CGLIB的DefaultGeneratorStrategy
用來(lái)在生成代理對(duì)象的時(shí)候,設(shè)置額外的信息到代理對(duì)象中狗准。也是在這里將克锣,容器對(duì)象BeanFactory
放到了代理對(duì)象中,這里只截取部分的代碼腔长。
private static class BeanFactoryAwareGeneratorStrategy extends DefaultGeneratorStrategy {
......
@Override
protected ClassGenerator transform(ClassGenerator cg) throws Exception {
//實(shí)現(xiàn)ClassEmitterTransformer袭祟,為代理對(duì)象增加額外的字段BEAN_FACTORY_FIELD,訪問(wèn)級(jí)別是PUBLIC捞附,類型為BeanFactory
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);
}
......
}
?設(shè)置的這個(gè)值巾乳,在后面的兩個(gè)攔截其中都會(huì)用到
2.2.5 增加容器到代理對(duì)象中的BeanFactoryAwareMethodInterceptor
?BeanFactoryAwareMethodInterceptor
主要用來(lái)處理實(shí)現(xiàn)了BeanFactoryAware
類的setBeanFactory
方法類。
private static class BeanFactoryAwareMethodInterceptor implements MethodInterceptor, ConditionalCallback {
@Override
@Nullable
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
//從代理的對(duì)象中獲取BEAN_FACTORY_FIELD字段
Field field = ReflectionUtils.findField(obj.getClass(), BEAN_FACTORY_FIELD);
Assert.state(field != null, "Unable to find generated BeanFactory field");
//將BEAN_FACTORY_FIELD字段設(shè)置到obj對(duì)象中
field.set(obj, args[0]);
//如果當(dāng)前代理類的父類實(shí)現(xiàn)了BeanFactoryAware故俐,則調(diào)用setBeanFactory方法想鹰,如果不是就推出
if (BeanFactoryAware.class.isAssignableFrom(ClassUtils.getUserClass(obj.getClass().getSuperclass()))) {
return proxy.invokeSuper(obj, args);
}
return null;
}
@Override
public boolean isMatch(Method candidateMethod) {
//檢查是否是設(shè)置BeanFactory的方法
return isSetBeanFactory(candidateMethod);
}
public static boolean isSetBeanFactory(Method candidateMethod) {
//方法名是setBeanFactory,參數(shù)個(gè)數(shù)為1個(gè)药版,平且參數(shù)類型是BeanFactory類型辑舷,方法是BeanFactoryAware的實(shí)現(xiàn)類
return (candidateMethod.getName().equals("setBeanFactory") &&
candidateMethod.getParameterCount() == 1 &&
BeanFactory.class == candidateMethod.getParameterTypes()[0] &&
BeanFactoryAware.class.isAssignableFrom(candidateMethod.getDeclaringClass()));
}
}
2.2.6 處理@Configuration
注解中@Bean
注解的BeanMethodInterceptor
?BeanMethodInterceptor
主要處理@Configuration
注解中貼有@Bean
注解的方法。也正是這個(gè)方法槽片,讓@Configuration
有了區(qū)別于@Component
注解中貼有@Bean
注解的方法的原因之一何缓。主要邏輯集中在這個(gè)類的
intercept
方法中,現(xiàn)在來(lái)看看:
?這里要先看看實(shí)現(xiàn)了ConditionalCallback
接口的isMatch
方法还栓,因?yàn)檫@個(gè)會(huì)先被調(diào)用
public boolean isMatch(Method candidateMethod) {
//定義當(dāng)前方法的對(duì)象不是Object碌廓,并且不是方法不是setBeanFactory方法,并且方法上面包含@Bean注解
return (candidateMethod.getDeclaringClass() != Object.class &&
!BeanFactoryAwareMethodInterceptor.isSetBeanFactory(candidateMethod) &&
BeanAnnotationHelper.isBeanAnnotated(candidateMethod));
}
?到這里就知道剩盒,只要是聲明方法的類Object
類谷婆,方法名不是setBeanFactory
貼了@Bean
注解就會(huì)被攔截。
?接下來(lái)就是攔截之后的處理邏輯了。
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
MethodProxy cglibMethodProxy) throws Throwable {
//從代理的實(shí)例中獲取beanFactory纪挎,根據(jù)BEAN_FACTORY_FIELD字段獲取期贫,而這個(gè)字段在enhanced對(duì)象創(chuàng)建設(shè)置stratege的BeanFactoryAwareGeneratorStrategy類中設(shè)置的
ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
//獲取到方法上@Bean注解的name屬性或者方法名來(lái)決定bean的名稱
String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
// Determine whether this bean is a scoped-proxy
//檢查緩存中是否有方法的@Scope注解信息緩存,如果沒(méi)有則檢查是否有@Scope注解并且proxyMode不是NO
if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
//生成作用域代理內(nèi)用于引用目標(biāo)bean的bean名稱
String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
beanName = scopedBeanName;
}
}
/**
* 為了處理bean間方法引用的情況异袄,我們必須顯式地檢查容器中已經(jīng)緩存的實(shí)例通砍。
* 檢查當(dāng)前的bean是不是一個(gè)FactoryBean,如果是這樣創(chuàng)建一個(gè)子類roxy烤蜕,攔截對(duì)getObject()的調(diào)用并返回所有緩存的bean實(shí)例
* 這確保了從@Bean方法中調(diào)用FactoryBean的語(yǔ)義與在XML中引用FactoryBean的語(yǔ)義相同
*/
if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
factoryContainsBean(beanFactory, beanName)) {
Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
if (factoryBean instanceof ScopedProxyFactoryBean) {
//作用域代理工廠bean是一種特殊情況封孙,不應(yīng)該進(jìn)一步代理
// Scoped proxy factory beans are a special case and should not be further proxied
}
else {
// It is a candidate FactoryBean - go ahead with enhancement
//進(jìn)行增強(qiáng)
return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
}
}
//檢查當(dāng)前的方法是不是當(dāng)前調(diào)用的工廠方法,就是當(dāng)前攔截的方法是不是當(dāng)前貼有@Configuration注解類里面貼有@Bean注解的方法
if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
// The factory is calling the bean method in order to instantiate and register the bean (i.e. via a getBean() call) -> invoke the super implementation of the method to actually create the bean instance.
//工廠調(diào)用bean方法是為了實(shí)例化和注冊(cè)bean(即通過(guò)getBean()調(diào)用)->調(diào)用父類方法來(lái)實(shí)際創(chuàng)建bean實(shí)例讽营。
if (logger.isInfoEnabled() &&
BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
logger.info(String.format("@Bean method %s.%s is non-static and returns an object " +
"assignable to Spring's BeanFactoryPostProcessor interface. This will " +
"result in a failure to process annotations such as @Autowired, " +
"@Resource and @PostConstruct within the method's declaring " +
"@Configuration class. Add the 'static' modifier to this method to avoid " +
"these container lifecycle issues; see @Bean javadoc for complete details.",
beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
}
//調(diào)用父類方法
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
}
//從容器獲取bean
return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}
?這里需要說(shuō)明的以下幾點(diǎn)
-
BeanMethodInterceptor
是ConfigurationClassEnhancer
的一個(gè)內(nèi)部類
enhancedConfigInstance
對(duì)象中的 - 當(dāng)貼有
@Bean
注解的方法返回的是BeanFactory
的子類的時(shí)候虎忌,會(huì)先獲取到實(shí)際的bean,也就是beanName前面加上“&”符號(hào)橱鹏,然后進(jìn)行代理 -
isCurrentlyInvokedFactoryMethod
用來(lái)驗(yàn)證當(dāng)前攔截的方法是不是貼有@Bean
注解的方法呐籽,是的話會(huì)調(diào)用代理的方法。如果不是則直接從容器中獲取bean蚀瘸。
3.@Configuration
跟@Component
例證
如果在@Configuration
注解的類的中有@Bean
注解在方法上來(lái)注入對(duì)象,當(dāng)調(diào)用這個(gè)方法的時(shí)候庶橱,返回的是容器里面已經(jīng)創(chuàng)建好的對(duì)象贮勃。舉個(gè)例子
@Configuration
public class ConfigurationTest {
@Bean
public BeanB beanB(){
BeanB beanB = new BeanB();
System.out.println("beanB one---"+beanB);
return beanB;
}
@Bean
@DependsOn(value = "beanB")
public BeanA beanA(){
System.out.println("beanA");
BeanA beanA = new BeanA();
beanA.setBeanB(beanB());
System.out.println("beanB two---"+beanA.getBeanB());
return beanA;
}
}
?當(dāng)從容器中獲取beanA
的時(shí)候。打印的結(jié)果如下
beanB one---springstudy.configuration.BeanB@2611b9a3
beanA
beanB two---springstudy.configuration.BeanB@2611b9a3
?當(dāng)我們把ConfigurationTest
類上面的@Configuration
注解換成@Component
的時(shí)候苏章,看結(jié)果如下
beanB one---springstudy.configuration.BeanB@6d24ffa1
beanA
beanB one---springstudy.configuration.BeanB@65a4798f
beanB two---springstudy.configuration.BeanB@65a4798f
?發(fā)現(xiàn)會(huì)創(chuàng)建兩次BeanB
對(duì)象寂嘉。
?會(huì)發(fā)生這種區(qū)別的原因就是,當(dāng)時(shí)存在@Configuration
注解的時(shí)候枫绅,beanB
跟beanA
方法會(huì)被代理增強(qiáng)泉孩,在beanA
方法中調(diào)用beanB
方法的時(shí)候會(huì)被攔截,并返回容器中已經(jīng)創(chuàng)建的BeanB
對(duì)象并淋。