摘要:一什么是中的簡(jiǎn)單來(lái)講就是一個(gè)個(gè)被容器管理的對(duì)象,我們寫(xiě)了一個(gè)類之后,這個(gè)類只是一個(gè)單純的類,可以通過(guò)的方式去創(chuàng)建它。以類為例在不指定的情況下,所有的實(shí)例都是單實(shí)例的,并且是餓漢式加載容器啟動(dòng)時(shí)就創(chuàng)建好了。
Spring中的Bean簡(jiǎn)單來(lái)講就是一個(gè)個(gè)被Spring容器管理的Java對(duì)象,我們寫(xiě)了一個(gè)類之后,這個(gè)類只是一個(gè)單純的Java類,可以通過(guò)new的方式去創(chuàng)建它。當(dāng)我們把這個(gè)類添加到Spring的容器里之后,這個(gè)類就變成了Bean,由Spring容器管理,可以通過(guò)自動(dòng)注入的方式去使用。
這里列出四種常用的添加Bean的方式。
1、@Bean: 寫(xiě)一個(gè)普通的類時(shí)最常用的添加Bean的方式
2、@ComponentScan + @Controller @Service @Component @Repository:SpringBoot寫(xiě)多了之后一定會(huì)很熟悉這些。
3、@Import:通過(guò)導(dǎo)入的方式注入Bean
4、@ImportBeanDefinitionRegister:和Import類似,可以指定Bean的名稱
首先介紹最基本的@Bean注解,@Bean注解聲明這個(gè)類是一個(gè)Bean,在Spring5之前,大部分的聲明都會(huì)放到配置文件里,Spring5之后通過(guò)兩個(gè)注解就可以完成。以Teacher類為例
public class Teacher {}@Configurationpublic 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//@Lazypublic 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í)別
有幾個(gè)注解經(jīng)常會(huì)和@Bean一起使用
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è)到容器中。
這個(gè)注解會(huì)和Controller、Service等同時(shí)出現(xiàn),給一個(gè)類添加Controller、Service等注解后,需要在配置類中增加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 類進(jìn)行了一層判斷:包名為dao下的類會(huì)被注冊(cè)到Bean容器中
public class TestFilterType implements TypeFilter { public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { //獲取當(dāng)前類的class源信息 ClassMetadata classMetadata = metadataReader.getClassMetadata(); if (classMetadata.getClassName().contains("dao")){ return true; } return false; }}
@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)的類,這里和直接寫(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的名稱)
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注解的身影。
當(dāng)由容器管理Bean的生命周期時(shí),我們可以通過(guò)自己指定Bean方法的初始化方法和銷毀方法,使得一個(gè)Bean在初始化和銷毀時(shí)能執(zhí)行自己的方法。
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 銷毀方法"); }}@Configurationpublic class MainConfig { @Bean(initMethod = "init",destroyMethod = "destory") public Teacher teacher(){ return new Teacher(); }}
對(duì)于單例bean(singleton)容器啟動(dòng)的時(shí)候,bean對(duì)象就創(chuàng)建了,在容器銷毀的時(shí)候,就會(huì)去調(diào)用Bean的銷毀方法。
對(duì)于多實(shí)例的bean,容器啟動(dòng)的時(shí)候bean還未被創(chuàng)建,在獲取Bean的時(shí)候才會(huì)被創(chuàng)建,并且bean的銷毀不受IOC容器的管理。
Spring的這兩個(gè)接口也可以實(shí)現(xiàn)初始化和銷毀的功能。
public class Student implements InitializingBean, DisposableBean { public Student(){ System.out.println("Student 構(gòu)造方法"); } @Override public void destroy() throws Exception { System.out.println("Student銷毀"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("Student初始化"); }}@Configurationpublic class MainConfig { @Bean public Student student(){ return new Student(); }}
BeanPostProcessor在所有Bean的初始化前和初始化后都會(huì)被調(diào)用
@Componentpublic 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@Configurationpublic class MainConfig { @Bean(initMethod = "init",destroyMethod = "destory") public Teacher teacher(){ return new Teacher(); } @Bean public Student student(){ return new Student(); }}
別看Bean這個(gè)概念聽(tīng)起來(lái)簡(jiǎn)單,里面的內(nèi)容還真不少。Spring的核心之一IOC也就是對(duì)Bean進(jìn)行管理。我是魚(yú)仔,我們下期再見(jiàn)!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/122169.html
摘要:何為簡(jiǎn)單點(diǎn)來(lái)定義就是切面,是一種編程范式。定義一個(gè)切面的載體定義一個(gè)切點(diǎn)定義一個(gè)為,并指定對(duì)應(yīng)的切點(diǎn)一個(gè)注冊(cè)配置類,啟動(dòng)容器,初始化時(shí)期獲取對(duì)象,獲取對(duì)象時(shí)期,并進(jìn)行打印好了,這樣我們整體的代理就已經(jīng)完成。 問(wèn)題:Spring AOP代理中的運(yùn)行時(shí)期,是在初始化時(shí)期織入還是獲取對(duì)象時(shí)期織入? 織入就是代理的過(guò)程,指目標(biāo)對(duì)象進(jìn)行封裝轉(zhuǎn)換成代理,實(shí)現(xiàn)了代理,就可以運(yùn)用各種代理的場(chǎng)景模式。 ...
摘要:在寫(xiě)完容器源碼分析系列文章中的最后一篇后,沒(méi)敢懈怠,趁熱打鐵,花了天時(shí)間閱讀了方面的源碼。從今天開(kāi)始,我將對(duì)部分的源碼分析系列文章進(jìn)行更新。全稱是,即面向切面的編程,是一種開(kāi)發(fā)理念。在中,切面只是一個(gè)概念,并沒(méi)有一個(gè)具體的接口或類與此對(duì)應(yīng)。 1. 簡(jiǎn)介 前一段時(shí)間,我學(xué)習(xí)了 Spring IOC 容器方面的源碼,并寫(xiě)了數(shù)篇文章對(duì)此進(jìn)行講解。在寫(xiě)完 Spring IOC 容器源碼分析系列...
摘要:一面應(yīng)該還問(wèn)了其他內(nèi)容,但是兩次面試多線程面試問(wèn)題和答案采訪中,我們通常會(huì)遇到兩個(gè)主題采集問(wèn)題和多線程面試問(wèn)題。多線程是關(guān)于并發(fā)和線程的。我們正在共享重要的多線程面試問(wèn)題和答案。。 2016 年末,騰訊,百度,華為,搜狗和滴滴面試題匯總 2016 年未,騰訊,百度,華為,搜狗和滴滴面試題匯總 【碼農(nóng)每日一題】Java 內(nèi)部類(Part 2)相關(guān)面試題 關(guān)注一下嘛,又不讓你背鍋!問(wèn):Ja...
摘要:一面應(yīng)該還問(wèn)了其他內(nèi)容,但是兩次面試多線程面試問(wèn)題和答案采訪中,我們通常會(huì)遇到兩個(gè)主題采集問(wèn)題和多線程面試問(wèn)題。多線程是關(guān)于并發(fā)和線程的。我們正在共享重要的多線程面試問(wèn)題和答案。。 2016 年末,騰訊,百度,華為,搜狗和滴滴面試題匯總 2016 年未,騰訊,百度,華為,搜狗和滴滴面試題匯總 【碼農(nóng)每日一題】Java 內(nèi)部類(Part 2)相關(guān)面試題 關(guān)注一下嘛,又不讓你背鍋!問(wèn):Ja...
摘要:簡(jiǎn)介為了寫(xiě)容器源碼分析系列的文章,我特地寫(xiě)了一篇容器的導(dǎo)讀文章。在做完必要的準(zhǔn)備工作后,從本文開(kāi)始,正式開(kāi)始進(jìn)入源碼分析的階段。從緩存中獲取單例。返回以上就是和兩個(gè)方法的分析。 1. 簡(jiǎn)介 為了寫(xiě) Spring IOC 容器源碼分析系列的文章,我特地寫(xiě)了一篇 Spring IOC 容器的導(dǎo)讀文章。在導(dǎo)讀一文中,我介紹了 Spring 的一些特性以及閱讀 Spring 源碼的一些建議。在...
閱讀 2479·2021-10-12 10:11
閱讀 1229·2021-10-11 10:58
閱讀 3272·2019-08-30 15:54
閱讀 710·2019-08-30 13:59
閱讀 680·2019-08-29 13:07
閱讀 1407·2019-08-26 11:55
閱讀 2142·2019-08-26 10:44
閱讀 2642·2019-08-23 18:25