在springboot中我们经常使用@Configuration来配置项目中的配置类的bean。 那么它到底有什么用呢。追根溯源,还是回到spring的源码中来看。 首先演示下不加@Configuration的场景,其实可以发现bean依然可以注入进来,没有任何问题。
上代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Application {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Configure.class);
TestDaoImpl testDao = annotationConfigApplicationContext.getBean(TestDaoImpl.class);
testDao.test();
}
}
@ComponentScan(value = "com.clear")
public class Configure {
@Bean
public TestDaoImpl testDaoImpl() {
return new TestDaoImpl();
}
}
public class TestDaoImpl {
public void test() {
System.out.println("test");
}
}
可以看到我在TestDaoImpl中没有添加@Component/@Service/@Repository样的声明, 只是在Configure类中以@Bean并new一个TestDaoImpl 方式注入到spring容器中,使用没有问题,那么为什么要加@Configuration注解呢,是用来解决什么样的问题呢。
核心实现在ConfigurationClassPostProcessor中,我贴出较为关键的代码分析下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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.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<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) {
//完成对全注解类的cglib代理
Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
if (configClass != enhancedClass) {
if (logger.isDebugEnabled()) {
logger.debug(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);
}
}
}
当类添加了@Configuration注解后会由cglib对其实现动态代理,那么来看下newEnhancer方法实现。
1
2
3
4
5
6
7
8
9
10
11
12
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(configSuperClass);
//增强接口,主要是需要通过该接口获取到beanFactory
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;
}
既然是代理那么就需要重点关注它的回调方法,这里提供的回调方法是一个数组
1
2
3
4
5
6
private static final Callback[] CALLBACKS = new Callback[] {
//核心逻辑
new BeanMethodInterceptor(),
new BeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
};
那么继续跟进到BeanMethodInterceptor中去看intercept方法,主要看这段逻辑
1
2
3
4
5
if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
}
return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
isCurrentlyInvokedFactoryMethod方法的实现,
1
2
3
4
5
private boolean isCurrentlyInvokedFactoryMethod(Method method) {
Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
return (currentlyInvoked != null && method.getName().equals(currentlyInvoked.getName()) &&
Arrays.equals(method.getParameterTypes(), currentlyInvoked.getParameterTypes()));
}
这里就是判断@Configuration配置的bean中如果当@Bean中需要引用到另外一个bean的时候是创建一个新的bean还是引用之前创建的bean问题, 也就是为了遵守单例原则,做的一次判断。这里的判断是第二次来创建bean的方法是否与第一次来创建bean的方法一样, 显然,第二次来创建bean的方法是代理方法与第一次不一样,则第二次来创建的bean的时候直接从beanFactory中获取即可。