文章目录前序文章 Spring如何扫描工作目录下的Bean?|图文并茂讲解@Configuration的工作原理
- 揭秘@Configuration的秘密之BeanFactory后置处理器
- 基础介绍
- 目的
- 流程图
- 代码分析
- (1) postProcessBeanFactory()
- (2)enhanceConfigurationClasses()
- (3)ConfigurationClassEnhancer.enhance()
- (4)ConfigurationClassEnhancer.newEnhancer()
- (5)ConfigurationClassEnhancer.createClass()
- 特别分析
- BeanMethodInterceptor.class
- Bean案例
- FactoryBean
- BeanFactoryAwareMethodInterceptor.class
- 谨防入坑
- FactoryBean注入进Spring后,其BeanName真的是&FactoryBean吗?
- FactoryBean中getObject()对象什么时候注入进Spring中的?
- 如果@Configuration被换成了@Component,@Bean方法还会生成单例吗?
前面我们已经探究了@Configuration的原理 Spring如何扫描工作目录下的Bean?|图文并茂讲解@Configuration的工作原理。实际上是ConfigurationClassPostProcessor.class在背后承担了重量级的地位。该类继承了BDR后置处理器,而且BDR后置处理器又继承了BF后置处理器。本文将探究继承了BF后置处理器,它实现了怎么样的逻辑;
目的@Configuration
public MyConfiguration {
@Bean
public MyBean createMyBean() {
return new MyBean();
}
@Bean
public MySubBean createSubBean() {
// 此时createMyBean()只会new一次
return new MySubBean(createMyBean());
}
}
在配置类中,有许多地方声明了@Bean方法,Spring中的bean默认情况下都是单例的,那么如果又有方法调用了@Bean的方法,例如上面的代码,createSubBean()方法中又调用了createMyBean()方法。如何保证bean只会被new一次呢?
Spring在处理@Configuration的配置类时,实际上是给他增加了一个CGLIB代理,放入SpringBean中的配置类实例实际上是一个被代理的对象。当第一次调用createMyBean()方法时,会执行new方法,创建出对象。那么再一次调用createMyBean()方法时,就会去bean工厂中的beanMap中去取,因此保证了单例模型;
流程图在invokeBeanFactoryPostProcessors()方法中,首先执行:
BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry(registry);
然后再执行:
BeanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
前文中,首先执行的是扫描所有的bd,将项目中所有的类都扫描成bd放进beanFactory中;那么接下来就要将所有的bd取出,筛选出上面加了@Configuration的bd,将其通过cglib进行代理;
代码分析 (1) postProcessBeanFactory()该类就是bf后置处理器需要实现的方法,在该方法中,就是将配置类进行cglib代理(见方法2),之后再放入一个Bean的后置处理器importAwareBeanPostProcessor.class;
// ConfigurationClassPostProcessor.class
@Override
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);
}
// 将配置类进行cglib代理
enhanceConfigurationClasses(beanFactory);
beanFactory.addBeanPostProcessor(new importAwareBeanPostProcessor(beanFactory));
}
(2)enhanceConfigurationClasses()
该方法首先取出所有的bd,依次遍历,筛选出加了@Configuration的bd;
创建ConfigurationClassEnhancer配置类代理增强器,后面就通过该增强器去给配置类设置代理;
循环配置类bd,通过配置类代理增强器对bd进行代理enhancer.enhance(),见方法3;
配置类bd设置setBeanClass为代理类class,后续实例化bean的时候,就创建的代理类的对象;
// ConfigurationClassPostProcessor.class
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
Map configBeanDefs = new linkedHashMap<>();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
// 将加了@Configuration的配置类放入configBeanDefs
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
if (!(beanDef instanceof AbstractBeanDefinition)) {
throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
}
// 如果该bd被实例化了则需要将其中@Bean设置为静态的
else if (logger.isWarnEnabled() && beanFactory.containsSingleton(beanName)) {
logger.warn("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);
}
}
if (configBeanDefs.isEmpty()) {
// nothing to enhance -> return immediately
return;
}
// 定义配置类增强器
ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
for (Map.Entry 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> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
if (configClass != enhancedClass) {
// bd设置最终实例化对象就是这个被代理类
beanDef.setBeanClass(enhancedClass);
}
}
}
catch (Throwable ex) {
throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
}
}
}
(3)ConfigurationClassEnhancer.enhance()
配置类增强器的enhance()方法,他判断该class是否实现了EnhancedConfiguration.class接口,因为如果是被代理的,都会实现这个接口;如果已实现,则表示已经被代理过,直接返回即可;
给class创建一个代理class见方法4,然后再返回代理类class见方法5,最终将代理class返回出去,让外层方法设置进bd中;
// ConfigurationClassEnhancer.class
public Class> enhance(Class> configClass, @Nullable ClassLoader classLoader) {
// 如果class的父类是EnhancedConfiguration,则不需要进行代理
if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
return configClass;
}
// 设置被代理的类class
Class> enhancedClass = createClass(newEnhancer(configClass, classLoader));
return enhancedClass;
}
(4)ConfigurationClassEnhancer.newEnhancer()
这个方法就是创建一个cglib代理,我们可以看出,他是通过继承的方式实现代理,然后需要实现EnhancedConfiguration.class接口去标识他已经被代理;
最关键的是他实现了两个回调接口BeanMethodInterceptor.class,BeanFactoryAwareMethodInterceptor.class,他们是用来处理@Bean返回的对象以及factoryBean;
// ConfigurationClassEnhancer.class
private Enhancer newEnhancer(Class> configSuperClass, @Nullable ClassLoader classLoader) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(configSuperClass);
// cglib是通过是否实现EnhancedConfiguration接口判断是否有被代理
enhancer.setInterfaces(new Class>[] {EnhancedConfiguration.class});
enhancer.setUseFactory(false);
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
// 设置了两个关键的回调函数
enhancer.setCallbackFilter(CALLBACK_FILTER);
enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
return enhancer;
}
// 关键方法 回调接口
private static final ConditionalCallbackFilter CALLBACK_FILTER = new ConditionalCallbackFilter(CALLBACKS);
private static final Callback[] CALLBACKS = new Callback[] {
new BeanMethodInterceptor(),
new BeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
};
(5)ConfigurationClassEnhancer.createClass()
就是给代理的class设置CALLBACKS;可以看看我代码中的注释。
这里附上了被代理类的代码,需要保存被CGLIB类可以在java代码中加入该代码:
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\cglib");
private Class> createClass(Enhancer enhancer) {
// 获取被代理的类class
Class> subclass = enhancer.createClass();
// Registering callbacks statically (as opposed to thread-local)
// is critical for usage in an OSGi environment (SPR-5932)...
// 代理类中包含一个静态方法
// public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] callback);
// 将CALLBACKS设置其中
Enhancer.registerStaticCallbacks(subclass, CALLBACKS);
return subclass;
}
// 被CGLIB代理后的配置类
public class SpringstudyApplication$$EnhancerBySpringCGLIB$$26a254aa extends SpringstudyApplication implements EnhancedConfiguration {
private boolean CGLIB$BOUND;
public static Object CGLIB$FACTORY_DATA;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
private MethodInterceptor CGLIB$CALLBACK_0;
private MethodInterceptor CGLIB$CALLBACK_1;
private NoOp CGLIB$CALLBACK_2;
private static Object CGLIB$CALLBACK_FILTER;
private static final Method CGLIB$setBeanFactory$4$Method;
private static final MethodProxy CGLIB$setBeanFactory$4$Proxy;
private static final Object[] CGLIB$emptyArgs;
public BeanFactory $$beanFactory;
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("cn.ixp.springstudy.SpringstudyApplication$$EnhancerBySpringCGLIB$$26a254aa");
Class var1;
CGLIB$setBeanFactory$4$Method = ReflectUtils.findMethods(new String[]{"setBeanFactory", "(Lorg/springframework/beans/factory/BeanFactory;)V"}, (var1 = Class.forName("org.springframework.beans.factory.BeanFactoryAware")).getDeclaredMethods())[0];
CGLIB$setBeanFactory$4$Proxy = MethodProxy.create(var1, var0, "(Lorg/springframework/beans/factory/BeanFactory;)V", "setBeanFactory", "CGLIB$setBeanFactory$4");
}
final void CGLIB$setBeanFactory$4(BeanFactory var1) throws BeansException {
super.setBeanFactory(var1);
}
public final void setBeanFactory(BeanFactory var1) throws BeansException {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_1;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_1;
}
if (var10000 != null) {
var10000.intercept(this, CGLIB$setBeanFactory$4$Method, new Object[]{var1}, CGLIB$setBeanFactory$4$Proxy);
} else {
super.setBeanFactory(var1);
}
}
public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
String var10000 = var0.toString();
switch(var10000.hashCode()) {
case 2095635076:
if (var10000.equals("setBeanFactory(Lorg/springframework/beans/factory/BeanFactory;)V")) {
return CGLIB$setBeanFactory$4$Proxy;
}
}
return null;
}
public SpringstudyApplication$$EnhancerBySpringCGLIB$$26a254aa() {
CGLIB$BIND_CALLBACKS(this);
}
public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
CGLIB$THREAD_CALLBACKS.set(var0);
}
// 这里设置静态的callback集合
public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
CGLIB$STATIC_CALLBACKS = var0;
}
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
SpringstudyApplication$$EnhancerBySpringCGLIB$$26a254aa var1 = (SpringstudyApplication$$EnhancerBySpringCGLIB$$26a254aa)var0;
if (!var1.CGLIB$BOUND) {
var1.CGLIB$BOUND = true;
Object var10000 = CGLIB$THREAD_CALLBACKS.get();
if (var10000 == null) {
var10000 = CGLIB$STATIC_CALLBACKS;
if (var10000 == null) {
return;
}
}
Callback[] var10001 = (Callback[])var10000;
var1.CGLIB$CALLBACK_2 = (NoOp)((Callback[])var10000)[2];
var1.CGLIB$CALLBACK_1 = (MethodInterceptor)var10001[1];
var1.CGLIB$CALLBACK_0 = (MethodInterceptor)var10001[0];
}
}
static {
CGLIB$STATICHOOK2();
CGLIB$STATICHOOK1();
}
static void CGLIB$STATICHOOK2() {
}
}
特别分析
上面我们分析了postProcessBeanFactory()方法的执行流程。那么在过程中,有两个特殊的Callbacks需要我们关注,那么我们来分析一下这两个特别的callbacks;
private static final Callback[] CALLBACKS = new Callback[] {
new BeanMethodInterceptor(),
new BeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
};
BeanMethodInterceptor.class
当代理类对象调用方法的时候,就会进入intercept()方法,做方法拦截。代码的具体流程可以看我加的注释,这个方法的具体流程见后续分析;
@Override
@Nullable
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs, MethodProxy cglibMethodProxy) throws Throwable {
// 获取bean工厂
ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
// 如果有获取@Bean,就获取bean的名称——返回的要不是bean名称,要么就是方法名
String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
// Determine whether this bean is a scoped-proxy
// 作用域
Scope scope = AnnotatedElementUtils.findMergedAnnotation(beanMethod, Scope.class);
if (scope != null && scope.proxyMode() != ScopedProxyMode.NO) {
String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
beanName = scopedBeanName;
}
}
// To handle the case of an inter-bean method reference, we must explicitly check the
// container for already cached instances.
// First, check to see if the requested bean is a FactoryBean. If so, create a subclass
// proxy that intercepts calls to getObject() and returns any cached bean instance.
// This ensures that the semantics of calling a FactoryBean from within @Bean methods
// is the same as that of referring to a FactoryBean within XML. See SPR-6602.
// 判断有没有循环调用返回factoryBean的方法,如果有的话则对该factoryBean方法创建代理
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
// 给getObject()方法增加代理
return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
}
}
// 比如代码 a(){ return new a();} b(){ return a()}
// (1)首先a访问到这isCurrentlyInvokedFactoryMethod()返回true,然后就直接执行new a()
// (2)然后b访问到这isCurrentlyInvokedFactoryMethod()返回true,然后直接执行a()方法
// (3)这次再调用a()方法时,isCurrentlyInvokedFactoryMethod()返回false,就不执行new a()了
// isCurrentlyInvokedFactoryMethod解析:
// 他会获取当前调用的方法currentlyInvokedMethod 和将要执行的方法 method
// 当currentlyInvokedMethod==method时返回true
// 因此(3)这块,currentlyInvokedMethod是b(),而执行的method是a(),因此返回false
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.
if (logger.isWarnEnabled() &&
BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
logger.warn(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()));
}
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
}
// 直接从bean工厂里取,不再重新new
return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}
Bean案例
拿文章开头的demo来分析。
@Configuration
public MyConfiguration {
@Bean
public MyBean createMyBean() {
return new MyBean();
}
@Bean
public MySubBean createSubBean() {
// 此时createMyBean()只会new一次
return new MySubBean(createMyBean());
}
}
当实例化MyBean的bd的时候,我们调用的就是MyConfiguration.createMyBean()方法。这时就会被方法拦截,通过isCurrentlyInvokedFactoryMethod()方法来判断是否是第一次创建MyBean对象。
private boolean isCurrentlyInvokedFactoryMethod(Method method) {
Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
return (currentlyInvoked != null && method.getName().equals(currentlyInvoked.getName()) &&
Arrays.equals(method.getParameterTypes(), currentlyInvoked.getParameterTypes()));
}
这个方法有一个Method是currentlyInvoked,他表示当前调用该方法的方法,例如当前是createMyBean();
入口参数Method是method,他表示当前需要执行的方法;执行的是createMyBean();
当调用方法=执行方法,返回true,则可表示当前是第一次执行new对象,否则就不是第一次执行new对象;
因此MyBean的bd实例化走的是new MyBean()创建对象;
而实例化MySubBean的bd时,里面调用了createMyBean(),这时进入isCurrentlyInvokedFactoryMethod方法返回的是false,因为调用方法是createSubBean(),执行方法createMyBean(),因此这里是去beanFactory取MyBean的实例化对象;
总结:配置类中的@Bean(单例下)方法,多次调用只会实例化一次,后面都会从bean工厂中取已实例化的对象。
FactoryBean先上demo
@Configuration
public class MyBeanConfig {
// 放入Bean容器中
@Bean
public MyFactoryBean getMyFactoryBean() {
return new MyFactoryBean();
}
@Bean
public MyFactoryBean getMySameFactoryBean() {
return getMyFactoryBean();
}
}
// 定义的FactoryBean
public class MyFactoryBean implements FactoryBean {
@Override
public MyBean getObject() throws Exception {
return new MyBean();
}
@Override
public Class> getObjectType() {
return MyBean.class;
}
}
// 定义的Bean
public class MyBean {
public MyBean() {
System.out.println("创建了 MyBean");
}
}
这里的流程是这样的:
-
执行getMyFactoryBean()方法时,第一次进入时不会走下面的代码,而是和@Bean的流程一样,判断当前调用方法和执行方法是否一样,这里为true,执行new MyFactoryBean();
// 判断有没有循环调用返回factoryBean的方法,如果有的话则对该factoryBean方法创建代理 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 // 给getObject()方法增加代理 return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName); } } -
接下来执行getMySameFactoryBean(),这里也是执行到判断当前调用方法和执行方法是否一样,这里为true,执行getMyFactoryBean();
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
-
由于又去执行getMyFactoryBean();这时再一次进入方法拦截器中,这次会走这块的代码了。
factoryContainsBean()判断的是beanName=getMyFactoryBean是不是FactoryBean,其原理是getMyFactoryBean是不是已经在beanFactory中了,且是FactoryBean;
我们都知道,factoryBean在bean容器中都是以&为前缀的,【但并不是其beanName加了&】,后面会去解释;
这里第一次判断factoryContainsBean(beanFactory,“&” + beanName)我还不太明白,因为factoryContainsBean()对于beanName是取了去除&的,然后对于单例已创建的Bean是判断是否实现了FactoryBean.class接口,这里需要再探究!!!
// 判断有没有循环调用返回factoryBean的方法,如果有的话则对该factoryBean方法创建代理 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 // 给getObject()方法增加代理 return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName); } }然后创建了CGLIB代理MyFactoryBean.class并返回;我们可以看到,代理的方法拦截主要是如果调用getObject()方法从工厂里取,其余方法都是反射原代理对象的方法;
((Factory) fbProxy).setCallback(0, (MethodInterceptor) (obj, method, args, proxy) -> { if (method.getName().equals("getObject") && args.length == 0) { return beanFactory.getBean(beanName); } return proxy.invoke(factoryBean, args); });因此,我们从实验结果上可以看出,&getMyFactoryBean返回的对象是MyFactoryBean,而&getMySameFactoryBean返回的是MyFactoryBean代理对象,且被代理的对象就是MyFactoryBean;
这个方法拦截器只拦截setBeanFactory()方法,它主要是设置了$$beanFactory为args[0],另外如果该代理类实现了BeanFactoryAware.class则调用setBeanFactory(args)方法;
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 = 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.
// 如果实现了BeanFactoryAware,则调用setBeanFactory()方法
if (BeanFactoryAware.class.isAssignableFrom(ClassUtils.getUserClass(obj.getClass().getSuperclass()))) {
return proxy.invokeSuper(obj, args);
}
return null;
}
// 匹配的是setBeanFactory方法
@Override
public boolean isMatch(Method candidateMethod) {
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()));
}
}
谨防入坑
FactoryBean注入进Spring后,其BeanName真的是&FactoryBean吗?
首先声明:不是;他只是Spring在代码中判断Bean是否为FactoryBean的一个标记,并不是注入进Spring后其BeanName加了&;
上实验截图:
我们发现,在beanDefinition中查询getMyFactoryBean,发现其指向的仍然是MyBeanConfig.class#getMyFactoryBean();
那么我们看下单例池中的数据:
可以发现,其实在单例池中BeanName=getMyFactoryBean,其Value=MyFactoryBean对象,而不是MyBean对象;那MyBean对象是在哪里存储的呢?请看下一个问题。
因此,我们发现Spring的bd集合和单例池中,不存在FactoryBean注入进去后其BeanName加了"&"号。
FactoryBean中getObject()对象什么时候注入进Spring中的?从前面的分析看出来,程序已经执行完了,但bd和单例池中都没有MyBean对象,那么FactoryBean的getObject()对象什么时候被调用的呢?
其实,当我们调用完applicationContext.refresh();后,我们会把扫描的,手动注册的bd去实例化对应的Bean放入单例池中,而我们并没有特殊处理FactoryBean.getObject()方法,所以我们的bd中是没有FactoryBean.getObject()对应的bd的,因此单例池中也不会有相应的实例化对象;
那当我们调用getBean的时候为什么会拿出MyBean对象呢?
Object getMyFactoryBean = applicationContext.getBean("getMyFactoryBean");
这时,doGetBean()会将其MyFactoryBean的实例化对象取出来,如果MyFactoryBean不是FactoryBean就将其返回,若是FactoryBean,就会调用其getObject()方法将MyBean对象创建出来,然后返回。因此getMyFactoryBean返回的是MyBean对象;
那么如果我们调用两次getBean呢?
Object getMyFactoryBean = applicationContext.getBean("getMyFactoryBean");
Object getMyFactoryBean1 = applicationContext.getBean("getMyFactoryBean");
这时返回的getMyFactoryBean和getMyFactoryBean1是同一个MyBean对象。我们会疑问,MyBean对象并没有放入beanFactory的单例池中,那么第二次调用getBean()返回的对象是存储在哪里的呢?
原来,我们的beanFactory继承了FactoryBeanRegistrySupport.class类,它其中有个factoryBeanObjectCache专门存储factoryBean创建的对象,因此,第二次调用不会再次调用getObject()方法,而是从缓存中直接取。
private final MapfactoryBeanObjectCache = new ConcurrentHashMap(16);
总结:factoryBean.getObject()方法最终调用是在getBean()的时候,并且有个factoryBeanObjectCacheMap去保存对象,不存放在单例池中;
如果@Configuration被换成了@Component,@Bean方法还会生成单例吗?答案:不会!
都没有CGLIB代理了,肯定不会是单例,每次调用都会生成新的对象。



