@Component和@Configuration作為配置類的差別

海峽發表於2020-12-10

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

直到看到這篇文章:my.oschina.net/guangshan/blog/1807... 。我意識到@Component和@Configuration是有區別的,錯誤的使用可能會導致嚴重的後果。

請看下面一段程式碼:

@Configuration
public class MyTestConfig {

    @Bean
    public Driver driver(){
        Driver driver = new Driver();
        driver.setId(1);
        driver.setName("driver");
        driver.setCar(car());
        return driver;
    }

    @Bean
    public Car car(){
        Car car = new Car();
        car.setId(1);
        car.setName("car");
        return car;
    }
}

測試程式碼如下

@RunWith(SpringRunner.class)
@SpringBootTest
public class TestApplicationTests {

    @Autowired
    private Car car;

    @Autowired
    private Driver driver;

    @Test
    public void contextLoads() {
        boolean result = driver.getCar() == car;
        System.out.println(result ? "同一個car" : "不同的car");
    }

}

列印結果如下:
同一個car

替換為Component後的列印結果:
不同的car
從上面的結果可以發現使用Configuration時在driver和spring容器之中的是同一個物件,而使用Component時是不同的物件。
造成不同結果的原因在ConfigurationClassPostProcessor類之中,透過呼叫enhanceConfigurationClasses方法,為被註解@Configuration的類進行CGLIB代理.
雖然Component註解也會當做配置類,但是並不會為其生成CGLIB代理Class,所以在生成Driver物件時和生成Car物件時呼叫car()方法執行了兩次new操作,所以是不同的物件。當時Configuration註解時,生成當前物件的子類Class,並對方法攔截,第二次呼叫car()方法時直接從BeanFactory之中獲取物件,所以得到的是同一個物件。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章