您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“Spring創(chuàng)建bean的方法及使用場景是什么”的有關(guān)知識(shí),在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
創(chuàng)建bean,也可以叫組件注冊(cè),就是把單例bean放到spring容器中。我們定義如下工程結(jié)構(gòu):
sping --src ----main java com.xk.spring (包路徑) --bean (普通類所在的包名) --config (用來寫各種配置類) --service (用來編寫服務(wù)層) resources --(本目錄下用于存放各類資源配置文件,后面測試會(huì)用到) ----test --pom.xml
在bean包下面定義Person類,用于演示
package com.xk.spring.bean; /** * @author xk * @since 2023.04.28 8:44 */ public class Person { private Integer id; private String name; private Integer age; public Person(){} public Person(String name, Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } @Override public String toString() { return "name:"+this.name+" age:"+this.age+" id:"+this.id; } }
另外再定義一個(gè)打印spring容器中bean名稱的方法,在單元測試中會(huì)使用。
void printBeanNames(ApplicationContext applicationContext){ String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames(); for (String definitionName : beanDefinitionNames) { System.out.println("----"+definitionName); } }
首先我們先說下@Configuration這個(gè)注解,在springboot應(yīng)用中,經(jīng)常可以看到引用的各類jar包中定義的類中用到了這個(gè)注解。該注解只能作用于類上,在一個(gè)類上面加@Configuration注解,就說明該類是一個(gè)配置類,該配置類也會(huì)作為一個(gè)bean被存放到spring容器中,bean的名稱就是類的名稱(首字母小寫)。如下所示,MyConfig是個(gè)配置類,spring容器中就擁有了一個(gè)bean名稱為myConfig的bean。
package com.xk.spring.config; import org.springframework.context.annotation.Configuration; @Configuration public class MyConfig { }
我們編寫一個(gè)單元測試,來打印下spring容器中bean的名稱。
@Test public void testMyConfig(){ AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class); printBeanNames(applicationContext); }
執(zhí)行testMyConfig單元測試,得到結(jié)果如下:
----org.springframework.context.annotation.internalConfigurationAnnotationProcessor ----org.springframework.context.annotation.internalAutowiredAnnotationProcessor ----org.springframework.context.annotation.internalCommonAnnotationProcessor ----org.springframework.context.event.internalEventListenerProcessor ----org.springframework.context.event.internalEventListenerFactory ----myConfig
前面幾個(gè)bean,是spring內(nèi)置的bean,最后一個(gè)bean就是我們定義的這個(gè)配置類,bean名稱為myConfig.
@Bean作用于配置類的方法上,要求該方法有返回值,返回的值就是spring容器中的bean,bean名稱默認(rèn)就是取方法的名稱。比如下面的代碼說明創(chuàng)建一個(gè)名稱為onePerson的bean。
package com.xk.spring.config; import com.xk.spring.bean.Person; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MyConfig { @Bean public Person onePerson(){ return new Person("xx",12); } }
我們?cè)俅螆?zhí)行上面的testMyConfig單元測試,會(huì)得到如下結(jié)果:
----org.springframework.context.annotation.internalConfigurationAnnotationProcessor ----org.springframework.context.annotation.internalAutowiredAnnotationProcessor ----org.springframework.context.annotation.internalCommonAnnotationProcessor ----org.springframework.context.event.internalEventListenerProcessor ----org.springframework.context.event.internalEventListenerFactory ----myConfig ----onePerson
可以看到,相比于第1步中的結(jié)果,spring容器中多了一個(gè)叫onePerson的bean,而onePerson也就是方法onePerson的方法名稱。
@Import注解只能作用于類上面,可以導(dǎo)入標(biāo)記有@Configuration的配置類、ImportSelector和ImportBeanDefinitionRegistrar的實(shí)現(xiàn)類,還能導(dǎo)入普通的類(不含spring注解),所謂導(dǎo)入,就是將類的實(shí)例注冊(cè)到spring容器中。該注解必須和@Configuration注解結(jié)合使用,而且正常情況下,只有當(dāng)某個(gè)組件不會(huì)被spring自動(dòng)注冊(cè)時(shí)(比如當(dāng)我們使用ComponentScan指定了某個(gè)包掃描路徑),才會(huì)使用該注解。spring-boot-autoconfigure.jar包大量使用了該注解,感興趣的可以去參考下。
通過@Import注解導(dǎo)入配置類,會(huì)把該配置類中定義的bean都注冊(cè)到spring容器中,同時(shí)spring也會(huì)該該配置類創(chuàng)建一個(gè)bean,bean的名稱就是該類的全路徑名。
我們定義一個(gè)ImportConfig配置類,內(nèi)容如下:
package com.xk.spring.config; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; /** * @author xk * @since 2023.04.28 20:03 */ @Import({MyConfig.class}) @Configuration public class ImportConfig { }
我們?cè)谂渲妙惿贤ㄟ^@Import注解導(dǎo)入另外的配置類MyConfig,會(huì)把MyConfig配置類以及在MyConfig類中定義(注冊(cè))的bean都導(dǎo)入到spring容器中。
我們編寫一個(gè)單元測試,來打印下spring容器中bean的名稱。
----org.springframework.context.annotation.internalConfigurationAnnotationProcessor ----org.springframework.context.annotation.internalAutowiredAnnotationProcessor ----org.springframework.context.annotation.internalCommonAnnotationProcessor ----org.springframework.context.event.internalEventListenerProcessor ----org.springframework.context.event.internalEventListenerFactory ----importConfig ----com.xk.spring.config.MyConfig ----onePerson
注意,此時(shí)容器中不僅有importConfig這個(gè)bean,也有MyConfig配置類中定義的onePerson這個(gè)bean。而導(dǎo)入的MyConfig配置類在spring容器中對(duì)應(yīng)的bean名稱是MyConfig類的全路徑名com.xk.spring.config.MyConfig。特別提醒,由于MyConfig本身是個(gè)配置類,如果spring本身能自動(dòng)掃描注冊(cè)該類(比如配置了@ComponentScan包含config包路徑),那么我們?cè)偻ㄟ^@Import這種方式導(dǎo)入MyConfig,MyConfig在spring容器中對(duì)應(yīng)的名稱就變成了myConfig,也就是bean的名稱是類名(首字母小寫)。當(dāng)然,正如前面所說,如果我們的配置類能被spring自動(dòng)掃描注冊(cè),我們就不會(huì)使用@Import這種方式導(dǎo)入配置類。
另外,需要格外注意的是,我們通過@Import導(dǎo)入的類本身會(huì)被當(dāng)做配置類,所以即使此處MyConfig類沒有加@Configuration注解,通過配置@Import({Myconfig.class}),也會(huì)把MyConfig類里面定義的bean注冊(cè)到spring容器,此時(shí)MyConfig類對(duì)應(yīng)的bean名稱就是類的全路徑名。但我們一般不這么做,如果一個(gè)類中定義了bean,我們很自然會(huì)為該類加上@Configuration注解。
ImportSelector是個(gè)接口,它的定義如下:
public interface ImportSelector { /** * 返回需要導(dǎo)入的類的字符串?dāng)?shù)組,數(shù)組中的元素就是類的全路徑名。 * @param importingClassMetadata 當(dāng)前標(biāo)記@Import注解的類的元數(shù)據(jù)信息 */ String[] selectImports(AnnotationMetadata importingClassMetadata); /** * 定義一個(gè)斷言,用來對(duì)上面selectImports返回的類名數(shù)組進(jìn)行過濾,如果某個(gè)元素被斷言判定為true,則該元素不會(huì)被spring注冊(cè)為bean。此處我們先不關(guān)注該方法。 */ @Nullable default Predicate<String> getExclusionFilter() { return null; } }
我們定義一個(gè)MyImportSelector類,實(shí)現(xiàn)該接口,內(nèi)容如下:
package com.xk.spring.importselector; import org.springframework.context.annotation.ImportSelector; import org.springframework.core.type.AnnotationMetadata; /** * @author xk * @since 2023.04.28 21:32 */ public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { return new String[]{"com.xk.spring.bean.Person"}; } }
然后我們修改下我們的ImportConfig類,通過@Import導(dǎo)入MyImportSelector類,內(nèi)容如下:
package com.xk.spring.config; import com.xk.spring.importselector.MyImportSelector; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; /** * @author xk * @since 2023.04.28 20:03 */ @Import({MyImportSelector.class}) @Configuration public class ImportConfig { }
最后我們執(zhí)行上面的testImportConfig單元測試,可以得到下面的結(jié)果:
----org.springframework.context.annotation.internalConfigurationAnnotationProcessor ----org.springframework.context.annotation.internalAutowiredAnnotationProcessor ----org.springframework.context.annotation.internalCommonAnnotationProcessor ----org.springframework.context.event.internalEventListenerProcessor ----org.springframework.context.event.internalEventListenerFactory ----importConfig ----com.xk.spring.bean.Person
可以看到,通過導(dǎo)入MyImportSelector類,spring自動(dòng)幫我們生成了Person的bean實(shí)例,而Person對(duì)應(yīng)的bean的名稱就是Person類的全路徑名。
ImportBeanDefinitionRegistrar也是個(gè)接口,它的定義如下:
public interface ImportBeanDefinitionRegistrar { /** * 基于標(biāo)記@Import注解的類的元數(shù)據(jù)信息來注冊(cè)bean定義信息(最終spring會(huì)根據(jù)這些bean定義信息生成bean)。注意:由于spring bean生命周期的約束,BeanDefinitionRegistryPostProcessor類型的bean不會(huì)在此處被注冊(cè)。后面我們?cè)賮碛懻揵ean的生命周期。 * @param importingClassMetadata 當(dāng)前標(biāo)記@Import注解的類的元數(shù)據(jù)信息 * @param registry bean定義注冊(cè)中心,所有的bean定義信息都會(huì)被注冊(cè)到這里 * @param importBeanNameGenerator 被導(dǎo)入的bean名稱的生成策略 */ default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) { registerBeanDefinitions(importingClassMetadata, registry); } /** * 基于標(biāo)記@Import注解的類的元數(shù)據(jù)信息來注冊(cè)bean定義信息(最終spring會(huì)根據(jù)這些bean定義信息生成bean)。注意:由于spring bean生命周期的約束,BeanDefinitionRegistryPostProcessor類型的bean不會(huì)在此處被注冊(cè)。后面我們?cè)賮碛懻揵ean的生命周期。 * @param importingClassMetadata 當(dāng)前標(biāo)記@Import注解的類的元數(shù)據(jù)信息 * @param registry bean定義注冊(cè)中心,所有的bean定義信息都會(huì)被注冊(cè)到這里 */ default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { } }
我們定義一個(gè)MyImportBeanDefinitionRegistrar類,實(shí)現(xiàn)ImportBeanDefinitionRegistrar接口,定義如下:
package com.xk.spring.importbeandefinitionregistrar; import com.xk.spring.bean.Person; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.type.AnnotationMetadata; /** * @author xk * @since 2023.04.28 21:45 */ public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { boolean flag = registry.containsBeanDefinition("com.xk.spring.bean.Person"); if(!flag){ RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Person.class); //注冊(cè)person,并且自定義bean的名稱為myPerson registry.registerBeanDefinition("myPerson",rootBeanDefinition); } } }
然后我們修改下我們的ImportConfig配置類,使用@Import導(dǎo)入MyImportBeanDefinitionRegistrar類,內(nèi)容如下:
package com.xk.spring.config; import com.xk.spring.importbeandefinitionregistrar.MyImportBeanDefinitionRegistrar; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; /** * @author xk * @since 2023.04.28 20:03 */ @Import({MyImportBeanDefinitionRegistrar.class}) @Configuration public class ImportConfig { }
最后我們執(zhí)行testImportConfig單元測試,會(huì)得到如下的結(jié)果:
----org.springframework.context.annotation.internalConfigurationAnnotationProcessor ----org.springframework.context.annotation.internalAutowiredAnnotationProcessor ----org.springframework.context.annotation.internalCommonAnnotationProcessor ----org.springframework.context.event.internalEventListenerProcessor ----org.springframework.context.event.internalEventListenerFactory ----importConfig ----myPerson
可以看到,我們通過這種方式成功的導(dǎo)入Person類對(duì)應(yīng)的bean,而且bean的名稱就是我們自定義的myPerson。
我們還可以通過@Import導(dǎo)入普通類到spring容器,導(dǎo)入之后的bean的名稱就是類名的全路徑。這些普通類可以什么注解都不加,比如沒有@Component注解,也沒有@Configuration注解。就拿我們的Person類來說,我們可以通過@Import({Person.class})的方式直接將其導(dǎo)入spring容器,。
修改ImportConfig配置類,內(nèi)容如下:
package com.xk.spring.config; import com.xk.spring.bean.Person; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; /** * @author xk * @since 2023.04.28 20:03 */ @Import({Person.class}) @Configuration public class ImportConfig { }
最后執(zhí)行testImportConfig單元測試,會(huì)得出如下結(jié)果:
----org.springframework.context.annotation.internalConfigurationAnnotationProcessor ----org.springframework.context.annotation.internalAutowiredAnnotationProcessor ----org.springframework.context.annotation.internalCommonAnnotationProcessor ----org.springframework.context.event.internalEventListenerProcessor ----org.springframework.context.event.internalEventListenerFactory ----importConfig ----com.xk.spring.bean.Person
可以看到,Person類被導(dǎo)入到spring容器,并且對(duì)應(yīng)的bean名稱是Person類的全路徑名。
傳統(tǒng)的spring項(xiàng)目通過使用xml配置文件來定義bean信息,然后在web.xml中聲明我們的spring的xml配置文件?,F(xiàn)在我們換種方式,我們可以通過使用@ImportResource注解,將整個(gè)的xml配置文件導(dǎo)入到配置類,進(jìn)而由spring替我們生成對(duì)應(yīng)的bean。
我們?cè)诠こ痰膔esources資源目錄下創(chuàng)建application-beans.xml文件(文件名隨便起),內(nèi)容如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <!--定義person--> <bean id="person" class="com.xk.spring.bean.Person"> <!-- collaborators and configuration for this bean go here --> </bean> </beans>
然后我們修改ImportConfig配置類,內(nèi)容如下:
package com.xk.spring.config; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ImportResource; /** * @author xk * @since 2023.04.28 20:03 */ @ImportResource({"classpath:/application-beans.xml"}) @Configuration public class ImportConfig { }
最后執(zhí)行testImportResource單元測試,得出結(jié)果如下:
----org.springframework.context.annotation.internalConfigurationAnnotationProcessor ----org.springframework.context.annotation.internalAutowiredAnnotationProcessor ----org.springframework.context.annotation.internalCommonAnnotationProcessor ----org.springframework.context.event.internalEventListenerProcessor ----org.springframework.context.event.internalEventListenerFactory ----importConfig ----person
可以看到,通過@ImportResource的方式,我們把在xml配置文件中定義的person這個(gè)bean注冊(cè)到了spring容器中。
@ComponentScan注解可以讓spring方便地識(shí)別標(biāo)記了@Component注解的組件,需要和@Configuration注解一起使用。我們?cè)趙eb開發(fā)時(shí),經(jīng)常會(huì)使用@Service、@Repository、@Controller、@Configuration、@Component等注解,用來表示MVC不同層次的組件bean。其實(shí)前面四種注解的元注解上面都標(biāo)記了@Component,說明被這四種注解標(biāo)記的類通過配置@ComponentScan指令,就可以被注冊(cè)到spring容器中,而它們對(duì)應(yīng)的bean的名稱就是類名(首字母小寫)。
我們拿@Service為例,在service包下面創(chuàng)建PersonService類,內(nèi)容如下:
package com.xk.spring.service; import org.springframework.stereotype.Service; /** * 人員服務(wù)層 * @author xk * @since 2023.04.29 7:25 */ @Service public class PersonService { }
內(nèi)容很簡單,就簡單的通過@Service將該類標(biāo)記為一個(gè)組件。接下來我們修改MyConfig類,在它上面加上@ComponentScan注解,內(nèi)容如下:
package com.xk.spring.config; import com.xk.spring.bean.Person; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @ComponentScan("com.xk.spring.service") @Configuration public class MyConfig { @Bean public Person onePerson(){ return new Person("xx",18); } }
最后我們執(zhí)行下先前定義的testMyConfig單元測試,得到結(jié)果如下:
----org.springframework.context.annotation.internalConfigurationAnnotationProcessor ----org.springframework.context.annotation.internalAutowiredAnnotationProcessor ----org.springframework.context.annotation.internalCommonAnnotationProcessor ----org.springframework.context.event.internalEventListenerProcessor ----org.springframework.context.event.internalEventListenerFactory ----myConfig ----personService ----onePerson
可以看到,容器中多了一個(gè)personService的bean,而該bean就是對(duì)應(yīng)被我們標(biāo)記了@Service注解的PersonService。雖然我們config包下面的ImportConfig類也加了@Configuration注解,但由于它不在包掃描的范圍,所以spring無法將其自動(dòng)注冊(cè)到容器中。
“Spring創(chuàng)建bean的方法及使用場景是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。