@Bean注册Bean,你有多了解?

要学习@Bean注册Bean,那么首先必须了解org.springframework.context.annotation.Bean这个注解了。在Spring源码中关于这个注解的注释相当的详细,如下所示:
在这里插入图片描述
足足有一个170行左右,不知道你有没有认真阅读过呢?

此处大致总结一下:

  • bean的名称问题:默认是方法名称,当然可以通过value参数和name参数来定义,比如如下两个定义的bean的名称分别就是方法名称orderDao和value属性orderDaoName(而非方法名orderDaoWithName),这个so easy,没啥技术含量,注册bean的时候解析一下注解就好了
@Bean
public OrderDao orderDao() {
    return new OrderDao();
}
    
@Bean(value = "orderDaoName", initMethod = "start", destroyMethod = "stop")
public OrderDao orderDaoWithName() {
    return new OrderDao();
}
  • 注解中也包含了一些其他的属性,比如initMethoddestroyMethod,如果定义了对应类中初始化方法和销毁方法的话,在bean初始化和容器销毁的时候就会触发相应的方法。比如上面的orderDaoName对应的bean初始化执行类中的start方法,而容器销毁时触发stop方法。这个看起来也不难吧?
  • Profile, Scope, Lazy, DependsOn, Primary, Order可以与Bean注解一起使用,如下所示,定义了一个原形bean,仍然不感觉有啥难度吧?
@Lazy(value = false)
@Order
@Scope("prototype")
@Bean
public OrderDao protoTypeOrderDao() {
    return new OrderDao();
}
  • inter-bean references 内部bean方法引用
@Configuration
public class RootConfig {
    @Bean
    public OrderDao orderDao() {
        return new OrderDao();
    }
    
    @Bean
    public OrderService orderService() {
        return new OrderService(orderDao());
    }
}

如上所示,定义了两个bean方法,orderService会引用orderDao,其实也就是依赖orderDao这个bean。这个很常见,只不过在实例化orderService的时候去填充orderDao这个bean不就好了吗?

  • @Bean Lite Mode 非@Configuration类下面定义
@Component
public class LiteModeBean {
    @Bean
    public LiteOrderDao liteOrderDao() {
        return new LiteOrderDao();
    }

    @Bean
    public LiteOrderService liteOrderService() {
        return new LiteOrderService(liteOrderDao());
    }
}

这里除了把类的注解从@Configuration换成了@Component没有其他区别,那么这种方式与上面的有什么区别吗?或者说有什么不同呢?

  • Bootstrapping模式 静态方法模式

假如有如下一个类

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }
}

然后再注册这样的一个类如下

@Configuration
public class RootConfig {
    /**
     * ConfigurationClassBeanDefinition
     * isFactoryMethodUnique = false
     * beanClass = com.example.bean.RootConfig 、factoryBeanName = null 、factoryMethodName = myBeanFactoryPostProcessor
     */
    @Bean
    public static MyBeanFactoryPostProcessor myBeanFactoryPostProcessor() {
        return new MyBeanFactoryPostProcessor();
    }
}    

在这里,对应的方法前面加了一个static,加static与不加static对方法来说,你可能知道,一个静态方法属于类,一个实例方法属于类实例对象嘛,但是对于这两种方式注入的bean有什么讲究吗?

好啦!如果以上6个知识点你都了然如胸而且对其中的原理都非常了解的话,那么下面都可以不用阅读了。如果你不清楚,而且有兴趣了解的话,那么我们从源码来说明这些问题。

首先必须提醒,以下的内容会对初学者极为不适,可以说有相当的难度。需要的技术栈如下:

  1. 反射,必须熟悉方法的反射调用、属性的反射调用
  2. 动态代理,CGLIB对一个类的代理增强
  3. 熟悉Spring的Bean定义的解析和实例化的大致流程

如果对以上三点都是否的话,建议不要阅读,否则会非常受打击。

首先可以给出部分的答案,这样在阅读后续内容会更轻松一点。

上面我故意按照通常错误的见解解释了内部bean方法引用,真的不是在实例化orderService之后去注入orderDao这个名称的bean的。假如这个成立的话,Spring是如何知道是去查找这个Bean的呢?byName or byType?难到Spring解析orderService这个bean定义的时候还要详细获取这个方法中的各种调用关系吗?如果思路这样下去一定会很难,非常难,而且你会觉得Spring一定超级牛逼,采用了某个不为人知的技术。其实是出发点错误了。

以下是重点。

其实在Spring中,把通过@Bean这种模式注册的方法都称为工厂方法(factoryMethodName),而对应类称为工厂bean(factoryBean),如下图所示:
在这里插入图片描述
RootConfig这个类最后会作为一个bean注入到Spring中,也就是factoryBean,注意这个factoryBean与FactoryBean不是一回事,只是说这个类作为下面那些方法的factoryBean,bean的名称为rootConfig,而实例方法注册的bean定义中包含了factoryBeanName和factoryMethodName,而静态方法中仅仅包含factoryMethodName,factoryBeanName为空的。

为什么?其实如果我们获取到对应的方法的话,通过方法反射就相当于执行了对应的方法,能得到目标实例了,(static)静态方法反射是不需要对应类的实例的,比如以上的myBeanFactoryPostProcessor方法反射是不需要RootConfig实例的,因为它是类方法,而实例方法就不同了,orderDao方法要反射必须首先有RootConfig实例对象,因此这两种模式最大的区别就出来了,静态方法其实很简单,反射调用就好了,但是实例方法,必须首先获得factoryBean(通过getBean获取),然后再反射才行。

好了,那么接下来再谈谈内部方法引用的问题,假如说按照以上的方式进行反射了,最后又调用到了另一个方法,这个方法当然也是这个实例的了,直接调用就可以了吗?当然不行,如果被调用的那个方法增强过了怎么办?比如说有另外两个方法引用了同一个方法,那么每次都执行一次被调用方法new一个实例不是就违背了单例bean的原则了吗? 或者比如加了这样的注解@Scope(scopeName = "prototype",proxyMode = ScopedProxyMode.INTERFACES),作为原型bean,又该如何处理呢?Spring的解决方案是对factoryBean进行了代理增强(CGLIB),这样每次反射调用的时候,其实会调用增强的那个类,就可定制增强的逻辑了。但是Spring只对@Configuration的类做了代理增强,而其他模式(我们叫lite mode)的没有做增强,因此非@Configuration类下的内部方法引用与@Configuration类下的内部方法引用本质上是完全不同的。

好了,那么下面我们从源码来解读以上的问题。


bean定义的解析和注册

首先介绍一个类ConfigurationClassPostProcessor,因为一切的源头就是从它开始的,它会扫描指定目录下的所有的带有@Configuration(Full Mode)和其他比如@Component的类(Lite Mode),然后将这个类下面所有带有@Bean的方法(所谓BeanMethod)提取出来,最后注册为一个BeanDefinition,对一个的注册方法为
org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod

  • 与beanName解析相关
AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
Assert.state(bean != null, "No @Bean annotation attributes");

// Consider name and any aliases
List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
String beanName = (!names.isEmpty() ? names.remove(0) : methodName);

// Register aliases even when overridden
for (String alias : names) {
	this.registry.registerAlias(beanName, alias);
}

不难看出,首先获取name属性,如果为空,则取方法名称methodName。不为空,则取第一个作为beanName,其他都作为别名。

  • 静态方法or实例方法
if (metadata.isStatic()) {
	// static @Bean method
	beanDef.setBeanClassName(configClass.getMetadata().getClassName());
	beanDef.setFactoryMethodName(methodName);
}
else {
	// instance @Bean method
	beanDef.setFactoryBeanName(configClass.getBeanName());
	beanDef.setUniqueFactoryMethodName(methodName);
}

这里区分了静态方法和非静态方法,就是通过设置bean定义中不同属性值来实现的,然后再后面真正实例化的时候根据不同的属性值进行不同的反射过程。

  • 其他属性的解析
Autowire autowire = bean.getEnum("autowire");
if (autowire.isAutowire()) {
	beanDef.setAutowireMode(autowire.value());
}

boolean autowireCandidate = bean.getBoolean("autowireCandidate");
if (!autowireCandidate) {
	beanDef.setAutowireCandidate(false);
}

String initMethodName = bean.getString("initMethod");
if (StringUtils.hasText(initMethodName)) {
	beanDef.setInitMethodName(initMethodName);
}

String destroyMethodName = bean.getString("destroyMethod");
beanDef.setDestroyMethodName(destroyMethodName);

这几个比较简单

  • 与Scope相关
// Consider scoping
ScopedProxyMode proxyMode = ScopedProxyMode.NO;
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
if (attributes != null) {
	beanDef.setScope(attributes.getString("value"));
	proxyMode = attributes.getEnum("proxyMode");
	if (proxyMode == ScopedProxyMode.DEFAULT) {
		proxyMode = ScopedProxyMode.NO;
	}
}

// Replace the original bean definition with the target one, if necessary
BeanDefinition beanDefToRegister = beanDef;
if (proxyMode != ScopedProxyMode.NO) {
	BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
			new BeanDefinitionHolder(beanDef, beanName), this.registry,
			proxyMode == ScopedProxyMode.TARGET_CLASS);
	beanDefToRegister = new ConfigurationClassBeanDefinition(
			(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);
}

最后会通过ScopedProxyUtils生成一个代理类,注册一个名称为在原来beanName前面加上scopedTarget.的bean。由于与本文关联不是特别大,也不细究了。

Configuration classes的增强

对应的源码方法:org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanFactory

/**
 * Post-processes a BeanFactory in search of Configuration class BeanDefinitions;
 * any candidates are then enhanced by a {@link ConfigurationClassEnhancer}.
 * Candidate status is determined by BeanDefinition attribute metadata.
 * @see ConfigurationClassEnhancer
 */
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)) {
			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);
		}
	}
	if (configBeanDefs.isEmpty()) {
		// nothing to enhance -> return immediately
		return;
	}

从以上不难看出,只会把isFullConfigurationClass,也就是带有注解Configuration的类

	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<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader);
			if (configClass != null) {
				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);
				}
			}
		}
		catch (Throwable ex) {
			throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
		}
	}
}

从以上不难看出,主要是通过ConfigurationClassEnhancer这个类来进行增强的。

/**
 * Creates a new CGLIB {@link Enhancer} instance.
 */
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
	Enhancer enhancer = new Enhancer();
	enhancer.setSuperclass(configSuperClass);
	// 实现了EnhancedConfiguration接口 其实就是实现了BeanFactoryAware接口
	enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
	enhancer.setUseFactory(false);
	enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
	// 这里会产生一个$$beanFactory的属性
	enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
	enhancer.setCallbackFilter(CALLBACK_FILTER);
	enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
	return enhancer;
}

具体增强首先是实现了EnhancedConfiguration接口,其实也就是实现了BeanFactoryAware接口,另外还通过Strategy产生了一个属性($$beanFactory),但是这些与本文关系没那么强。主要的增强还是在CallBack类中,就是对应以下的三个类:

class ConfigurationClassEnhancer {
// The callbacks to use. Note that these callbacks must be stateless.
private static final Callback[] CALLBACKS = new Callback[] {
		new BeanMethodInterceptor(),
		new BeanFactoryAwareMethodInterceptor(),
		NoOp.INSTANCE
};

他们都实现了接口

private interface ConditionalCallback extends Callback {

	boolean isMatch(Method candidateMethod);
}
public interface MethodInterceptor extends Callback {
    
    Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable;
}

第三个其实是空的,只有前两个有效。也就是说后续在执行这些增强类的任何方法的时候都会进入BeanMethodInterceptorBeanFactoryAwareMethodInterceptor中。首先通过isMatch方法判断是否需要进行拦截,如果匹配的话,就会进入到对应的intercept方法。后面会详述,这里先不息究了,但是要有个印象。

这里介绍的比较简单,对ConfigurationClassPostProcessor不熟悉的可以先去阅读一下源码或者参考本人的博客:
Spring中最重要的一个后置处理器,没有之一

实例方法注册bean
创建实例对象

在Spring容器刷新之后需要对每一个非懒加载的bean进行实例化,bean的实例化包括对象实例化以及bean的初始化等一系列的动作,这个对象实例化也就是doCreateBean的过程。通过@Bean注入的bean都会认为是工厂方法来获取的bean,所在的类就是工厂bean(factoryBean)。实例化的过程就是先要实例化factoryBean,然后查找对应的方法,执行反射就可以创建出想要的对象了,步骤如下:

doCreateBean-> createBeanInstance
在这里插入图片描述

/**
 * Instantiate the bean using a named factory method. The method may be static, if the
 * mbd parameter specifies a class, rather than a factoryBean, or an instance variable
 * on a factory object itself configured using Dependency Injection.
 * @param beanName the name of the bean
 * @param mbd the bean definition for the bean
 * @param explicitArgs argument values passed in programmatically via the getBean method,
 * or {@code null} if none (-> use constructor argument values from bean definition)
 * @return a BeanWrapper for the new instance
 * @see #getBean(String, Object[])
 */
protected BeanWrapper instantiateUsingFactoryMethod(
		String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {

	return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}

在这里插入图片描述

解析的目标是要获取factoryBean、factoryClass(为了查找方法)、是否是静态方法(反射所需的要素不同)

Object factoryBean;
Class<?> factoryClass;
boolean isStatic;

通过factoryBeanName是否设置对应是否为静态方法定义的bean。如果不为空,那么为实例方法。对于实例方法,是需要通过beanFactory来获取factoryBean的,因为实例方法的反射需要有当前对象存在。

String factoryBeanName = mbd.getFactoryBeanName();
if (factoryBeanName != null) {
	if (factoryBeanName.equals(beanName)) {
		throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
				"factory-bean reference points back to the same bean definition");
	}
	// 获取factoryBean
	factoryBean = this.beanFactory.getBean(factoryBeanName);
	if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
		throw new ImplicitlyAppearedSingletonException();
	}
	// 获取工厂类类型
	factoryClass = factoryBean.getClass();
	// 当前为实例方法
	isStatic = false;
}

在这里插入图片描述
进行实例化

@Override
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();
		try {
			currentlyInvokedFactoryMethod.set(factoryMethod);
			// 反射
			Object result = factoryMethod.invoke(factoryBean, args);
			if (result == null) {
				result = new NullBean();
			}
			return result;
		}
		finally {
			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());
	}
}

在这里插入图片描述
注意此处的factoryBean是一个被CGLIB增强的类,因此在执行目标方法的时候会进入对应的增强方法。在进行解析和注册时候,RootConfig会做为一个ConfigurationClassConfigurationClassEnhancer进行增强。对应的Callback类如下所示:

class ConfigurationClassEnhancer {

	// The callbacks to use. Note that these callbacks must be stateless.
	private static final Callback[] CALLBACKS = new Callback[] {
			new BeanMethodInterceptor(),
			new BeanFactoryAwareMethodInterceptor(),
			NoOp.INSTANCE
	};
}

反射调用的时候,首先进入方法org.springframework.context.annotation.ConfigurationClassEnhancer.BeanMethodInterceptor#intercept,首先是要获取beanFactory对象,这里又会和另一个知识点挂上关系,在ConfigurationClassPostProcessor对每一个类进行增强之后会注册一个ImportAwareBeanPostProcessor,这个后置处理器会在ConfigurationClass这些增强的类(EnhancedConfiguration类型)添加BeanFactory属性。(ImportAwareBeanPostProcessor的一个作用。)

获取beanName
/**
 * Enhance a {@link Bean @Bean} method to check the supplied BeanFactory for the
 * existence of this bean object.
 * @throws Throwable as a catch-all for any exception that may be thrown when invoking the
 * super implementation of the proxied method i.e., the actual {@code @Bean} method
 */
@Override
@Nullable
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
	MethodProxy cglibMethodProxy) throws Throwable {
  // 获取beanFacotory
ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);

获取beanFactory采用的是反射的方法:

private ConfigurableBeanFactory getBeanFactory(Object enhancedConfigInstance) {
	Field field = ReflectionUtils.findField(enhancedConfigInstance.getClass(), BEAN_FACTORY_FIELD);
	Assert.state(field != null, "Unable to find generated bean factory field");
	Object beanFactory = ReflectionUtils.getField(field, enhancedConfigInstance);
	Assert.state(beanFactory != null, "BeanFactory has not been injected into @Configuration class");
	Assert.state(beanFactory instanceof ConfigurableBeanFactory,
			"Injected BeanFactory is not a ConfigurableBeanFactory");
	return (ConfigurableBeanFactory) beanFactory;
}

在这里插入图片描述
获取beanName,默认情况下为方法名称,如果对应方法上@Bean注解属性name存在,则取该属性值。

	String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);

在这里插入图片描述
判断是否为scoped-proxy类型的bean,对应方法上存在Scope注解而且设置的模式不为NO。
在这里插入图片描述
为啥要判断是否为scope-proxy对象呢?因为这种bean的名称经过了修饰,一般在前面添加了scopedTarget.前缀。
在这里插入图片描述

	// Determine whether this bean is a scoped-proxy
	if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
		String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
		if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
			beanName = scopedBeanName;
		}
	}

通过以上的操作,无非就是获取到beanName。

解决Bean method代用FactoryBean问题

假如存在以下的案例

public class MyFactoryBean implements FactoryBean<OrderDao> {
    @Override
    public OrderDao getObject() throws Exception {
        return new OrderDao();
    }

    @Override
    public Class<?> getObjectType() {
        return OrderDao.class;
    }
}

进行bean的定义

@Configuration
public class RootConfig {
    /**
     * @return 通过myFactoryBean获取的应该是getObject获得的对象
     */
    @Bean
    public MyFactoryBean myFactoryBean() {
        return new MyFactoryBean();
    }

    // 此时注入成了一个问题了
    @Bean
    public OrderService orderServiceFactoryBean() throws Exception {
        return new OrderService(myFactoryBean().getObject());
    }
}

那么此时调用通过myFactoryBean名称获取的对象的类型应该为OrderDao,而不是MyFactoryBean 。如果要获取MyFactoryBean的对象,需要使用&myFactoryBean。只要对FactoryBean有了解的人,理解这个应该不难。

但是如果是其他bean通过方法调用的时候,如果也是返回OrderDao,然后再调用getObject显然会存在问题(应该在方法中不添加getObject编译又没法通过),因此遇到这种情形,必须是返回MyFactoryBean了,那么不就和通常情况冲突了吗?Spring当在这种情况出现的时候,返回一个动态代理,代理之后的对象遇到getObject方法就会到beanFactory中查找名称为myFactoryBean的bean。

	// 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.
	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);
		}
	}
/**
 * Create a subclass proxy that intercepts calls to getObject(), delegating to the current BeanFactory
 * instead of creating a new instance. These proxies are created only when calling a FactoryBean from
 * within a Bean method, allowing for proper scoping semantics even when working against the FactoryBean
 * instance directly. If a FactoryBean instance is fetched through the container via &-dereferencing,
 * it will not be proxied. This too is aligned with the way XML configuration works.
 */
private Object enhanceFactoryBean(final Object factoryBean, Class<?> exposedType,
		final ConfigurableBeanFactory beanFactory, final String beanName) {

	try {
		Class<?> clazz = factoryBean.getClass();
		boolean finalClass = Modifier.isFinal(clazz.getModifiers());
		boolean finalMethod = Modifier.isFinal(clazz.getMethod("getObject").getModifiers());
		if (finalClass || finalMethod) {
			if (exposedType.isInterface()) {
				if (logger.isTraceEnabled()) {
					logger.trace("Creating interface proxy for FactoryBean '" + beanName + "' of type [" +
							clazz.getName() + "] for use within another @Bean method because its " +
							(finalClass ? "implementation class" : "getObject() method") +
							" is final: Otherwise a getObject() call would not be routed to the factory.");
				}
				return createInterfaceProxyForFactoryBean(factoryBean, exposedType, beanFactory, beanName);
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Unable to proxy FactoryBean '" + beanName + "' of type [" +
							clazz.getName() + "] for use within another @Bean method because its " +
							(finalClass ? "implementation class" : "getObject() method") +
							" is final: A getObject() call will NOT be routed to the factory. " +
							"Consider declaring the return type as a FactoryBean interface.");
				}
				return factoryBean;
			}
		}
	}
	catch (NoSuchMethodException ex) {
		// No getObject() method -> shouldn't happen, but as long as nobody is trying to call it...
	}

	return createCglibProxyForFactoryBean(factoryBean, beanFactory, beanName);
}

通过createCglibProxyForFactoryBean创建动态代理,主要还是最后设置的Callback方法:
在这里插入图片描述

非FactoryBean 当前正在实例化中

当前对象正在实例化过程中(isCurrentlyInvokedFactoryMethod),返回类型为BeanFactoryPostProcessor的方法必须定义为静态的,否则会影响到自动注入。

	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.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()));
		}
		return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
	}

在这里插入图片描述
然后会下一个拦截器BeanFactoryAwareMethodInterceptor.首先会判断一下当前方法是否为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()));
}

如果是setBeanFactory方法,那么传入的第一个参数应该就是目标对象。所以先通过反射找到$$beanFactory属性并设置值。另外如果该类实现了BeanFactoryAware,则继续执行,否则直接退出即可。

private static final String BEAN_FACTORY_FIELD = "$$beanFactory";

@Override
@Nullable
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
	Field field = ReflectionUtils.findField(obj.getClass(), BEAN_FACTORY_FIELD);
	Assert.state(field != null, "Unable to find generated BeanFactory field");
	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;
}

最后会调用到真实的方法构造目标对象实例(完成了创建bean的第一步)
在这里插入图片描述
不难看出,实例方法定义bean必须提前实例化对应的类(FactoryBean),而且由于这个bean已经在注册之前进行了增强操作,所以在反射调用的时候会进行到CGLIB的拦截器,这主要是因为我们会注入FactoryBean或者Scope增强(Scope不为NO)的Bean。

非FactoryBean 非实例化中(方法引用注入)

如果当前对象不是在实例化过程中,一般都是依赖注入的过程。(在类中一个方法内部直接调用另一个类的方法注入bean)

	return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}

另外调用这个类中的任何方法都会是增强之后的。比如:
在这里插入图片描述
在这里插入图片描述

只有带@Configuration类被ConfigurationClassEnhancer类进行了增强,因此@Component注解下方法直接调用不会得到增强。

此时属于注入模式,会走另一个逻辑。目标就是获取目标bean。
在这里插入图片描述
在这里插入图片描述
最终通过getBean获取要注入的对象,然后进行registerDependentBean

Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
if (currentlyInvoked != null) {
	String outerBeanName = BeanAnnotationHelper.determineBeanNameFor(currentlyInvoked);
	beanFactory.registerDependentBean(beanName, outerBeanName);
}
return beanInstance;

在这里插入图片描述
将依赖关系记录到属性org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#dependenciesForBeanMap当中

/** Map between depending bean names: bean name to Set of bean names for the bean's dependencies. */
private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);

在这里插入图片描述
最后将从容器中获取到的依赖bean返回并设置
在这里插入图片描述
以上情形是一个单例bean注入另一个单例bean的情形,最后返回的对象和注入的对象都是唯一的。

注入原型bean(非单例bean)

如果是以下情形(一个单例bean注入一个原型bean),会有什么不同吗?

/**
 * ConfigurationClassBeanDefinition
 * beanClass = null 、factoryBeanName = rootConfig 、factoryMethodName = protoTypeOrderDao
 */
@Scope("prototype")
@Bean
public OrderDao protoTypeOrderDao() {
    return new OrderDao();
}

/**
 * ConfigurationClassBeanDefinition
 * beanClass = null 、factoryBeanName = rootConfig 、factoryMethodName = orderServiceScope
 */
@Bean
public OrderService orderServiceScope() {
    return new OrderService(protoTypeOrderDao());
}

除了在获取依赖bean的时候不是获取单例bean(没有缓存,每次get都能获取一个新的),其他都是一样的。(因为单例bean都会放入缓存,虽然一个单例bean的依赖bean会是原型的,但是下次获取这个单例bean,其实还是一样的)
在这里插入图片描述
在这里插入图片描述

ConfigurationBeanFactoryMetadata

by the way,在Spring中存在一个工具类(ConfigurationBeanFactoryMetadata,其实是一个BeanFactoryPostProcessor)来记录这些实例类型bean的信息,反射方法和反射实例。
在这里插入图片描述

静态方法注册bean

对于静态方法注册的类,与实例方法的方法调用都是一样,只不过反射的时候只要知道方法就好了,不需要对应的类实例。依旧是通过方法
org.springframework.beans.factory.support.ConstructorResolver#instantiateUsingFactoryMethod来创建实例,只是在解析的时候在bean的定义中不存在factoryBeanName属性。

String factoryBeanName = mbd.getFactoryBeanName();
if (factoryBeanName != null) {
    // 实例方法逻辑省略
	isStatic = false;
}
else {
	// It's a static factory method on the bean class.
	if (!mbd.hasBeanClass()) {
		throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
				"bean definition declares neither a bean class nor a factory-bean reference");
	}
	factoryBean = null;
	factoryClass = mbd.getBeanClass();
	isStatic = true;
}

静态方法的factoryBeanName在前面解析的时候是没有设置的,因此为空

else {
	// It's a static factory method on the bean class.
	if (!mbd.hasBeanClass()) {
		throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
				"bean definition declares neither a bean class nor a factory-bean reference");
	}
	// 不需要factoryBean
	factoryBean = null;
	// 工厂类类型已经设置在bean定义当中了
	factoryClass = mbd.getBeanClass();
	// 设置静态方法
	isStatic = true;
}

对于静态方法在反射执行的时候是不需要对象存在的
在这里插入图片描述
而且此时由于不需要类实例,因此也不会进行与实例方法的那一套增强操作,而且完全不依赖于factoryBean,可以在factoryBean完全没有初始化的时候就可以实例化了,这也就是为什么对于BeanFactoryPostProcessor类型的bean在类中必须通过静态方法定义了,这种类对象会在很早就必须进行实例化了。
在这里插入图片描述
总结一下,将方法定义为静态方法实例化过程更简单,但是如果是要对其他方法定义的bean进行方法注入的话,则必须通过实例方法了,否则无法得到有效的增强。

同时也必须注意,这种增强也只是针对@Configuration注解的类(也叫full mode),而其他的,比如(@Component等 称为lite mode)是得不到增强的。比如在一个服务层的实现类中,一个方法没有添加事务注解,调用另一个添加事务注解的方法,其实都是没有事务的道理都是差不多的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lang20150928

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值