寫(xiě)了兩年代碼之后再來(lái)談一談Spring中的Bean
(一)什么是Bean
Spring中的Bean簡(jiǎn)單來(lái)講就是一個(gè)個(gè)被Spring容器管理的Java對(duì)象,我們寫(xiě)了一個(gè)類(lèi)之后,這個(gè)類(lèi)只是一個(gè)單純的Java類(lèi),可以通過(guò)new的方式去創(chuàng)建它。當(dāng)我們把這個(gè)類(lèi)添加到Spring的容器里之后,這個(gè)類(lèi)就變成了Bean,由Spring容器管理,可以通過(guò)自動(dòng)注入的方式去使用。
(二)如何往Spring容器中添加Bean
這里列出四種常用的添加Bean的方式。
1、@Bean: 寫(xiě)一個(gè)普通的類(lèi)時(shí)最常用的添加Bean的方式
2、@ComponentScan + @Controller @Service @Component @Repository:SpringBoot寫(xiě)多了之后一定會(huì)很熟悉這些。
3、@Import:通過(guò)導(dǎo)入的方式注入Bean
4、@ImportBeanDefinitionRegister:和Import類(lèi)似,可以指定Bean的名稱(chēng)
(三)Bean的作用域
首先介紹最基本的@Bean注解,@Bean注解聲明這個(gè)類(lèi)是一個(gè)Bean,在Spring5之前,大部分的聲明都會(huì)放到配置文件里,Spring5之后通過(guò)兩個(gè)注解就可以完成。以Teacher類(lèi)為例
public class Teacher {
}
@Configuration
public class MainConfig {
@Bean
public Teacher teacher(){
return new Teacher();
}
}
在不指定@Scope的情況下,所有bean的實(shí)例都是單實(shí)例的bean,并且是餓漢式加載(容器啟動(dòng)時(shí)就創(chuàng)建好了)??梢酝ㄟ^(guò)注解@Lazy實(shí)現(xiàn)懶加載(在調(diào)用時(shí)被加載)。
@Bean
//@Lazy
public User user(){
return new User();
}
指定@Scope為prototype表示為多實(shí)例,并且是懶漢式加載(使用時(shí)才會(huì)創(chuàng)建)
@Bean
@Scope(value = "prototype")
public User user(){
return new User();
}
列出其他的幾種Bean作用域:
singleton 單例(默認(rèn)) prototype 多實(shí)例 request 同一次請(qǐng)求 session 同一個(gè)會(huì)話級(jí)別
(四)Bean的常用注解
有幾個(gè)注解經(jīng)常會(huì)和@Bean一起使用
4.1 Conditional
Conditional注解的意思是條件,即滿足條件的情況下才會(huì)生效
比如我在Bean中配置了Conditional:
@Bean
@Conditional(value = TeacherCondition.class)
public Teacher teacher(){
return new Teacher();
}
TeacherCondition 代碼如下:如果Spring的Bean中有名字為student的,則返回true,否則返回false
public class TeacherCondition implements Condition {
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
if (conditionContext.getBeanFactory().containsBean("student")){
return true;
}
return false;
}
}
最后的結(jié)果就是,如果TeacherCondition返回的是true,則teacher這個(gè)bean會(huì)被注冊(cè)到容器中,否則就不會(huì)注冊(cè)到容器中。
4.2 ComponentScan
這個(gè)注解會(huì)和Controller、Service等同時(shí)出現(xiàn),給一個(gè)類(lèi)添加Controller、Service等注解后,需要在配置類(lèi)中增加ComponentScan,ComponentScan掃描到的包下的Controller、Service等注解才會(huì)生效:
@Configuration
//最基本的掃描路徑方式
//@ComponentScan(basePackages = {"com.javayz.testcompentscan"})
//增加了Filter的方式
@ComponentScan(basePackages = {"com.javayz.testcompentscan"},includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class, Service.class}),
@ComponentScan.Filter(type = FilterType.CUSTOM,value = {TestFilterType.class})
},useDefaultFilters = false)
public class MainConfig {
@Bean
@Scope(value = "prototype")
public User user(){
return new User();
}
}
Filter是在掃描時(shí)的過(guò)濾器,比如設(shè)置FilterType.ANNOTATION表示只有這里設(shè)置的注解才會(huì)被掃描到,F(xiàn)ilterType.CUSTOM是自定義過(guò)濾器,TestFilterType 類(lèi)進(jìn)行了一層判斷:包名為dao下的類(lèi)會(huì)被注冊(cè)到Bean容器中
public class TestFilterType implements TypeFilter {
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//獲取當(dāng)前類(lèi)的class源信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
if (classMetadata.getClassName().contains("dao")){
return true;
}
return false;
}
}
4.3 @Import
@Import可以用來(lái)往容器中導(dǎo)入第三方的組件,也可以起到和@Bean一樣的作用:
@Configuration
//@Import(value = {Teacher.class, Student.class})
//@Import(value = {MyImportSelector.class})
@Import(value = {MyBeanDefinitionRegister.class})
public class MainConfig {
}
第一種方式直接導(dǎo)入對(duì)應(yīng)的類(lèi),這里和直接寫(xiě)@Bean效果一致
@Import(value = {Teacher.class, Student.class})
第二種方式導(dǎo)入ImportSelector對(duì)象,通過(guò)selectImports方法返回要導(dǎo)入Bean的全限定名:
public class MyImportSelector implements ImportSelector {
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"com.javayz.testimport.compent.Teacher"};
}
}
第三種方式通過(guò)BeanDefinitionRegister注入Bean(可以指定Bean的名稱(chēng))
public class MyBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Student.class);
registry.registerBeanDefinition("student",rootBeanDefinition);
}
}
Import注解最常用的場(chǎng)景就是SpringBoot自動(dòng)注入,在SpringBoot自動(dòng)注入源碼中導(dǎo)出可以看到@Import注解的身影。
(五)Bean的初始化和銷(xiāo)毀
當(dāng)由容器管理Bean的生命周期時(shí),我們可以通過(guò)自己指定Bean方法的初始化方法和銷(xiāo)毀方法,使得一個(gè)Bean在初始化和銷(xiāo)毀時(shí)能執(zhí)行自己的方法。
1、自定義初始化方法和銷(xiāo)毀方法
public class Teacher {
public Teacher(){
System.out.println("Teacher 構(gòu)造方法");
}
public void init(){
System.out.println("Teacher 初始化方法");
}
public void destory(){
System.out.println("Teacher 銷(xiāo)毀方法");
}
}
@Configuration
public class MainConfig {
@Bean(initMethod = "init",destroyMethod = "destory")
public Teacher teacher(){
return new Teacher();
}
}
對(duì)于單例bean(singleton)容器啟動(dòng)的時(shí)候,bean對(duì)象就創(chuàng)建了,在容器銷(xiāo)毀的時(shí)候,就會(huì)去調(diào)用Bean的銷(xiāo)毀方法。
對(duì)于多實(shí)例的bean,容器啟動(dòng)的時(shí)候bean還未被創(chuàng)建,在獲取Bean的時(shí)候才會(huì)被創(chuàng)建,并且bean的銷(xiāo)毀不受IOC容器的管理。
2、通過(guò) InitializingBean, DisposableBean 接口實(shí)現(xiàn)
Spring的這兩個(gè)接口也可以實(shí)現(xiàn)初始化和銷(xiāo)毀的功能。
public class Student implements InitializingBean, DisposableBean {
public Student(){
System.out.println("Student 構(gòu)造方法");
}
@Override
public void destroy() throws Exception {
System.out.println("Student銷(xiāo)毀");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Student初始化");
}
}
@Configuration
public class MainConfig {
@Bean
public Student student(){
return new Student();
}
}
3、BeanPostProcessor
BeanPostProcessor在所有Bean的初始化前和初始化后都會(huì)被調(diào)用
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean初始化前");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean初始化后");
return bean;
}
}
@ComponentScan
@Configuration
public class MainConfig {
@Bean(initMethod = "init",destroyMethod = "destory")
public Teacher teacher(){
return new Teacher();
}
@Bean
public Student student(){
return new Student();
}
}
(六)總結(jié)
別看Bean這個(gè)概念聽(tīng)起來(lái)簡(jiǎn)單,里面的內(nèi)容還真不少。Spring的核心之一IOC也就是對(duì)Bean進(jìn)行管理。我是魚(yú)仔,我們下期再見(jiàn)!
到此這篇關(guān)于寫(xiě)了兩年代碼之后再來(lái)看看Spring中的Bean的文章就介紹到這了,更多相關(guān)Spring中的Bean內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解spring中使用Elasticsearch的代碼實(shí)現(xiàn)
本篇文章主要介紹了詳解spring中使用Elasticsearch的代碼實(shí)現(xiàn),具有一定的參考價(jià)值,有興趣的可以了解一下2017-05-05
springboot全局配置文件與多環(huán)境配置的全過(guò)程
SpringBoot項(xiàng)目在多環(huán)境配置上表現(xiàn)的非常優(yōu)秀,只需要非常簡(jiǎn)單的操作就可以完成配置,下面這篇文章主要給大家介紹了關(guān)于springboot全局配置文件與多環(huán)境配置的相關(guān)資料,需要的朋友可以參考下2021-12-12
JWT在OpenFeign調(diào)用中進(jìn)行令牌中繼詳解
Feign是一個(gè)聲明式的Web Service客戶端,是一種聲明式、模板化的HTTP客戶端。而OpenFeign是Spring Cloud 在Feign的基礎(chǔ)上支持了Spring MVC的注解,如@RequesMapping等等,這篇文章主要給大家介紹了關(guān)于JWT在OpenFeign調(diào)用中進(jìn)行令牌中繼的相關(guān)資料,需要的朋友可以參考下2021-10-10
詳解Java實(shí)現(xiàn)緩存(LRU,FIFO)
本篇文章主要介紹了詳解Java實(shí)現(xiàn)緩存(LRU,FIFO) ,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04
Java中Date時(shí)區(qū)的轉(zhuǎn)換代碼示例
這篇文章主要給大家介紹了關(guān)于Java中Date時(shí)區(qū)轉(zhuǎn)換的相關(guān)資料,當(dāng)在不同的時(shí)區(qū)使用相同程序,時(shí)間的值只會(huì)為當(dāng)?shù)貢r(shí)間,這樣就會(huì)造成時(shí)間混亂,需要的朋友可以參考下2023-07-07
java配置數(shù)據(jù)庫(kù)連接池的方法步驟
java配置數(shù)據(jù)庫(kù)連接池的方法步驟,需要的朋友可以參考一下2013-05-05
SpringBoot如何接收數(shù)組參數(shù)的方法
這篇文章主要介紹了SpringBoot如何接收數(shù)組參數(shù)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12

