有迷茫,就会有困惑,有困惑,就有寻找答案的动力,尽管这一过程并不舒服,但是正如士兵突击里面许三多说的,人不能过的太舒服。
前言
我一直有一个疑问,就是@Configuration 和 @Component有什么区别?他们都能将对象放入spring容器,那他们的区别是什么呢?
带着这个困惑,今天终于找到了答案
@Configuration 注解:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
String value() default "";
}
上一篇中,我有说过@Configuration是 @Component的派生注解,@Configuration包含@Component的所有功能,那他本身有什么特性呢?他是怎么实现将类放入Spring容器的呢,我们来看看
特性:
- 配置类必须以类的形式提供(不能是工厂方法返回的实例),允许通过生成子类在运行时增强(cglib 动态代理)。
- 配置类不能是 final 类(没法动态代理)。
- 配置注解通常为了通过 @Bean 注解生成 Spring 容器管理的类,
- 配置类必须是非本地的(即不能在方法中声明,不能是 private)。
- 任何嵌套配置类都必须声明为static。
- @Bean 方法可能不会反过来创建进一步的配置类(也就是返回的 bean 如果带有 @Configuration,也不会被特殊处理,只会作为普通的 bean)
从特性中我们发现,@Configuration将配置的类放入容器实际是通过动态代理来实现的,通过具体的代码查看
在 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<String, AbstractBeanDefinition>();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
// 查询系统中所有带有@Configuration的bean定义
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
//省略部分代码
//将@Configuration的bean定义放入MAP集合
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);
// 使用动态代理 增强后的类替换原有的类 cglib动态代理的方式,见下面代码
Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
if (configClass != enhancedClass) {
//省略部分代码
beanDef.setBeanClass(enhancedClass);
}
}
catch (Throwable ex) {
throw new IllegalStateException(
"Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
}
}
}
cglib动态里生成增强类
private Enhancer newEnhancer(Class<?> superclass, ClassLoader classLoader) {
Enhancer enhancer = new Enhancer();
// cglib的动态代理是通过生成子类的形式
enhancer.setSuperclass(superclass);
enhancer.setInterfaces(new Class[]{ConfigurationClassEnhancer.EnhancedConfiguration.class});
enhancer.setUseFactory(false);
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ConfigurationClassEnhancer.BeanFactoryAwareGeneratorStrategy(classLoader));
enhancer.setCallbackFilter(CALLBACK_FILTER);
enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
return enhancer;
}
通过 cglib 代理的类在调用方法时,会通过 CallbackFilter 调用
private static final Callback[] CALLBACKS = new Callback[] {
new BeanMethodInterceptor(),
new BeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
};
private static final ConditionalCallbackFilter CALLBACK_FILTER =
new ConditionalCallbackFilter(CALLBACKS);
最终会匹配BeanMethodInterceptor 与BeanFactoryAwareMethodInterceptor类的 isMatch方法
public boolean isMatch(Method candidateMethod) {
return BeanAnnotationHelper.isBeanAnnotated(candidateMethod);
}
public boolean isMatch(Method candidateMethod) {
return candidateMethod.getName().equals("setBeanFactory") && candidateMethod.getParameterTypes().length == 1 && BeanFactory.class == candidateMethod.getParameterTypes()[0] && BeanFactoryAware.class.isAssignableFrom(candidateMethod.getDeclaringClass());
}
最终将@Bean修饰的对象放入Spring容器。
这里我们就十分清晰了@Configuration 的实现原理。
而@Component并没有使用动态代理,他是会直接将配置类放入spring容器。