javascript
Spring Boot2.x-04Spring Boot基础-使用注解装配bean
文章目錄
- 概述
- 通過Java配置文件@Bean的方式定義Bean
- 通過注解掃描的方式(@Component/@ComponentScan)裝配Bean
- 使用excludeFilters屬性不讓IoC加載某些Bean
- 裝配第三方 Bean
概述
Spring Boot主要是通過注解來裝配 Bean 到 Spring IoC 容器中,使用注解裝配Bean就不得不提AnnotationConfigApplicationContext,很顯然它是一個(gè)基于注解的 IoC 容器。
之前的博文 Spring-基于Java類的配置
通過Java配置文件@Bean的方式定義Bean
POJO類
package com.artisan.springbootmaster.pojo;public class Artisan {public String name;public int age;// setter/getter }然后編寫一個(gè)配置文件
package com.artisan.springbootmaster;import com.artisan.springbootmaster.pojo.Artisan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;@Configuration public class AppConfig {@Bean(name = "artisan")public Artisan initArtisan(){Artisan artisan = new Artisan();artisan.setName("小工匠");artisan.setAge(20);return artisan;} }- @Configuration 代表是一個(gè) Java 配置文件 , Spring會(huì)根據(jù)它來生成 IoC 容器去裝配 Bean
- @Bean 代表將 initArtisan方法返回的 POJO 裝配到 IoC 容器中,屬性 name 定義 Bean 的名稱,如果沒有配置它,則會(huì)將方法名稱“initArtisan作為 Bean 的名稱保存到 Spring IoC 容器中 。
使用 AnnotationConfigApplicationContext 來構(gòu)建
package com.artisan.springbootmaster;import com.artisan.springbootmaster.pojo.Artisan; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class LoadTest {public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);//Artisan artisan = applicationContext.getBean(Artisan.class);Artisan artisan = (Artisan) applicationContext.getBean("artisan");System.out.println(artisan.getName() + " || " + artisan.getAge());} }- new AnnotationConfigApplicationContext(AppConfig.class) 將 Java 配置文件 AppConfig 傳遞給 AnnotationConfigApplicationContext 的構(gòu)造方法,這樣它就能夠?qū)嵗撆渲妙愔卸x的信息,然后將配置里面的 Bean 裝配到 IoC 容器中
- 裝載到IoC容器以后,就可以使用getBean來獲取對(duì)應(yīng)實(shí)例化的bean信息了
輸出 :
23:08:36.164 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'artisan' 小工匠 || 20關(guān)鍵日志:Returning cached instance of singleton bean 'artisan' ,可以知道配置在配置文件中 的名稱為 artisan的 Bean 已經(jīng)被裝配到 IoC 容器中 ,并且可以通過 getBean方法獲取對(duì)應(yīng)的 Bean.
通過注解掃描的方式(@Component/@ComponentScan)裝配Bean
Spring 中可以使用 XML 或者 Java 配置文件的方式裝配 Bean , 但是由于 Spring Boot 是基于注解的方式,因此我們來說下基于注解的方式.
上面的例子使用Java配置文件的方式,使注解@Bean 注入 Spring loC 容器中,假設(shè)有多個(gè)bean的話,就需要多個(gè)@Bean來標(biāo)注多次。
Spring也提供通過掃描的方式去裝配bean到IoC容器中。 對(duì)于掃描裝配而言使用的注解是@Component和@ComponentScan.
- @Component:標(biāo)明哪個(gè)類被掃描進(jìn)入 Spring IoC 容器
- @ComponentScan:標(biāo)明采用何種策略去掃描裝配 Bean
同樣的,我們還是用上個(gè)例子來演示下用法
我們先假設(shè)AppConfig1.java 和 Artisan.java在同一個(gè)包下面 ,
然后對(duì)Artisan這個(gè)類加上@Component注解,如下
package com.artisan.springbootmaster.pojo;import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component;@Component("artisan") public class Artisan {@Value("little_artisan")public String name;@Value("99")public int age;// setter/getter}-
注解@Component 表明這個(gè)類將被Spring IoC容器掃描裝配,bean的名稱為artisan。 如果不配置這個(gè)值 ,那IoC 容器就會(huì)把類名第一個(gè)字母作為小寫,其他的不變作為 Bean 名稱放入到 IoC 容器中。
-
注解@Value 則是指定具體的值,使得 Spring IoC 給予對(duì)應(yīng)的屬性注入對(duì)應(yīng)的值
為了讓 Spring IoC 容器裝配這個(gè)類 , 我們來改造下AppConfig,重新命名為AppConfig1,加入注解@ComponentScan,并取消掉其中的@Bean的配置。
package com.artisan.springbootmaster.pojo;import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration;@Configuration @ComponentScan public class AppConfig1 {}加入了@ComponentScan,意味著它會(huì)進(jìn)行掃描,但是只是個(gè)干巴巴的注解,什么屬性都沒設(shè)置,這就意味著它只會(huì)掃描類 AppConfig1 所在的當(dāng)前包和其子包。 因?yàn)锳rtisan和它在同一個(gè)目錄下,所以可以刪掉之前使用@Bean 標(biāo)注的創(chuàng)建對(duì)象方法。
測(cè)試同第一個(gè)例子
package com.artisan.springbootmaster;import com.artisan.springbootmaster.pojo.AppConfig1; import com.artisan.springbootmaster.pojo.Artisan; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class LoadTest2 {public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig1.class);Artisan artisan = applicationContext.getBean(Artisan.class);System.out.println(artisan.getName() + " || " + artisan.getAge());} 23:17:05.981 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'artisan' little_artisan || 99來,繼續(xù)優(yōu)化,上面為了讓Spring掃描到Artisan, 把Artisan.java類和AppConfig1.java放在一塊,實(shí)在是不合理。所以:使用 @ComponentScan自定義掃包
那就去看下@ComponentScan源碼吧
定義:
方法:
說幾個(gè)比較常用的
- basePackages: 定義掃描的包名,在沒有定義的情況下,只會(huì)掃描當(dāng)前包和其子包下的路徑。
- includeFilters :定義滿足過濾器( Filter )條件的 Bean 才去 掃描,
- excludeFilters :排除過濾器條件的 Bean , 和includeFilters 一樣都需要通過注解@Filter 去定義,@Filter中的type 類型,可以定義為注解或者正則式等類型
- @Filter中classes屬性定義注解類, pattern屬性 定義正則式類。
來吧,把Artisan還是放在pojo下,AppConfig1.java換個(gè)地方吧 ,并通過以下任意方式指定使得 IoC 容器去掃描到 User 類即可
運(yùn)行測(cè)試,結(jié)果同樣可以獲取到
使用excludeFilters屬性不讓IoC加載某些Bean
假設(shè)AppConfig1上配置的basePackages 屬性為basePackages = "com.artisan.springbootmaster.*", 在springbootmaster目錄下還有個(gè)service包,里面的類都標(biāo)注了@Service注解,假設(shè)我們只想讓IoC容器掃描到Artisan類,而不掃描ArtisanService類呢?
只需要加上excludeFilters屬性,通過excludeFilters 指定排除掉標(biāo)注了Service注解的類即可
package com.artisan.springbootmaster;import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Service;@Configuration @ComponentScan(basePackages = "com.artisan.springbootmaster.*",excludeFilters = {@ComponentScan.Filter(classes = {Service.class})}) public class AppConfig1 {}驗(yàn)證下吧
package com.artisan.springbootmaster;import com.artisan.springbootmaster.pojo.Artisan; import com.artisan.springbootmaster.service.ArtisanService; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class LoadTest2 {public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig1.class);Artisan artisan = applicationContext.getBean(Artisan.class);System.out.println(artisan.getName() + " || " + artisan.getAge());ArtisanService artisanService = applicationContext.getBean(ArtisanService.class);artisanService.doSomething();} } 23:54:04.274 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'artisan' little_artisan || 99 Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.artisan.springbootmaster.service.ArtisanService' availableat org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:346)at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:333)at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1105)at com.artisan.springbootmaster.LoadTest2.main(LoadTest2.java:16)Process finished with exit code 1可以看到,No qualifying bean of type 'com.artisan.springbootmaster.service.ArtisanService' available,Spring IoC容器并沒有在啟動(dòng)的時(shí)候去掃表標(biāo)注了@Service的ArtisanService類,說明excludeFilters 起了作用 。由于加入了 excludeFilters 的配置,使標(biāo)注了@Service 的類將不被 IoC 容器掃描注入
裝配第三方 Bean
一個(gè)項(xiàng)目中,不可避免的要使用到第三方的jar,如果希望把第三方包的類對(duì)象也放入到 Spring IoC 容器中,@Bean 注解就發(fā)揮用處了。
如下
package com.artisan.redpacket.config;import java.util.Properties;import javax.sql.DataSource;import org.apache.commons.dbcp2.BasicDataSourceFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.mapper.MapperScannerConfigurer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.stereotype.Repository; import org.springframework.stereotype.Service; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.transaction.annotation.TransactionManagementConfigurer;@Configuration //定義Spring 掃描的包 @ComponentScan(value= "com.*", includeFilters= {@Filter(type = FilterType.ANNOTATION, value ={Service.class})}) //使用事務(wù)驅(qū)動(dòng)管理器 @EnableTransactionManagement //實(shí)現(xiàn)接口TransactionManagementConfigurer,這樣可以配置注解驅(qū)動(dòng)事務(wù) public class RootConfig implements TransactionManagementConfigurer {private DataSource dataSource = null;/*** 配置數(shù)據(jù)庫.* @return 數(shù)據(jù)連接池*/@Bean(name = "dataSource")public DataSource initDataSource() {if (dataSource != null) {return dataSource;}try {Properties props = new Properties();props.load(RootConfig.class.getClassLoader().getResourceAsStream("jdbc.properties"));props.setProperty("driverClassName", props.getProperty("jdbc.driver"));props.setProperty("url", props.getProperty("jdbc.url"));props.setProperty("username", props.getProperty("jdbc.username"));props.setProperty("password", props.getProperty("jdbc.password"));dataSource = BasicDataSourceFactory.createDataSource(props);} catch (Exception e) {e.printStackTrace();}return dataSource;}/**** 配置SqlSessionFactoryBean* @return SqlSessionFactoryBean*/@Bean(name="sqlSessionFactory")public SqlSessionFactoryBean initSqlSessionFactory() {SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();sqlSessionFactory.setDataSource(initDataSource());//配置MyBatis配置文件Resource resource = new ClassPathResource("mybatis/mybatis-config.xml");sqlSessionFactory.setConfigLocation(resource);return sqlSessionFactory;}/**** 通過自動(dòng)掃描,發(fā)現(xiàn)MyBatis Mapper接口* @return Mapper掃描器*/@Bean public MapperScannerConfigurer initMapperScannerConfigurer() {MapperScannerConfigurer msc = new MapperScannerConfigurer();msc.setBasePackage("com.*");msc.setSqlSessionFactoryBeanName("sqlSessionFactory");msc.setAnnotationClass(Repository.class);return msc;}/*** 實(shí)現(xiàn)接口方法,注冊(cè)注解事務(wù),當(dāng)@Transactional 使用的時(shí)候產(chǎn)生數(shù)據(jù)庫事務(wù) */@Override@Bean(name="annotationDrivenTransactionManager")public PlatformTransactionManager annotationDrivenTransactionManager() {DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();transactionManager.setDataSource(initDataSource());return transactionManager;}}上面通過@Bean 如果指定了name屬性的名字,Spring 就會(huì)把該name的值作為bean的名稱 保存在 loC 容器中如果不填name的值,Spring就會(huì)用方法名作為 Bean 名稱保存到IoC 容器中。
總結(jié)
以上是生活随笔為你收集整理的Spring Boot2.x-04Spring Boot基础-使用注解装配bean的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring Boot2.x-03Spr
- 下一篇: Spring Boot2.x-05Spr