@Configuration和@Component區別


@Configuration詳解

一、@Configuration

@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Configuration { @AliasFor( annotation = Component.class ) String value() default ""; }

可以看到在@Configuration注解中是包含@Component注解的,被@Configuration修飾的類被定義為一個Spring容器(應用上下文)

@Configuration就相當於Spring配置文件中的<beans />標簽,里面可以配置bean

二、@Bean
@Bean相當於Spring配置文件中的<bean />標簽可以在Spring容器中注入一個bean

@Configuration public class TestConfiguration { @Bean public TestBean testBean() { return new TestBean(); } }

上述代碼相當於實例化一個TestBean並交給Spring容器管理

ps:

1、@Bean注解在返回實例的方法上,如果未通過@Bean指定bean的名稱,則默認與方法名相同

2、@Bean注解默認作用域為單例singleton作用域,可通過@Scope(“prototype”)設置為多例

三、依賴注入

@Configuration public class TestConfiguration { @Bean public TestBean testBean() { return new TestBean(); } @Bean public DIBean diBean() { return new DIBean(testBean()); } }

如上述代碼,通過在@Bean方法中調用其他@Bean注解的方法來實現依賴注入

ps:

當需要強制指定實例化bean的順序,可以通過@Order或@DependsOn注解來實現

除此之外我們還能使用@Component聲明Spring Bean

@Configuration和@Component區別

public class Car { private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } public class Driver { private int id; private String name; private Car car; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } }
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.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; } }
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Component 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; } }

上面兩段代碼除MyTestConfig類上的注解不同之外其他都相同,但Spring對兩者的處理方式是完全不一樣的。

  • 第一段代碼會像我們期望的一樣正常運行,因為driver()這段代碼中driver.setCar(car())方法會由Spring代理執行,

    Spring發現方法所請求的Bean已經在容器中,那么就直接返回容器中的Bean。所以全局只有一個Car對象的實例。

  • 第二段代碼在執行driver() 時driver.setCar(car())不會被Spring代理,會直接調用car()方法獲取一個全新的Car對象實例,所以全局會有多個Car對象的實例

造成這種差異的原因如下:

概括就是 @Configuration 中所有帶 @Bean 注解的方法都會被動態代理,因此調用該方法返回的都是同一個實例。

其工作原理是:如果方式是首次被調用那么原始的方法體會被執行並且結果對象會被注冊到Spring上下文中,之后所有的對該方法的調用僅僅只是從Spring上下文中取回該對象返回給調用者。

在上面的第二段代碼中,driver.setCar(car())只是純JAVA方式的調用,多次調用該方法返回的是不同的對象實例。

要修正第二段代碼中的問題,可以使用@Autowired如下所示:

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; //@Configuration @Component public class MyTestConfig2 { @Autowired Car car; @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; } }

驗證

import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class TestMain { public static void main(String[] args) { // TODO Auto-generated method stub // @Configuration注解的spring容器加載方式,用AnnotationConfigApplicationContext替換ClassPathXmlApplicationContext ApplicationContext context = new AnnotationConfigApplicationContext(MyTestConfig.class); // 獲取bean Driver driver = (Driver) context.getBean("driver"); // 獲取bean Car car = (Car) context.getBean("car"); boolean result = driver.getCar() == car; System.out.println(result ? "同一個car" : "不同的car"); } }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM