@Component和@Configuration作为配置类的差别
隨著spingboot的大火,注解式配置受到了大家的熱烈歡迎,而@Component和@Configuration都可以作為配置類,之前一直都沒覺得這兩個用起來有什么差別,可能有時程序跑的和自己想的有所區別也沒注意到。
直到看到這篇文章:https://my.oschina.net/guangshan/blog/1807721 。我意識到@Component和@Configuration是有區別的,錯誤的使用可能會導致嚴重的后果。
請看下面一段代碼:
@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 ? "同一個car" : "不同的car");}}打印結果如下: 同一個car替換為Component后的打印結果:
不同的car從上面的結果可以發現使用Configuration時在driver和spring容器之中的是同一個對象,而使用Component時是不同的對象。
造成不同結果的原因在ConfigurationClassPostProcessor類之中,通過調用enhanceConfigurationClasses方法,為被注解@Configuration的類進行CGLIB代理,代碼如下:
判斷是否為配置類的代碼如下:
//是否為配置類 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注解也會當做配置類,但是并不會為其生成CGLIB代理Class,所以在生成Driver對象時和生成Car對象時調用car()方法執行了兩次new操作,所以是不同的對象。當時Configuration注解時,生成當前對象的子類Class,并對方法攔截,第二次調用car()方法時直接從BeanFactory之中獲取對象,所以得到的是同一個對象。
至于產生CGLIB代理的流程,可以看一下下面鏈接,其中含有詳細介紹:https://my.oschina.net/guangshan/blog/1807721
總結
以上是生活随笔為你收集整理的@Component和@Configuration作为配置类的差别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PyTorch随笔-4
- 下一篇: python精要(66)—类(3)-文档