<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在前面的章節,我們介紹了@Comfiguration
和@Bean
結合AnnotationConfigApplicationContext
零xml組態檔使用Spring容器的方式,也介紹了通過<context:component-scan base-package="org.example"/>
掃描包路徑下的bean的方式。如果忘了可以看下前面幾篇。這篇我們來結合這2種方式來理解@ComponentScan
@ComponentScan
基本原理和使用
@ComponentScan
進階使用
@Componet
及其衍生註解使用
原始碼中解析為設定元件掃描指令與@Configuration
類一起使用提供與 Spring XML 的 <context:component-scan>
元素同樣的作用支援。簡單點說,就是可以掃描特定包下的bean定義資訊,將其註冊到容器中,並自動提供依賴注入。
@ComponentScan
可以對應一下xml設定。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="org.example"/> </beans>
提示: 使用 <context:component-scan>
隱式啟用 <context:annotation-config>
的功能,也就是掃描批次註冊並自動DI。
預設情況下,使用@Component
、@Repository
、@Service
、@Controller
、@Configuration
註釋的類或本身使用@Component 註釋的自定義註釋是會作為元件被@ComponentScan
指定批次掃描到容器中自動註冊。
@Component public class RepositoryA implements RepositoryBase { } @Component public class Service1 { @Autowired private RepositoryBase repository; }
@Configuration @ComponentScan(basePackages = "com.crab.spring.ioc.demo08") public class AppConfig { }
@org.junit.Test public void test_component_scan1() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); Service1 service1 = context.getBean(Service1.class); System.out.println(service1); context.close(); }
@ComponentScan
原始碼和解析如下
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Repeatable(ComponentScans.class) public @interface ComponentScan { // 見 basePackages @AliasFor("basePackages") String[] value() default {}; // 指定掃描元件的包路徑,為空則預設是掃描當前類所在包及其子包 @AliasFor("value") String[] basePackages() default {}; // 指定要掃描帶註釋的元件的包 可替換basePackages Class<?>[] basePackageClasses() default {}; // 用於命名 Spring 容器中檢測到的元件的類 Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class; // 指定解析bean作用域的類 Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class; // 指示為檢測到的元件生成代理的模式 ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT; // 控制符合元件檢測條件的類檔案;建議使用下面的 includeFilters excludeFilters String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN; // 指示是否應啟用使用 @Component @Repository @Service @Controller 註釋的類的自動檢測。 boolean useDefaultFilters() default true; // 指定哪些型別適合元件掃描。進一步將候選元件集從basePackages中的所有內容縮小到與給定過濾器或多個過濾 器匹配的基本包中的所有內容。 // <p>請注意,除了預設過濾器(如果指定)之外,還將應用這些過濾器。將包含指定基本包下與給定過濾器匹配的任 何型別,即使它與預設過濾器不匹配 Filter[] includeFilters() default {}; // 定哪些型別不適合元件掃描 Filter[] excludeFilters() default {}; // 指定是否應為延遲初始化註冊掃描的 bean boolean lazyInit() default false; }
其中用到的Filter
型別過濾器的原始碼和解析如下
@Retention(RetentionPolicy.RUNTIME) @Target({}) @interface Filter { // 過濾的型別 支援註解、類、正則、自定義等 FilterType type() default FilterType.ANNOTATION; @AliasFor("classes") Class<?>[] value() default {}; // 指定匹配的型別,多個時是OR關係 @AliasFor("value") Class<?>[] classes() default {}; // 用於過濾器的匹配模式,valua沒有設定時的替代方法,根據type變化 String[] pattern() default {}; }
FilterType
的支援型別如下
過濾型別 | 樣例表示式 | 描述 |
---|---|---|
annotation (default) | org.example.SomeAnnotation | 在目標元件的型別級別存在的註釋。 |
assignable | org.example.SomeClass | 目標元件可分配(擴充套件或實現)的類(或介面) |
aspectj | org.example..*Service+ | 要由目標元件匹配的 AspectJ 型別表示式。 |
regex | org.example.Default.* | 與目標元件的類名匹配的正規表示式。 |
custom | org.example.MyTypeFilter | org.springframework.core.type.TypeFilter 介面的自定義實現。 |
忽略所有@Repository 註釋並使用特定包下正規表示式來匹配*Repository
@Configuration @ComponentScan(basePackages = "org.example", includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*My.*Repository"), excludeFilters = @Filter(Repository.class)) public class AppConfig { // ... }
自定義一個生成策略實現BeanNameGenerator
介面
/** * 自定義的bean名稱生成策略 * @author zfd * @version v1.0 * @date 2022/1/19 9:07 * @關於我 請關注公眾號 螃蟹的Java筆記 獲取更多技術系列 */ public class MyNameGenerator implements BeanNameGenerator { public MyNameGenerator() { } @Override public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) { // bean命名統一採用固定字首+類名 return "crab$$" + definition.getBeanClassName(); } }
在@ComponentScan
中指定生成名稱策略
@Configuration @ComponentScan(basePackages = "com.crab.spring.ioc.demo08", nameGenerator = MyNameGenerator.class) public class AppConfig { }
從 Spring Framework 5.2.3 開始,位於包 org.springframework.context.annotation 中的 FullyQualifiedAnnotationBeanNameGenerator 可用於預設為生成的 bean 名稱的完全限定類名稱
測試輸出
@org.junit.Test public void test_name_generator() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); Service1 service1 = context.getBean(Service1.class); Arrays.stream(context.getBeanNamesForType(service1.getClass())).forEach(System.out::println); System.out.println(service1); context.close(); } // bean名稱中存在我們自定義的命名了 crab$$com.crab.spring.ioc.demo08.Service1 com.crab.spring.ioc.demo08.Service1@769f71a9
與一般 Spring 管理的元件一樣,自動檢測元件的預設和最常見的範圍是單例。可以使用@Scope
註解中提供範圍的名稱,針對單個元件。
@Scope("prototype") // @Repository public class MovieFinderImpl implements MovieFinder { // ... }
針對全部掃描元件,可以提供自定義作用域策略。
自定義策略實現ScopeMetadataResolver
介面
/** * 自定義作用域策略 * @author zfd * @version v1.0 * @date 2022/1/19 9:32 * @關於我 請關注公眾號 螃蟹的Java筆記 獲取更多技術系列 */ public class MyMetadataResolver implements ScopeMetadataResolver { @Override public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) { ScopeMetadata metadata = new ScopeMetadata(); // 指定原型作用域 metadata.setScopeName(BeanDefinition.SCOPE_PROTOTYPE); // 代理模式為介面 metadata.setScopedProxyMode(ScopedProxyMode.INTERFACES); return metadata; } }
在@ComponentScan
中指定作用域策略
@Configuration @ComponentScan(basePackages = "com.crab.spring.ioc.demo08", // nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class) nameGenerator = MyNameGenerator.class, scopeResolver = MyMetadataResolver.class ) public class AppConfig { }
@Component
是任何 Spring 管理的元件的通用原型註解。在使用基於註釋的設定和類路徑掃描時,此類類被視為自動檢測的候選物件
@Repository
、@Service
和 @Controller
是 @Component
針對更具體的用例(分別在持久層、服務層和表示層)的特化。
簡單看一下的註解@Component
和@Repository
定義,其它的類似
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Indexed public @interface Component { // 指定元件名 String value() default ""; }
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component // 元註解@Component public @interface Repository { @AliasFor(annotation = Component.class) String value() default ""; }
Spring 提供的許多註解都可以在您自己的程式碼中用作元註解。元註釋是可以應用於另一個註釋的註釋。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Component // @Component 導致 @Service 以與 @Component 相同的方式處理 public @interface Service { // ... }
可以組合元註釋來建立“組合註釋”,例如@RestController
就是@ResponseBody
和@Controller
的組合。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Controller @ResponseBody public @interface RestController { @AliasFor(annotation = Controller.class) String value() default ""; }
組合註釋可以選擇從元註釋中重新宣告屬性以允許自定義。這在只想公開元註釋屬性的子集時可能特別有用。
例如,Spring 的 @SessionScope 註解將作用域名稱寫死為 session,但仍允許自定義 proxyMode。
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Scope(WebApplicationContext.SCOPE_SESSION) public @interface SessionScope { // 重新宣告了元註解的屬性並賦予了預設值 @AliasFor(annotation = Scope.class) ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS; }
Spring 中對java的註解增強之一: 通過@AliasFor
宣告註解屬性的別名,此機制實現了通過當前註解內的屬性給元註解屬性賦值。
本文介紹各種@ComponentScan
批次掃描註冊bean的基本使用以及進階用法和@Componet
及其衍生註解使用。
本篇原始碼地址: https://github.com/kongxubihai/pdf-spring-series/tree/main/spring-series-ioc/src/main/java/com/crab/spring/ioc/demo08
知識分享,轉載請註明出處。學無先後,達者為先!
到此這篇關於詳解Spring系列之@ComponentScan批次註冊bean的文章就介紹到這了,更多相關Spring @ComponentScan批次註冊bean內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45