这个注解在项目开发中出现在配置类上面,配置类有无这个注解都没有问题,那么此注解的作用是神马呢?
现象
#Demo#
@ComponentScan("com.spring.test.ch04")
@Configuration
public class Ch04Config {
@Bean
public UserService userService(){
UserService userService = new UserService();
System.out.println("创建UserService "+ userService);
return userService;
}
@Bean
public OrderService orderService(){
UserService userService = userService();
System.out.println("创建OrderService "+ userService);
return new OrderService(userService);
}
}
public class OrderService {
public OrderService(UserService userService) {
System.out.println("orderService 构造方法");
}
}
public class UserService {
}
public class Ch04Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
ac.register(Ch04Config.class);
ac.refresh();
System.out.println(ac.getBean("orderService"));
}
}
复制代码
从以上现象可以得知有 @Configuration 注解的时候配置类的在 spring 的容器中存储的是一个代理对象。
从以上现象可以得知
分析
有 @Configuration 注解情况下 Spring 是如何避免 UserService 两次实例化的呢?要分析根因就的死磕源码。
首先 spring 根据配置类生成 BeanDefinition 的时候,判断类是有 @Configuration 注解且 proxyBeanMethods 为 true(该属性默认是 true)的情况,在 BeanDefinition 中存入一个属性 CONFIGURATION_CLASS_ATTRIBUTE 的值是 full,否则是 lite;
ConfigurationClassPostProcessor
#postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
#processConfigBeanDefinitions(BeanDefinitionRegistry registry)
#checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory)
// 获取Configuration注解的属性信息,配置类分两种,被@Configuration标记的配置类为full,其他的配置类为lite,full的配置类会生成代理对象
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
// 注意,并不是没有Configuration注解当前BeanDefinition就不是一个配置类
// 注意isConfigurationCandidate方法,会检查是否存在@Component, @ComponentScan,@Import,@ImportResource,@Bean注解
else if (config != null || isConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
// 如果没有Configuration注解信息,则返回false,表示不是一个配置类
return false;
}
复制代码
ConfigurationClassPostProcessor
#postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
#enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory)
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
MethodMetadata methodMetadata = null;
if (beanDef instanceof AnnotatedBeanDefinition) {
methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
}
if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
// Configuration class (full or lite) or a configuration-derived @Bean method
// -> resolve bean class at this point...
AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
if (!abd.hasBeanClass()) {
try {
abd.resolveBeanClass(this.beanClassLoader);
}
catch (Throwable ex) {
throw new IllegalStateException(
"Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
}
}
}
// 被@Configuration标注的配置类就是full
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);
}
}
// 加了@Configuration注解的配置类的BeanDefinition
if (configBeanDefs.isEmpty()) {
// nothing to enhance -> return immediately
return;
}
// 生成AppConfig的代理对象
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);
// Set enhanced subclass of the user-specified bean class
Class<?> configClass = beanDef.getBeanClass();
// 增强类
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()));
}
// 将增强类设置给beanDefinition,后续基于BeanDefinition产生的bean就是增加类的对象了
beanDef.setBeanClass(enhancedClass); // AppConfig--->Bean 代理对象
}
}
}
/**
* Loads the specified class and generates a CGLIB subclass of it equipped with
* container-aware callbacks capable of respecting scoping and other bean semantics.
* @return the enhanced subclass
*/
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 " +
"<context:annotation-config>). 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;
}
/**
* Creates a new CGLIB {@link Enhancer} instance.
*/
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(configSuperClass);
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;
}
复制代码
cglib 代理主要是对我们的方法进行拦截增强,当我们执行 Ch04Config 中的方法的时候会去执行 cglib 代理类中的代理方法,主要就是 callBacks 中的方法
ConfigurationClassEnhancer
#BeanMethodInterceptor
#intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs
MethodProxy cglibMethodProxy)
/**
* Check whether the given method corresponds to the container's currently invoked
* factory method. Compares method name and parameter types only in order to work
* around a potential problem with covariant return types (currently only known
* to happen on Groovy classes).
*/
private boolean isCurrentlyInvokedFactoryMethod(Method method) {
Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
return (currentlyInvoked != null && method.getName().equals(currentlyInvoked.getName()) &&
Arrays.equals(method.getParameterTypes(), currentlyInvoked.getParameterTypes()));
}
复制代码
比如当前正在进行实例化的是 orderService()方法所对应的 bean,而在 orderService()方法中会调用 userService()方法,isCurrentlyInvokedFactoryMethod 这个时候下面这个判断等于 false,而等于 false,就不会真正去执行 userService()方法了,就会直接去 beanFactory 中去获取 bean。
总结
配置类加上 @Configuration 注解主要是给类加上了 cglib 代理。在执行配置类的方法时,会执行 cglib 代理类中的方法,其中有一个非常重要的判断,当我们的执行方法和我们的调用方法是同一个方法时,会执行父类的方法 new(cglib 代理基于继承);当执行方法和调用方法不是同一个方法时会调用 beanFactory.getBean 获取。
评论