日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

@Component和@Configuration作为配置类的差别

發(fā)布時(shí)間:2025/3/12 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 @Component和@Configuration作为配置类的差别 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

隨著spingboot的大火,注解式配置受到了大家的熱烈歡迎,而@Component和@Configuration都可以作為配置類,之前一直都沒覺得這兩個(gè)用起來有什么差別,可能有時(shí)程序跑的和自己想的有所區(qū)別也沒注意到。

直到看到這篇文章:https://my.oschina.net/guangshan/blog/1807721 。我意識(shí)到@Component和@Configuration是有區(qū)別的,錯(cuò)誤的使用可能會(huì)導(dǎo)致嚴(yán)重的后果。

請看下面一段代碼:

@Configuration public class MyTestConfig {@Beanpublic Driver driver(){Driver driver = new Driver();driver.setId(1);driver.setName("driver");driver.setCar(car());return driver;}@Beanpublic Car car(){Car car = new Car();car.setId(1);car.setName("car");return car;} }測試代碼如下@RunWith(SpringRunner.class) @SpringBootTest public class TestApplicationTests {@Autowiredprivate Car car;@Autowiredprivate Driver driver;@Testpublic void contextLoads() {boolean result = driver.getCar() == car;System.out.println(result ? "同一個(gè)car" : "不同的car");}}打印結(jié)果如下: 同一個(gè)car

替換為Component后的打印結(jié)果:

不同的car

從上面的結(jié)果可以發(fā)現(xiàn)使用Configuration時(shí)在driver和spring容器之中的是同一個(gè)對象,而使用Component時(shí)是不同的對象。
造成不同結(jié)果的原因在ConfigurationClassPostProcessor類之中,通過調(diào)用enhanceConfigurationClasses方法,為被注解@Configuration的類進(jìn)行CGLIB代理,代碼如下:

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<String, AbstractBeanDefinition>();for (String beanName : beanFactory.getBeanDefinitionNames()) {BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {//判斷是否被@Configuration標(biāo)注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 immediatelyreturn;}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 classbeanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);try {// Set enhanced subclass of the user-specified bean classClass<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader);Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);//生成代理的classif (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()));}//替換class,將原來的替換為CGLIB代理的classbeanDef.setBeanClass(enhancedClass);}}catch (Throwable ex) {throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex);}}}

判斷是否為配置類的代碼如下:

//是否為配置類 public static boolean isConfigurationCandidate(AnnotationMetadata metadata) { return (isFullConfigurationCandidate(metadata) || isLiteConfigurationCandidate(metadata)); }//是否為完整配置類 public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) { return metadata.isAnnotated(Configuration.class.getName()); } //是否為精簡配置類 public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) {// Do not consider an interface or an annotation...if (metadata.isInterface()) {return false;}// Any of the typical annotations found?for (String indicator : candidateIndicators) {if (metadata.isAnnotated(indicator)) {return true;}}// Finally, let's look for @Bean methods...try {return metadata.hasAnnotatedMethods(Bean.class.getName());}catch (Throwable ex) {if (logger.isDebugEnabled()) {logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);}return false;} } //精簡配置類包含的注解 static {candidateIndicators.add(Component.class.getName());candidateIndicators.add(ComponentScan.class.getName());candidateIndicators.add(Import.class.getName());candidateIndicators.add(ImportResource.class.getName()); }

從上面可以看到,雖然Component注解也會(huì)當(dāng)做配置類,但是并不會(huì)為其生成CGLIB代理Class,所以在生成Driver對象時(shí)和生成Car對象時(shí)調(diào)用car()方法執(zhí)行了兩次new操作,所以是不同的對象。當(dāng)時(shí)Configuration注解時(shí),生成當(dāng)前對象的子類Class,并對方法攔截,第二次調(diào)用car()方法時(shí)直接從BeanFactory之中獲取對象,所以得到的是同一個(gè)對象。

至于產(chǎn)生CGLIB代理的流程,可以看一下下面鏈接,其中含有詳細(xì)介紹:https://my.oschina.net/guangshan/blog/1807721

總結(jié)

以上是生活随笔為你收集整理的@Component和@Configuration作为配置类的差别的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。