Spring創(chuàng)建Bean的6種方式詳解
前言
本文講解了在Spring 應(yīng)用中創(chuàng)建Bean的多種方式,包括自動創(chuàng)建,以及手動創(chuàng)建注入方式,實(shí)際開發(fā)中可以根據(jù)業(yè)務(wù)場景選擇合適的方案。
方式1:
使用Spring XML方式配置,該方式用于在純Spring 應(yīng)用中,適用于簡單的小應(yīng)用,當(dāng)應(yīng)用變得復(fù)雜,將會導(dǎo)致XMl配置文件膨脹 ,不利于對象管理。
<bean id="xxxx" class="xxxx.xxxx"/>
方式2:
使用@Component,@Service,@Controler,@Repository注解
這幾個注解都是同樣的功能,被注解的類將會被Spring 容器創(chuàng)建單例對象。
- @Component : 側(cè)重于通用的Bean類
- @Service:標(biāo)識該類用于業(yè)務(wù)邏輯
- @Controler:標(biāo)識該類為Spring MVC的控制器類
- @Repository: 標(biāo)識該類是一個實(shí)體類,只有屬性和Setter,Getter
@Component public class User{ }
當(dāng)用于Spring Boot應(yīng)用時,被注解的類必須在啟動類的根路徑或者子路徑下,否則不會生效。
如果不在,可以使用@ComponentScan標(biāo)注掃描的路徑。
spring xml 也有相關(guān)的標(biāo)簽<component-scan />
@ComponentScan(value={"com.microblog.blog","com.microblog.common"}) public class MicroblogBlogApplication { public static void main(String args[]){ SpringApplication.run(MicroblogBlogApplication.class,args); } }
方式3:
使用@Bean注解,這種方式用在Spring Boot 應(yīng)用中。
@Configuration 標(biāo)識這是一個Spring Boot 配置類,其將會掃描該類中是否存在@Bean 注解的方法,比如如下代碼,將會創(chuàng)建User對象并放入容器中。
@ConditionalOnBean 用于判斷存在某個Bean時才會創(chuàng)建User Bean.
這里創(chuàng)建的Bean名稱默認(rèn)為方法的名稱user。也可以@Bean("xxxx")定義。
@Configuration public class UserConfiguration{ @Bean @ConditionalOnBean(Location.class) public User user(){ return new User(); } }
Spring boot 還為我們提供了更多類似的注解。
也和方式2一樣,也會存在掃描路徑的問題,除了以上的解決方式,還有使用Spring boot starter 的解決方式
在resources下創(chuàng)建如下文件。META-INF/spring.factories.
Spring Boot 在啟動的時候?qū)呙柙撐募瑥暮潍@取到配置類UserConfiguration。
spring.factories.
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.log.config.UserConfiguration
如果不成功,請引入該依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
這個方式也是創(chuàng)建SpringBoot-starter的方式。
方式4:
使用注解@Import,也會創(chuàng)建對象并注入容器中
@Import(User.class) public class MicroblogUserWebApplication { public static void main(String args[]) { SpringApplication.run(MicroblogUserWebApplication.class, args); } }
方式5:
使用ImportSelector或者ImportBeanDefinitionRegistrar接口,配合@Import實(shí)現(xiàn)。
在使用一些Spring Boot第三方組件時,經(jīng)常會看到@EnableXXX來使能相關(guān)的服務(wù),這里以一個例子來實(shí)現(xiàn)。
創(chuàng)建測試類
@Slf4j public class House { public void run(){ log.info("House run ...."); } } @Slf4j public class User { public void run(){ log.info("User run ...."); } } @Slf4j public class Student { public void run(){ log.info("Student run ...."); } }
實(shí)現(xiàn)ImportSelector接口
selectImports方法的返回值為需要創(chuàng)建Bean的類名稱。這里創(chuàng)建User類。
@Slf4j public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { log.info("MyImportSelector selectImports ..."); return new String[]{ User.class.getName()}; } }
實(shí)現(xiàn)ImportBeanDefinitionRegistrar接口
beanDefinitionRegistry.registerBeanDefinition用于設(shè)置需要創(chuàng)建Bean的類名稱。這里創(chuàng)建House類。
@Slf4j public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) { log.info("MyImportBeanDefinitionRegistrar registerBeanDefinitions ....."); BeanDefinition beanDefinition = new RootBeanDefinition(House.class.getName()); beanDefinitionRegistry.registerBeanDefinition(House.class.getName(),beanDefinition); } }
創(chuàng)建一個配置類
這里創(chuàng)建Student類。
@Configuration public class ImportAutoconfiguration { @Bean public Student student(){ return new Student(); } }
創(chuàng)建EnableImportSelector注解
EnableImportSelector注解上使用@Import,引入以上的三個類。
@Retention(RetentionPolicy.RUNTIME) @Documented @Target(ElementType.TYPE) @Import({MyImportSelector.class,ImportAutoconfiguration.class,MyImportBeanDefinitionRegistrar.class}) public @interface EnableImportSelector { String value(); }
測試
@EnableImportSelector(value = "xxx") @SpringBootApplication public class ImportDemoApplication { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(ImportDemoApplication.class, args); User user = context.getBean(User.class); user.run(); Student student = context.getBean(Student.class); student.run(); House house = context.getBean(House.class); house.run(); } }
輸出,可以看到,三個類User Student House都創(chuàng)建成功,都可從Spring 容器中獲取到。
2019-06-20 17:53:39.528 INFO 27255 --- [ main] com.springboot.importselector.pojo.User : User run .... 2019-06-20 17:53:39.530 INFO 27255 --- [ main] c.s.importselector.pojo.Student : Student run .... 2019-06-20 17:53:39.531 INFO 27255 --- [ main] c.springboot.importselector.pojo.House : House run ....
方式6
手動注入Bean容器,有些場景下需要代碼動態(tài)注入,以上方式都不適用。這時就需要創(chuàng)建 對象手動注入。
通過DefaultListableBeanFactory注入。
registerSingleton(String beanName,Object object);
這里手動使用new創(chuàng)建了一個Location對象。并注入容器中。
@Component public class LocationRegister implements BeanFactoryAware { @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { DefaultListableBeanFactory listableBeanFactory = (DefaultListableBeanFactory)beanFactory; Location location = new Location(); listableBeanFactory.registerSingleton("location1",location); } }
這種方式的應(yīng)用場景是為接口創(chuàng)建動態(tài)代理對象,并向SPRING容器注冊。
比如MyBatis中的Mapper接口,Mapper沒有實(shí)現(xiàn)類,啟動時創(chuàng)建動態(tài)代理對象,將該對象注冊到容器中,使用時只要@Autowired注入即可使用,調(diào)用接口方法將會被代理攔截,進(jìn)而調(diào)用相關(guān)的SqlSession執(zhí)行相關(guān)的SQL業(yè)務(wù)邏輯。
可以看以下它的繼承體系
DefaultListableBeanFactory 是ConfigurableListableBeanFactory的實(shí)現(xiàn)類。是對BeanFactory功能的擴(kuò)展。
測試代碼和以上一樣
Location location = context.getBean(Location.class); location.run();
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Spring超詳細(xì)講解創(chuàng)建BeanDefinition流程
- SpringBoot詳細(xì)講解如何創(chuàng)建及刷新Spring容器bean
- Spring-Bean創(chuàng)建對象的步驟方式詳解
- Spring BPP中如何優(yōu)雅的創(chuàng)建動態(tài)代理Bean詳解
- Spring工廠方法創(chuàng)建(實(shí)例化)bean實(shí)例代碼
- 詳解Spring Boot 使用Java代碼創(chuàng)建Bean并注冊到Spring中
- Spring創(chuàng)建Bean完成后執(zhí)行指定代碼的幾種實(shí)現(xiàn)方式
相關(guān)文章
Spring配置shiro時自定義Realm中屬性無法使用注解注入的解決辦法
今天小編就為大家分享一篇關(guān)于Spring配置shiro時自定義Realm中屬性無法使用注解注入的解決辦法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-03-03Java中JDBC實(shí)現(xiàn)動態(tài)查詢的實(shí)例詳解
從多個查詢條件中隨機(jī)選擇若干個組合成一個DQL語句進(jìn)行查詢,這一過程叫做動態(tài)查詢。下面通過實(shí)例代碼給大家講解JDBC實(shí)現(xiàn)動態(tài)查詢的方法,需要的朋友參考下吧2017-07-07Spring @Primary作用和實(shí)現(xiàn)原理詳解
今天分享一下Spring中的@Primary注解,Primary的意思是主要的,我們在使用spring的時候,難免會定義多個類型相同的bean,這時候如果不采取一些方法,那么是無法正常使用bean的,所以本就給大家介紹Spring @Primary的作用和實(shí)現(xiàn)原理2023-07-07Intellij IDEA 添加jar包的三種方式(小結(jié))
這篇文章主要介紹了Intellij IDEA 添加jar包的三種方式(小結(jié)),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-08-08IDEA 項目創(chuàng)建Mapper的xml文件的方法
這篇文章主要介紹了IDEA 項目創(chuàng)建Mapper的xml文件的方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-11-11SpringBoot接口實(shí)現(xiàn)百萬并發(fā)的代碼示例
隨著互聯(lián)網(wǎng)的發(fā)展,越來越多的應(yīng)用需要支持高并發(fā),在這種情況下,如何實(shí)現(xiàn)高并發(fā)成為了一個重要的問題,Spring Boot是一個非常流行的Java框架,它提供了很多方便的功能來支持高并發(fā),本文將介紹如何使用Spring Boot來實(shí)現(xiàn)百萬并發(fā)2023-10-10