深入理解@component與@Configuration注解
1、@Configuration
從Spring3.0,@Configuration用于定義配置類,可替換xml配置文件,被注解的類內(nèi)部包含有一個(gè)或多個(gè)被@Bean注解的方法,這些方法將會(huì)被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext類進(jìn)行掃描,并用于構(gòu)建bean定義,初始化Spring容器。
注意:@Configuration注解的配置類有如下要求:
1、@Configuration不可以是final類型;
2、@Configuration不可以是匿名類;
3、嵌套的configuration必須是靜態(tài)類。
用@Configuration加載spring的用法
@Configuration配置spring并啟動(dòng)spring容器
@Configuration標(biāo)注在類上,相當(dāng)于把該類作為spring的xml配置文件中的,作用為:配置spring容器(應(yīng)用上下文)
@Configuration啟動(dòng)容器+@Bean注冊(cè)Bean
@Bean下管理bean的生命周期
可以使用基于 Java 的配置來管理 bean 的生命周期。@Bean 支持兩種屬性,即 initMethod和destroyMethod,這些屬性可用于定義生命周期方法。在實(shí)例化 bean或即將銷毀它時(shí),容器便可調(diào)用生命周期方法。生命周期方法也稱為回調(diào)方法,因?yàn)樗鼘⒂扇萜髡{(diào)用。使用 @Bean 注釋注冊(cè)的 bean 也支持JSR-250 規(guī)定的標(biāo)準(zhǔn) @PostConstruct 和 @PreDestroy 注釋。如果您正在使用 XML 方法來定義bean,那么就應(yīng)該使用 bean 元素來定義生命周期回調(diào)方法。
@Bean標(biāo)注在方法上(返回某個(gè)實(shí)例的方法),等價(jià)于spring的xml配置文件中的作用:注冊(cè)bean對(duì)象
@Bean注解在返回實(shí)例的方法上,如果未通過@Bean指定bean的名稱,則默認(rèn)與標(biāo)注的方法名相同; @Bean注解默認(rèn)作用域?yàn)閱卫齭ingleton作用域,可通過@Scope(“prototype”)設(shè)置為原型作用域; 既然@Bean的作用是注冊(cè)bean對(duì)象,那么完全可以使用@Component、@Controller、@Service、@Ripository等注解注冊(cè)bean,當(dāng)然需要配置@ComponentScan注解進(jìn)行自動(dòng)掃描。
- @Configuration啟動(dòng)容器+@Component注冊(cè)Bean
- 使用 AnnotationConfigApplicationContext 注冊(cè) AppContext 類的兩種方法
- 配置Web應(yīng)用程序(web.xml中配置AnnotationConfigApplicationContext)
2、@component注解
1、@controller 控制器(注入服務(wù))
2、@service 服務(wù)(注入dao)
3、@repository dao(實(shí)現(xiàn)dao訪問)
4、@component (把普通pojo實(shí)例化到spring容器中,相當(dāng)于配置文件中的<bean id="" class=""/>)
如果 Web 應(yīng)用程序采用了經(jīng)典的三層分層結(jié)構(gòu)的話,最好在持久層、業(yè)務(wù)層和控制層分別采用 @Repository、@Service 和 @Controller 對(duì)分層中的類進(jìn)行注釋,而用 @Component 對(duì)那些比較中立的類進(jìn)行注釋。 在 一個(gè)稍大的項(xiàng)目中,通常會(huì)有上百個(gè)組件,如果這些組件采用xml的bean定義來配置,顯然會(huì)增加配置文件的體積,查找以及維護(hù)起來也不太方便。 Spring2.5為我們引入了組件自動(dòng)掃描機(jī)制,他可以在類路徑底下尋找標(biāo)注了 @Component,@Service,@Controller,@Repository注解的類,并把這些類納入進(jìn)spring容器中管理。它的作用 和在xml文件中使用bean節(jié)點(diǎn)配置組件時(shí)一樣的。
說明: <context:component-scan base-package=”com.*”> 上面的這個(gè)例子是引入Component組件的例子,其中base-package表示為需要掃描的所有子包。
共同點(diǎn):被@controller 、@service、@repository 、@component 注解的類,都會(huì)把這些類納入進(jìn)spring容器中進(jìn)行管理
3、@configuration和@component之間的區(qū)別
@configuration和@component之間的區(qū)別是:@Component注解的范圍最廣,所有類都可以注解,但是@Configuration注解一般注解在這樣的類上:這個(gè)類里面有@Value注解的成員變量和@Bean注解的方法,就是一個(gè)配置類。
展示兩個(gè)注解的配圖

可以看出@Configuration注解中有@Component注解 從定義來看,@Configuration 注解本質(zhì)上還是@Component,因此context:component-scan/ 或者 @ComponentScan都能處理@Configuration注解的類。
@Configuration標(biāo)記的類必須符合下面的要求:
- 配置類必須以類的形式提供(不能是工廠方法返回的實(shí)例),允許通過生成子類在運(yùn)行時(shí)增強(qiáng)(cglib 動(dòng)態(tài)代理)。
- 配置類不能是 final類(沒法動(dòng)態(tài)代理)。
- 配置注解通常為了通過 @Bean 注解生成 Spring 容器管理的類,配置類必須是非本地的(即不能在方法中聲明,不能是private)。
- 任何嵌套配置類都必須聲明為static。
- @Bean方法可能不會(huì)反過來創(chuàng)建進(jìn)一步的配置類(也就是返回的 bean 如果帶有@Configuration,也不會(huì)被特殊處理,只會(huì)作為普通的bean)
加載過程
Spring 容器在啟動(dòng)時(shí),會(huì)加載默認(rèn)的一些PostProcessor,其中就有ConfigurationClassPostProcessor,這個(gè)后置處理程序?qū)iT處理帶有@Configuration注解的類,這個(gè)程序會(huì)在bean 定義加載完成后,在bean初始化前進(jìn)行處理。主要處理的過程就是使用cglib動(dòng)態(tài)代理增強(qiáng)類,而且是對(duì)其中帶有@Bean注解的方法進(jìn)行處理。
基于Java的配置我們通常使用@Configuration注解來聲明Spring Bean 除此之外我們還能使用@Component聲明Spring Bean
具體實(shí)例驗(yàn)證兩者的區(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;
}
}
測(cè)試代碼如下
@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 ? "同一個(gè)car" : "不同的car");
}
}
打印結(jié)果如下: 同一個(gè)car
使用@component注解除Config類上的注解不同之外其他都相同,Spring對(duì)兩者的處理方式就會(huì)完全不一樣。
- @configuration:會(huì)像我們期望的一樣正常運(yùn)行,因?yàn)閚ew SimpleBeanConsumer(simpleBean())這段代碼中simpleBean()方法會(huì)由Spring代理執(zhí)行,Spring發(fā)現(xiàn)方法所請(qǐng)求的Bean已經(jīng)在容器中,那么就直接返回容器中的Bean。所以全局只有一個(gè)SimpleBean對(duì)象的實(shí)例。
- @component:在執(zhí)行new SimpleBeanConsumer(simpleBean()) 時(shí)simpleBean()不會(huì)被Spring代理,會(huì)直接調(diào)用simpleBean()方法獲取一個(gè)全新的SimpleBean對(duì)象實(shí)例所以全局會(huì)有多個(gè)SimpleBean對(duì)象的實(shí)
使用Configuration時(shí)在driver和spring容器之中的是同一個(gè)對(duì)象,而使用Component時(shí)是不同的對(duì)象。 造成不同結(jié)果的原因在ConfigurationClassPostProcessor類之中,通過調(diào)用enhanceConfigurationClasses方法,為被注解@Configuration的類進(jìn)行CGLIB代理 雖然Component注解也會(huì)當(dāng)做配置類,但是并不會(huì)為其生成CGLIB代理Class,所以在生成Driver對(duì)象時(shí)和生成Car對(duì)象時(shí)調(diào)用car()方法執(zhí)行了兩次new操作,所以是不同的對(duì)象。當(dāng)時(shí)Configuration注解時(shí),生成當(dāng)前對(duì)象的子類Class,并對(duì)方法攔截,第二次調(diào)用car()方法時(shí)直接從BeanFactory之中獲取對(duì)象,所以得到的是同一個(gè)對(duì)象。
造成這種差異的原因如下:
如果使用@Configuration,所有用@Bean標(biāo)記的方法會(huì)被包裝成CGLIB的wrapper其工作原理是:如果方式是首次被調(diào)用那么原始的方法體會(huì)被執(zhí)行并且結(jié)果對(duì)象會(huì)被注冊(cè)到Spring上下文中。之后所有的對(duì)該方法的調(diào)用僅僅只是從Spring上下文中取回該對(duì)象返回給調(diào)用者。
到此這篇關(guān)于深入理解@component與@Configuration注解的文章就介紹到這了,更多相關(guān)@component與@Configuration注解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java非公平鎖知識(shí)點(diǎn)實(shí)例詳解
在本篇文章里小編給大家整理了一篇關(guān)于java非公平鎖知識(shí)點(diǎn)實(shí)例詳解,有興趣的朋友們可以學(xué)習(xí)參考下。2021-10-10
使用MultipartFile來上傳單個(gè)及多個(gè)文件代碼示例
這篇文章主要介紹了使用MultipartFile來上傳單個(gè)及多個(gè)文件代碼示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
java實(shí)現(xiàn)簡(jiǎn)易五子棋游戲
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)易五子棋游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-06-06
SpringBoot基于RabbitMQ實(shí)現(xiàn)消息延時(shí)隊(duì)列的方案
在很多的業(yè)務(wù)場(chǎng)景中,延時(shí)隊(duì)列可以實(shí)現(xiàn)很多功能,此類業(yè)務(wù)中,一般上是非實(shí)時(shí)的,需要延遲處理的,需要進(jìn)行重試補(bǔ)償?shù)?本文給大家介紹了SpringBoot基于RabbitMQ實(shí)現(xiàn)消息延遲隊(duì)列的方案,文中有詳細(xì)的代碼講解,需要的朋友可以參考下2024-04-04
java Callable與Future的詳解及實(shí)例
這篇文章主要介紹了java Callable與Future的詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-01-01

