首先我们来看下@Configuration这个注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@AliasFor(annotation = Component.class)
String value() default "";
boolean proxyBeanMethods() default true;
}
可以看到其实@Configuration注解本质上也是一个@Component注解,那么这两者之间有什么不同呢?我们下面去测试一下:
@Configuration
@ComponentScan("com.zyh.learning.springsource")
public class AppConfig {
}
@Component
public class A {
}
AnnotationConfigApplicationContext acf = new AnnotationConfigApplicationContext(AppConfig.class);
A a = acf.getBean(A.class);
System.out.println(a);
此时A类加了一个@Component注解并且通过包扫描的方式加入到spring容器中,然后我们从spring容器就可以获取到A这个bean
可以看到A打印出来的是一个普通的Java对象的地址,而此时我们把A类上的@Component注解换成@Configuration注解
@Configuration
public class A {
}
再从spring容器中获取A这个bean打印看看
神奇的是,打印出来的A的地址发生了变化,一眼看出来,发现A这个bean变成了一个由cglib创建的代理对象,所以,很明显,@Configuration注解和@Component注解都可以把对应的bean交给spring容器去管理,但是不一样的地方就在于,@Configuration注解所创建的bean是一个cglib代理对象,而@Component注解只是创建一个普通的Java对象
现在我们知道@Configuration注解和@Component注解都可以把bean放到spring容器进行管理,那么@Configuration注解把bean变成一个代理对象的作用是什么呢?我们现在看这样的一种场景:
@Component
public class AppConfig {
@Bean
public MyService myService() {
MyService myService = new MyService();
myService.setUserService(userService());
return myService;
}
@Bean
public UserService userService() {
return new UserService();
}
}
public class UserService {
public UserService() {
System.out.println("UserService...");
}
}
我们在AppConfig配置类上加上@Component注解,然后通过@Bean注解的方式注入MyService和UserService这两个bean,并且在MyService的@Bean方法中还调用UserService的@Bean方法,现在我们来启动下spring容器看一下
可以看到UserService的@Bean方法调用了两次,创建了两个UserService实例,那我们把AppConfig配置类上的@Component注解换成@Configuration注解看下会不会不一样
可以看到把@Component注解换成了@Configuration注解之后,UserService的@Bean方法只调用了一次,也就是UserService实例只创建了一个,所以@Configuration注解就是为了避免用户显式地去调用@Bean方法,造成破坏了@Bean方法的bean的单例,而@Configuration注解能够做到这样避免用户显式调用@Bean方法的原理就是通过创建对应的配置类cglib代理对象去实现的,下面我们重点看一下@Configuraton注解底层是怎么通过cglib代理去实现@Bean方法不被用户显式调用
org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanFactory
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));
}
ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor接口,而BeanDefinitionRegistryPostProcessor接口又是继承于BeanFactoryPostProcessor接口,众所周知BeanFactoryPostProcessor接口接口是一个BeanFactory的后置处理接口,也就是在BeanFactory初始化之后会调用该接口的postProcessBeanFactory方法,也就是上面的方法,其中里面会再调用enhanceConfigurationClasses方法,该方法就是生成cglib代理的关键方法
org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanFactory
/**
* 从spring容器中找到所有候选的BeanDefinitions,候选状态由BeanDefinition的属性元数据确定(找到全配置的配置类,也就是加了@Configuration注解的配置类)
* 然后通过{@link ConfigurationClassEnhancer}增强去对这些配置类进行cglib增强代理
* @see ConfigurationClassEnhancer
*/
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
Map configBeanDefs = new LinkedHashMap<>();
// 遍历当前spring容器中所有的bd名称,这个for循环的目的就是找到所有全配置类(加了@Configuration注解的配置类)
for (String beanName : beanFactory.getBeanDefinitionNames()) {
// 根据bd名称获取到bd
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
// 获取到CONFIGURATION_CLASS_ATTRIBUTE对应的属性值
Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
AnnotationMetadata annotationMetadata = null;
MethodMetadata methodMetadata = null;
if (beanDef instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDef;
annotationMetadata = annotatedBeanDefinition.getMetadata();
methodMetadata = annotatedBeanDefinition.getFactoryMethodMetadata();
}
if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
// Configuration class (full or lite) or a configuration-derived @Bean method
// -> eagerly resolve bean class at this point, unless it's a 'lite' configuration
// or component class without @Bean methods.
AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
if (!abd.hasBeanClass()) {
boolean liteConfigurationCandidateWithoutBeanMethods =
(ConfigurationClassUtils.CONFIGURATION_CLASS_LITE.equals(configClassAttr) &&
annotationMetadata != null && !ConfigurationClassUtils.hasBeanMethods(annotationMetadata));
if (!liteConfigurationCandidateWithoutBeanMethods) {
try {
abd.resolveBeanClass(this.beanClassLoader);
}
catch (Throwable ex) {
throw new IllegalStateException(
"Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
}
}
}
}
// 条件成立:说明这个bd对应的是一个配置类
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");
}
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;
}
// 如果这个类是一个全配置类,那么就使用cglib进行代理增强,目的是防止@Bean方法的手动重复调用造成单例的破坏
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);
// Set enhanced subclass of the user-specified bean class
Class> configClass = beanDef.getBeanClass();
// 给这个全配置类创建一个cglib增强后的Class对象
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()));
}
// 把cglib代理的Class对象设置到这个全配置类的bd中
beanDef.setBeanClass(enhancedClass);
}
}
}
该方法的代码很多,但是做的事情很明确,就是去遍历spring容器中的所有BeanDefinition,找出扩展属性CONFIGURATION_CLASS_ATTRIBUTE对应的值等于CONFIGURATION_CLASS_FULL的BeanDefinition,那么这个属性从哪里来的呢?在执行postProcessBeanFactory方法之前,spring会去解析所有的配置类,包括包扫描,@Import的处理等等,简单来说就是会把能够给spring管理的bean对应的BeanDefinition都找出来放入到spring容器中,而这些BeanDefinition又分为两种,一种是全配置类,一种是半配置类,全配置类就是加了@Configuration注解并且proxyBeanMethods属性等于true,半配置类则是加了@Component,@ComponentScan,@Import,@ImportResource这几个注解的类(或者加了@Configuration注解但是proxyBeanMethods属性等于false),对于全配置类CONFIGURATION_CLASS_ATTRIBUTE对应的值就等于CONFIGURATION_CLASS_FULL,而对于半配置类CONFIGURATION_CLASS_ATTRIBUTE对应的值等于CONFIGURATION_CLASS_LITE。所以这里其实就是把加了@Configuration注解并且proxyBeanMethods属性等于true的BeanDefinition找出来。找出来之后需要干嘛呢?我们上面不是说了要创建对应的cglib代理吗,所以接下来需要去获取一个cglib增强之后的Class对象设置到这个BeanDefinition中了,而怎么去获取呢?这里就通过一个spring的一个cglib工具类ConfigurationClassEnhancer,该工具类封装了cglib的api,然后专门给全配置类去创建对应的cglib增强Class对象,具体增强的逻辑在ConfigurationClassEnhancer中已经定义好了,调用ConfigurationClassEnhancer的enhance方法,传入原始的Class对象就能够返回一个增强的cglib
org.springframework.context.annotation.ConfigurationClassEnhancer#enhance
public Class> enhance(Class> configClass, @Nullable ClassLoader classLoader) {
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 " +
"). This is harmless, but you may " +
"want check your configuration and remove one CCPP if possible",
configClass.getName()));
}
return configClass;
}
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;
}
org.springframework.context.annotation.ConfigurationClassEnhancer#newEnhancer
/**
* 创建一个新的CGLIB{@link Enhancer}实例
*/
private Enhancer newEnhancer(Class> configSuperClass, @Nullable ClassLoader classLoader) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(configSuperClass);
// 给配置类代理实现EnhancedConfiguration接口,该接口又继承了BeanFactoryAware接口,所以在配置类进行实例化的过程中能够回调到setBeanFactory方法
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;
}
可以看到在newEnhancer方法中都是调用cglib的api,比如设置superClass为需要增强的原始Class对象,设置代理要实现的接口,设置增强逻辑Callback等等
org.springframework.context.annotation.ConfigurationClassEnhancer#createClass
private Class> createClass(Enhancer enhancer) {
Class> subclass = enhancer.createClass();
// Registering callbacks statically (as opposed to thread-local)
// is critical for usage in an OSGi environment (SPR-5932)...
Enhancer.registerStaticCallbacks(subclass, CALLBACKS);
return subclass;
}
然后最后调用enhancer的createClass方法,就可以得到一个增强后的Class对象,返回出去之后把这个增强的Class对象设置到BeanDefinition中就可以了
(1)CallbackFilter
在创建enhancer对象时候,spring设置了一个CallbackFilter
private static class ConditionalCallbackFilter implements CallbackFilter {
private final Callback[] callbacks;
private final Class>[] callbackTypes;
public ConditionalCallbackFilter(Callback[] callbacks) {
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) {
for (int i = 0; i < this.callbacks.length; i++) {
Callback callback = this.callbacks[i];
if (!(callback instanceof ConditionalCallback) || ((ConditionalCallback) callback).isMatch(method)) {
return i;
}
}
throw new IllegalStateException("No callback available for method " + method.getName());
}
public Class>[] getCallbackTypes() {
return this.callbackTypes;
}
}
CallbackFilter的作用就是,当执行目标方法的时候会被accept方法拦截,在accpet方法会根据传入的目标方法去返回一个Callback增强,也就是通过这个CallbackFilter就可以实现调用不同的方法使用不同的增强Callback,而spring这里传的是ConditionalCallbackFilter,这个CallbackFilter在创建的时候需要传入一个Callback数组,这个Callback数组就是给accept方法去筛选具体的Callback返回的,我们下面看一下Callback数组中的Callback是哪几个
/**
* 回调数组,根据CALLBACK_FILTER中accept方法返回的索引值去从该数组中选择对应的Callback
*/
private static final Callback[] CALLBACKS = new Callback[] {
new BeanMethodInterceptor(),
new BeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
};
spring传了三个Callback,分别是BeanMethodInterceptor,BeanFactoryAwareMethodInterceptor,NoOp.INSTANCE,最后一个NoOp.INSTANCE就是表示什么都不增强的意思,重点是BeanMethodInterceptor和BeanFactoryAwareMethodInterceptor
(2)给目标方法匹配Callback
在CallbackFilter的accpet方法中会通过每一个Callback的isMatch方法去对目标方法判断需要使用哪一个增强Callback进行增强,下面就看下BeanMethodInterceptor和BeanFactoryAwareMethodInterceptor这两个Callback的具体匹配条件
org.springframework.context.annotation.ConfigurationClassEnhancer.BeanMethodInterceptor#isMatch
public boolean isMatch(Method candidateMethod) {
// 方法匹配条件:调用的方法不能是Object的方法,不是setBeanFactory方法,方法上需要有@Bean注解
return (candidateMethod.getDeclaringClass() != Object.class &&
!BeanFactoryAwareMethodInterceptor.isSetBeanFactory(candidateMethod) &&
BeanAnnotationHelper.isBeanAnnotated(candidateMethod));
}
BeanMethodInterceptor的isMatch方法的匹配条件是:调用的方法不能是Object的方法,不是BeanFactoryAware接口的setBeanFactory方法,方法上需要有@Bean注解,简单的总结就是我们写的@Bean方法
org.springframework.context.annotation.ConfigurationClassEnhancer.BeanFactoryAwareMethodInterceptor#isMatch
public boolean isMatch(Method candidateMethod) {
// 调用方法匹配条件:调用的方法是BeanFactoryAware接口的setBeanFactory方法
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()));
}
BeanFactoryAwareMethodInterceptor的isMatch方法的匹配条件则是:调用的方法是BeanFactoryAware接口的setBeanFactory方法。这里可能有人有个疑问,就是我们的配置类并没有实现BeanFactoryAware接口啊,从何而来的调用BeanFactoryAware接口的setBeanFactory方法呢?我们还是回到enhancer设置属性,看到有一个setInterfaces的属性设置,该属性就是设置代理对象需要实现的接口,而spring在这个属性中设置了EnhancedConfiguration这个接口
enhancer.setInterfaces(new Class>[] {EnhancedConfiguration.class});
但是可能有人会问,这也不是BeanFactoryAware接口呀,但是其实EnhancedConfiguration这个接口就是继承于BeanFactoryAware接口的
public interface EnhancedConfiguration extends BeanFactoryAware {
}
所以自然地cglib代理对象中自然就会有这个BeanFactoryAware接口的setBeanFactory方法了
(3)方法增强
①BeanFactoryAwareMethodInterceptor
org.springframework.context.annotation.ConfigurationClassEnhancer.BeanFactoryAwareMethodInterceptor#intercept
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这个属性赋值,值等于BeanFactory对象
field.set(obj, args[0]);
// 判断配置类是否已经实现了BeanFactoryAware接口,如果实现了,那么此时还需要调用该配置类自己实现的setBeanFactory方法
if (BeanFactoryAware.class.isAssignableFrom(ClassUtils.getUserClass(obj.getClass().getSuperclass()))) {
return proxy.invokeSuper(obj, args);
}
return null;
}
我们现在已经知道了BeanFactoryAwareMethodInterceptor这个Callback增强的目标方法是BeanFactoryAware接口的setBeanFactory方法,那么setBeanFactory这个方法什么时候会被调用呢?如果大家熟知bean的生命周期的话可以知道,如果一个bean实现了BeanFactoryAware接口的话,那么在实例化的过程中会回调BeanFactoryAware接口的setBeanFactory方法,而已回调的时候会把BeanFactory对象传给setBeanFactory方法。然后在spring回调setBeanFactory方法的时候,BeanFactoryAwareMethodInterceptor这个Callback就能够拦截到,执行intercept方法中的增强逻辑。在intercept方法中做的其实就是把回调过来的BeanFactory对象赋值给属性名称为$$beanFactory的属性,那么这里可能就有人会问了,$$beanFactory这个属性哪里来的?原来的配置类也没有这个属性呀,答案就是在cglib创建代理的时候,会生成$$beanFactory这个名称的属性,是在哪里设置生成$$beanFactory这个属性的呢?我们继续回看spring在设置enhancer属性的时候,有一个strategy的属性
enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
setStrategy属性可以设置生成代理类的class文件字节码策略,这里具体设置的策略是BeanFactoryAwareGeneratorStrategy
private static class BeanFactoryAwareGeneratorStrategy extends
ClassLoaderAwareGeneratorStrategy {
public BeanFactoryAwareGeneratorStrategy(@Nullable ClassLoader classLoader) {
super(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);
}
}
private static final String BEAN_FACTORY_FIELD = "$$beanFactory";
可以大概地看到在BeanFactoryAwareGeneratorStrategy中做的就是给生成的代理类添加一个属性,属性名为$$beanFactory,访问域是public,属性类型是BeanFactory。那么现在就可以总结下BeanFactoryAwareMethodInterceptor这个Callback的作用了,它的作用就是在spring回调BeanFactoryAware接口的seetBeanFactory方法的时候,把回调的BeanFactory对象赋值给$$beanFactory属性,而这个属性的由来就是cglib在创建代理类的时候添加进来的
②BeanMethodInterceptor
org.springframework.context.annotation.ConfigurationClassEnhancer.BeanMethodInterceptor#intercept
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
MethodProxy cglibMethodProxy) throws Throwable {
// 获取到$$beanFactory属性的值,也就是BeanFactory对象
ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
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;
}
}
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);
}
}
// 条件成立:说明此时spring正在执行反射执行这个@Bean方法
if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
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()));
}
// 调用父类的原始@Bean方法返回bean实例,返回的bean实例会注册到spring容器中
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
}
// 代码来到这里说明此时的@Bean方法并不是由spring调用的,而是用户自身的代码显示调用的
// 这种情况也就是在@Bean方法A中调用@Bean方法B,在调用@Bean方法B的时候上面的条件就不会成立,所以会执行到这里
// 从BeanFactory中获取bean
return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}
BeanMethodInterceptor的intercept方法比较长,关键的我们主要看最后的if判断
private boolean isCurrentlyInvokedFactoryMethod(Method method) {
Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
return (currentlyInvoked != null && method.getName().equals(currentlyInvoked.getName()) &&
Arrays.equals(method.getParameterTypes(), currentlyInvoked.getParameterTypes()));
}
在这个方法中主要就是SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod()这句代码会返回一个Method,那么这句代码的意思是什么呢?还有返回的Method又到底是什么?这里的话就要牵扯到bean实例化的时候了。我们先跳到spring在处理通过@Bean的方式实例bean的那块代码
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#instantiateUsingFactoryMethod
org.springframework.beans.factory.support.ConstructorResolver#instantiateUsingFactoryMethod
org.springframework.beans.factory.support.SimpleInstantiationStrategy#instantiate(org.springframework.beans.factory.support.RootBeanDefinition, java.lang.String, org.springframework.beans.factory.BeanFactory, java.lang.Object, java.lang.reflect.Method, java.lang.Object...)
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
在spring实例化bean的时候会通过反射去调用这个bean所在的配置类的@Bean方法,而且在调用之前会把这个@Bean方法放到currentlyInvokedFactoryMethod中,那么放进去有什么作用呢?我们可以想一下,这一步是spring实例化bean的时候才触发的,如果我们是手动的调用这个@Bean方法,那么是根本不会调用到上面的方法的,currentlyInvokedFactoryMethod中也就不会有这个@Bean方法,然后此时回到isCurrentlyInvokedFactoryMethod方法的判断中
private boolean isCurrentlyInvokedFactoryMethod(Method method) {
Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
return (currentlyInvoked != null && method.getName().equals(currentlyInvoked.getName()) &&
Arrays.equals(method.getParameterTypes(), currentlyInvoked.getParameterTypes()));
}
判断的条件是currentlyInvoked不等于空,并且当前调用的目标方法要和currentlyInvoked方法名称,参数相同。如果该方法返回true,结合上面spring实例化bean的过程可以说明当前这个@Bean方法spring正在调用,而如果返回false的话,那么就表示当前这个@Bean方法并不是由spring实例化去调用的,而是我们用户手动去调用的,此时的话就会执行resolveBeanReference方法,resolveBeanReference方法就会从spring容器中去拿这个@Bean方法方法所对应的bean并返回,resolveBeanReference方法代码如下:
private Object resolveBeanReference(Method beanMethod, Object[] beanMethodArgs,
ConfigurableBeanFactory beanFactory, String beanName) {
boolean alreadyInCreation = beanFactory.isCurrentlyInCreation(beanName);
try {
if (alreadyInCreation) {
beanFactory.setCurrentlyInCreation(beanName, false);
}
boolean useArgs = !ObjectUtils.isEmpty(beanMethodArgs);
if (useArgs && beanFactory.isSingleton(beanName)) {
for (Object arg : beanMethodArgs) {
if (arg == null) {
useArgs = false;
break;
}
}
}
// 从spring容器中获取这个bean
Object beanInstance = (useArgs ? beanFactory.getBean(beanName, beanMethodArgs) :
beanFactory.getBean(beanName));
if (!ClassUtils.isAssignableValue(beanMethod.getReturnType(), beanInstance)) {
// Detect package-protected NullBean instance through equals(null) check
if (beanInstance.equals(null)) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("@Bean method %s.%s called as bean reference " +
"for type [%s] returned null bean; resolving to null value.",
beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
beanMethod.getReturnType().getName()));
}
beanInstance = null;
}
else {
String msg = String.format("@Bean method %s.%s called as bean reference " +
"for type [%s] but overridden by non-compatible bean instance of type [%s].",
beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
beanMethod.getReturnType().getName(), beanInstance.getClass().getName());
try {
BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(beanName);
msg += " Overriding bean of same name declared in: " + beanDefinition.getResourceDescription();
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore - simply no detailed message then.
}
throw new IllegalStateException(msg);
}
}
Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
if (currentlyInvoked != null) {
String outerBeanName = BeanAnnotationHelper.determineBeanNameFor(currentlyInvoked);
// 注册两个bean之间的依赖关系
beanFactory.registerDependentBean(beanName, outerBeanName);
}
return beanInstance;
}
finally {
if (alreadyInCreation) {
beanFactory.setCurrentlyInCreation(beanName, true);
}
}
}
关键就是调用了getBean方法从spring容器中获取这个@Bean方法对应的bean
@Configuration注解能够使得加了它的对应的配置类在spring容器中是一个cglib代理bean,让配置类实例变成cglib代理实例的作用就是防止@Bean方法A又调用@Bean方法B的这种场景破坏了bean的单例性。解决这种场景的原理就是在spring实例化@Bean方法A对应的bean的时候,会通过反射调用配置类的@Bean方法A,在反射调用之前@Bean方法A放到currentlyInvokedFactoryMethod中,然后由于配置类已经是一个cglib代理对象了,所以会被BeanMethodInterceptor这个Callback进行拦截增强,此时判断到currentlyInvokedFactoryMethod中存在方法A,那么就直接执行这个@Bean方法A了,而@Bean方法A中又调用了@Bean方法B,所以此时在执行@Bean方法A的时候,@Bean方法B也会被BeanMethodInterceptor这个Callback所拦截增强,但是,此时currentlyInvokedFactoryMethod中的方法是@Bean方法A,所以isCurrentlyInvokedFactoryMethod方法判断返回的是false,也就是走resolveBeanReference方法从spring容器中去获取@Bean方法B对应的bean