深入理解@component與@Configuration注解
1、@Configuration
從Spring3.0,@Configuration用于定義配置類,可替換xml配置文件,被注解的類內部包含有一個或多個被@Bean注解的方法,這些方法將會被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext類進行掃描,并用于構建bean定義,初始化Spring容器。
注意:@Configuration注解的配置類有如下要求:
1、@Configuration不可以是final類型;
2、@Configuration不可以是匿名類;
3、嵌套的configuration必須是靜態(tài)類。
用@Configuration加載spring的用法
@Configuration配置spring并啟動spring容器
@Configuration標注在類上,相當于把該類作為spring的xml配置文件中的,作用為:配置spring容器(應用上下文)
@Configuration啟動容器+@Bean注冊Bean
@Bean下管理bean的生命周期
可以使用基于 Java 的配置來管理 bean 的生命周期。@Bean 支持兩種屬性,即 initMethod和destroyMethod,這些屬性可用于定義生命周期方法。在實例化 bean或即將銷毀它時,容器便可調用生命周期方法。生命周期方法也稱為回調方法,因為它將由容器調用。使用 @Bean 注釋注冊的 bean 也支持JSR-250 規(guī)定的標準 @PostConstruct 和 @PreDestroy 注釋。如果您正在使用 XML 方法來定義bean,那么就應該使用 bean 元素來定義生命周期回調方法。
@Bean標注在方法上(返回某個實例的方法),等價于spring的xml配置文件中的作用:注冊bean對象
@Bean注解在返回實例的方法上,如果未通過@Bean指定bean的名稱,則默認與標注的方法名相同; @Bean注解默認作用域為單例singleton作用域,可通過@Scope(“prototype”)設置為原型作用域; 既然@Bean的作用是注冊bean對象,那么完全可以使用@Component、@Controller、@Service、@Ripository等注解注冊bean,當然需要配置@ComponentScan注解進行自動掃描。
- @Configuration啟動容器+@Component注冊Bean
- 使用 AnnotationConfigApplicationContext 注冊 AppContext 類的兩種方法
- 配置Web應用程序(web.xml中配置AnnotationConfigApplicationContext)
2、@component注解
1、@controller 控制器(注入服務)
2、@service 服務(注入dao)
3、@repository dao(實現dao訪問)
4、@component (把普通pojo實例化到spring容器中,相當于配置文件中的<bean id="" class=""/>)
如果 Web 應用程序采用了經典的三層分層結構的話,最好在持久層、業(yè)務層和控制層分別采用 @Repository、@Service 和 @Controller 對分層中的類進行注釋,而用 @Component 對那些比較中立的類進行注釋。 在 一個稍大的項目中,通常會有上百個組件,如果這些組件采用xml的bean定義來配置,顯然會增加配置文件的體積,查找以及維護起來也不太方便。 Spring2.5為我們引入了組件自動掃描機制,他可以在類路徑底下尋找標注了 @Component,@Service,@Controller,@Repository注解的類,并把這些類納入進spring容器中管理。它的作用 和在xml文件中使用bean節(jié)點配置組件時一樣的。
說明: <context:component-scan base-package=”com.*”> 上面的這個例子是引入Component組件的例子,其中base-package表示為需要掃描的所有子包。
共同點:被@controller 、@service、@repository 、@component 注解的類,都會把這些類納入進spring容器中進行管理
3、@configuration和@component之間的區(qū)別
@configuration和@component之間的區(qū)別是:@Component注解的范圍最廣,所有類都可以注解,但是@Configuration注解一般注解在這樣的類上:這個類里面有@Value注解的成員變量和@Bean注解的方法,就是一個配置類。
展示兩個注解的配圖
可以看出@Configuration注解中有@Component注解 從定義來看,@Configuration 注解本質上還是@Component,因此context:component-scan/ 或者 @ComponentScan都能處理@Configuration注解的類。
@Configuration標記的類必須符合下面的要求:
- 配置類必須以類的形式提供(不能是工廠方法返回的實例),允許通過生成子類在運行時增強(cglib 動態(tài)代理)。
- 配置類不能是 final類(沒法動態(tài)代理)。
- 配置注解通常為了通過 @Bean 注解生成 Spring 容器管理的類,配置類必須是非本地的(即不能在方法中聲明,不能是private)。
- 任何嵌套配置類都必須聲明為static。
- @Bean方法可能不會反過來創(chuàng)建進一步的配置類(也就是返回的 bean 如果帶有@Configuration,也不會被特殊處理,只會作為普通的bean)
加載過程
Spring 容器在啟動時,會加載默認的一些PostProcessor,其中就有ConfigurationClassPostProcessor,這個后置處理程序專門處理帶有@Configuration注解的類,這個程序會在bean 定義加載完成后,在bean初始化前進行處理。主要處理的過程就是使用cglib動態(tài)代理增強類,而且是對其中帶有@Bean注解的方法進行處理。
基于Java的配置我們通常使用@Configuration注解來聲明Spring Bean 除此之外我們還能使用@Component聲明Spring Bean
具體實例驗證兩者的區(qū)別,下面代碼使用@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注解除Config類上的注解不同之外其他都相同,Spring對兩者的處理方式就會完全不一樣。
- @configuration:會像我們期望的一樣正常運行,因為new SimpleBeanConsumer(simpleBean())這段代碼中simpleBean()方法會由Spring代理執(zhí)行,Spring發(fā)現方法所請求的Bean已經在容器中,那么就直接返回容器中的Bean。所以全局只有一個SimpleBean對象的實例。
- @component:在執(zhí)行new SimpleBeanConsumer(simpleBean()) 時simpleBean()不會被Spring代理,會直接調用simpleBean()方法獲取一個全新的SimpleBean對象實例所以全局會有多個SimpleBean對象的實
使用Configuration時在driver和spring容器之中的是同一個對象,而使用Component時是不同的對象。 造成不同結果的原因在ConfigurationClassPostProcessor類之中,通過調用enhanceConfigurationClasses方法,為被注解@Configuration的類進行CGLIB代理 雖然Component注解也會當做配置類,但是并不會為其生成CGLIB代理Class,所以在生成Driver對象時和生成Car對象時調用car()方法執(zhí)行了兩次new操作,所以是不同的對象。當時Configuration注解時,生成當前對象的子類Class,并對方法攔截,第二次調用car()方法時直接從BeanFactory之中獲取對象,所以得到的是同一個對象。
造成這種差異的原因如下:
如果使用@Configuration,所有用@Bean標記的方法會被包裝成CGLIB的wrapper其工作原理是:如果方式是首次被調用那么原始的方法體會被執(zhí)行并且結果對象會被注冊到Spring上下文中。之后所有的對該方法的調用僅僅只是從Spring上下文中取回該對象返回給調用者。
到此這篇關于深入理解@component與@Configuration注解的文章就介紹到這了,更多相關@component與@Configuration注解內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringBoot基于RabbitMQ實現消息延時隊列的方案
在很多的業(yè)務場景中,延時隊列可以實現很多功能,此類業(yè)務中,一般上是非實時的,需要延遲處理的,需要進行重試補償的,本文給大家介紹了SpringBoot基于RabbitMQ實現消息延遲隊列的方案,文中有詳細的代碼講解,需要的朋友可以參考下2024-04-04