这个注解在项目开发中出现在配置类上面,配置类有无这个注解都没有问题,那么此注解的作用是神马呢?
现象
#Demo#
@ComponentScan("com.spring.test.ch04")@Configurationpublic 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 获取。
评论