您好,登錄后才能下訂單哦!
這篇文章主要介紹“spring中@ComponentScan注解的使用介紹”,在日常操作中,相信很多人在spring中@ComponentScan注解的使用介紹問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”spring中@ComponentScan注解的使用介紹”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!
@ComponentScan注解的使用
一、注解定義
二、使用
1.環(huán)境準(zhǔn)備
2.excludeFilters的使用
3.includeFilters的使用
4.自定義過濾規(guī)則
關(guān)于@ComponentScan注解的一些細(xì)節(jié)
@ComponentScan注解的定義如下:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Repeatable(ComponentScans.class) public @interface ComponentScan { /** * 掃描路徑 * @ComponentScan(value = "spring.annotation.componentscan") */ @AliasFor("basePackages") String[] value() default {}; /** * 掃描路徑 */ @AliasFor("value") String[] basePackages() default {}; /** * 指定掃描類 * @ComponentScan(basePackageClasses = {BookDao.class, BookService.class}) */ Class<?>[] basePackageClasses() default {}; /** * 命名注冊的Bean,可以自定義實(shí)現(xiàn)命名Bean, * 1、@ComponentScan(value = "spring.annotation.componentscan",nameGenerator = MyBeanNameGenerator.class) * MyBeanNameGenerator.class 需要實(shí)現(xiàn) BeanNameGenerator 接口,所有實(shí)現(xiàn)BeanNameGenerator 接口的實(shí)現(xiàn)類都會被調(diào)用 * 2、使用 AnnotationConfigApplicationContext 的 setBeanNameGenerator方法注入一個BeanNameGenerator * BeanNameGenerator beanNameGenerator = (definition,registry)-> String.valueOf(new Random().nextInt(1000)); * AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(); * annotationConfigApplicationContext.setBeanNameGenerator(beanNameGenerator); * annotationConfigApplicationContext.register(MainConfig2.class); * annotationConfigApplicationContext.refresh(); * 第一種方式只會重命名@ComponentScan掃描到的注解類 * 第二種只有是初始化的注解類就會被重命名 * 列如第一種方式不會重命名 @Configuration 注解的bean名稱,而第二種就會重命名 @Configuration 注解的Bean名稱 */ Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class; /** * 用于解析@Scope注解,可通過 AnnotationConfigApplicationContext 的 setScopeMetadataResolver 方法重新設(shè)定處理類 * ScopeMetadataResolver scopeMetadataResolver = definition -> new ScopeMetadata(); 這里只是new了一個對象作為演示,沒有做實(shí)際的邏輯操作 * AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(); * annotationConfigApplicationContext.setScopeMetadataResolver(scopeMetadataResolver); * annotationConfigApplicationContext.register(MainConfig2.class); * annotationConfigApplicationContext.refresh(); * 也可以通過@ComponentScan 的 scopeResolver 屬性設(shè)置 *@ComponentScan(value = "spring.annotation.componentscan",scopeResolver = MyAnnotationScopeMetadataResolver.class) */ Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class; /** * 用來設(shè)置類的代理模式 */ ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT; /** * 掃描路徑 如 resourcePattern = "**/*.class" * 使用 includeFilters 和 excludeFilters 會更靈活 */ String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN; /** * 指示是否應(yīng)啟用對帶有{@code @Component},{@ code @Repository}, * {@ code @Service}或{@code @Controller}注釋的類的自動檢測。 */ boolean useDefaultFilters() default true; /** * 對被掃描的包或類進(jìn)行過濾,若符合條件,不論組件上是否有注解,Bean對象都將被創(chuàng)建 * @ComponentScan(value = "spring.annotation.componentscan",includeFilters = { * @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class}), * @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {SchoolDao.class}), * @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class}), * @ComponentScan.Filter(type = FilterType.ASPECTJ, pattern = "spring.annotation..*"), * @ComponentScan.Filter(type = FilterType.REGEX, pattern = "^[A-Za-z.]+Dao$") * },useDefaultFilters = false) * useDefaultFilters 必須設(shè)為 false */ Filter[] includeFilters() default {}; /** * 指定哪些類型不適合進(jìn)行組件掃描。 * 用法同 includeFilters 一樣 */ Filter[] excludeFilters() default {}; /** * 指定是否應(yīng)注冊掃描的Bean以進(jìn)行延遲初始化。 * @ComponentScan(value = "spring.annotation.componentscan",lazyInit = true) */ boolean lazyInit() default false; /** * 用于 includeFilters 或 excludeFilters 的類型篩選器 */ @Retention(RetentionPolicy.RUNTIME) @Target({}) @interface Filter { /** * 要使用的過濾器類型,默認(rèn)為 ANNOTATION 注解類型 * @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class}) */ FilterType type() default FilterType.ANNOTATION; /** * 過濾器的參數(shù),參數(shù)必須為class數(shù)組,單個參數(shù)可以不加大括號 * 只能用于 ANNOTATION 、ASSIGNABLE_TYPE 、CUSTOM 這三個類型 * @ComponentScan.Filter(type = FilterType.ANNOTATION, value = {Controller.class, Service.class}) * @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {SchoolDao.class}) * @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class}) */ @AliasFor("classes") Class<?>[] value() default {}; /** * 作用同上面的 value 相同 * ANNOTATION 參數(shù)為注解類,如 Controller.class, Service.class, Repository.class * ASSIGNABLE_TYPE 參數(shù)為類,如 SchoolDao.class * CUSTOM 參數(shù)為實(shí)現(xiàn) TypeFilter 接口的類 ,如 MyTypeFilter.class * MyTypeFilter 同時還能實(shí)現(xiàn) EnvironmentAware,BeanFactoryAware,BeanClassLoaderAware,ResourceLoaderAware * 這四個接口 * EnvironmentAware * 此方法用來接收 Environment 數(shù)據(jù) ,主要為程序的運(yùn)行環(huán)境,Environment 接口繼承自 PropertyResolver 接口, * 詳細(xì)內(nèi)容在下方 * @Override * public void setEnvironment(Environment environment) { * String property = environment.getProperty("os.name"); * } * * BeanFactoryAware * BeanFactory Bean容器的根接口,用于操作容器,如獲取bean的別名、類型、實(shí)例、是否單例的數(shù)據(jù) * @Override * public void setBeanFactory(BeanFactory beanFactory) throws BeansException { * Object bean = beanFactory.getBean("BeanName") * } * * BeanClassLoaderAware * ClassLoader 是類加載器,在此方法里只能獲取資源和設(shè)置加載器狀態(tài) * @Override * public void setBeanClassLoader(ClassLoader classLoader) { * ClassLoader parent = classLoader.getParent(); * } * * ResourceLoaderAware * ResourceLoader 用于獲取類加載器和根據(jù)路徑獲取資源 * public void setResourceLoader(ResourceLoader resourceLoader) { * ClassLoader classLoader = resourceLoader.getClassLoader(); * } */ @AliasFor("value") Class<?>[] classes() default {}; /** * 這個參數(shù)是 classes 或 value 的替代參數(shù),主要用于 ASPECTJ 類型和 REGEX 類型 * ASPECTJ 為 ASPECTJ 表達(dá)式 * @ComponentScan.Filter(type = FilterType.ASPECTJ, pattern = "spring.annotation..*") * REGEX 參數(shù)為 正則表達(dá)式 * @ComponentScan.Filter(type = FilterType.REGEX, pattern = "^[A-Za-z.]+Dao$") */ String[] pattern() default {}; } }
創(chuàng)建Maven項目,添加依賴:
<dependencies> <!-- https://mvnrepository.com/artifact/org.springframework/spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.26.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/junit/junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies>
創(chuàng)建bean,controller,dao,service層,并在類上加上對應(yīng)的注解,項目結(jié)構(gòu)如下:
編寫測試類,如下:
public class IoCTest { @Test public void test01() { //獲取Spring的IOC容器 ApplicationContext applicationContext=new AnnotationConfigApplicationContext(SpringConfig.class); //從容器中獲取bean String[] names= applicationContext.getBeanDefinitionNames(); for(String i:names) { System.out.println(i); } } }
使用excludeFilters不掃描com.learn包中的Controller、Service注解,如下:
@Configuration @ComponentScan(basePackages = "com.learn",excludeFilters = { @Filter(type = FilterType.ANNOTATION,classes = {Controller.class,Service.class}) }) public class SpringConfig { }
上面使用的excludeFilters用于設(shè)置排除的過濾條件,實(shí)現(xiàn)Filter接口的type屬性用于設(shè)置過濾類型,默認(rèn)值為FilterType.ANNOTATION,提供了這幾個過濾類型:
FilterType.ANNOTATION
:按照注解過濾
FilterType.ASSIGNABLE_TYPE
:按照給定的類型過濾
FilterType.ASPECTJ
:按照ASPECTJ表達(dá)式過濾
FilterType.REGEX
:按照正則表達(dá)式過濾
FilterType.CUSTOM
:按照自定義規(guī)則過濾
classes和value屬性為過濾器的參數(shù),必須為class數(shù)組,類只能為以下三種類型:
ANNOTATION
參數(shù)為注解類,如 Controller.class, Service.class,Repository.class
ASSIGNABLE_TYPE
參數(shù)為類,如 SchoolDao.class
CUSTOM
參數(shù)為實(shí)現(xiàn) TypeFilter 接口的類 ,如 MyTypeFilter.class
includeFilters屬性用于定義掃描過濾條件,滿足該條件才進(jìn)行掃描。用法與excludeFilters一樣。
但是因?yàn)閡seDefaultFilters屬性默認(rèn)為true,即使用默認(rèn)的過濾器,啟用對帶有@Component,@Repository,@Service,@Controller注釋的類的自動檢測。會將帶有這些注解的類注冊為bean裝配到IoC容器中。所以使用includeFilters時,需要把useDefaultFilters設(shè)置為false,如下:
@Configuration @ComponentScan(basePackages = "com.learn",includeFilters = { @Filter(type = FilterType.ANNOTATION,classes = {Controller.class,Service.class}) },useDefaultFilters = false) public class SpringConfig { }
結(jié)果如下,只掃描了帶有Controller,Service注解的自定義的類:
@ComponentScan注解掃描或解析的bean只能是Spring內(nèi)部所定義的,比如@Component、@Service、@Controller或@Repository。如果要掃描一些自定義的注解,就可以自定義過濾規(guī)則來完成這個操作。
自定義一個類MyTypeFilter實(shí)現(xiàn)TypeFilter接口,這樣這個TypeFilter就掃描所有類并只通過類名包含了controller的類,如下:
public class MyTypeFilter implements TypeFilter { /** * 兩個參數(shù)的含義: * metadataReader:包含讀取到的當(dāng)前正在掃描的類的信息 * metadataReaderFactory:可以獲取到當(dāng)前正在掃描的類的其他類信息(如父類和接口) * match方法返回false即不通過過濾規(guī)則,true通過過濾規(guī)則 */ @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { // TODO Auto-generated method stub //獲取當(dāng)前類注解的信息 AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); //獲取當(dāng)前正在掃描的類的類信息 ClassMetadata classMetadata = metadataReader.getClassMetadata(); //獲取當(dāng)前類資源(類的路徑) Resource resource = metadataReader.getResource(); String className = classMetadata.getClassName(); if(className.contains("controller")){ return true; } return false; } }
在@ComponentScan注解中進(jìn)行配置,如下:
@Configuration @ComponentScan(basePackages = "com.learn",includeFilters = { @Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {Person.class}), @Filter(type = FilterType.CUSTOM,classes = {MyTypeFilter.class}), },useDefaultFilters = false) public class SpringConfig { }
經(jīng)過上面的配置,第一個@Filter通過FilterType.ASSIGNABLE_TYPE規(guī)定了只掃描Person類型的類,第二個@Filter通過FilterType.CUSTOM自定義過濾規(guī)則規(guī)定了只掃描類名包含controller的類。結(jié)果:
@ComponentScan注解可以掃描 任意 類 或者 注解 中內(nèi)部類bean;
要想被掃描的前提是內(nèi)部類標(biāo)注了@Component及其相關(guān)衍生注解、內(nèi)部類必須是static修飾,否則掃描不到;如果是注解的內(nèi)部類則只能是public static修飾
//@Configuration public class ProfileConfig { @Component("class1") private static class Class1 { @Bean public Class3 class3() { return new Class3(); } } @Component("class2") static class Class2 { } //@Component("class3") protected static class Class3 { } // @Component("class4") //出錯 // protected class Class4 { // // } } -------------------------------------------------------- @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) //@Bean public @interface MyBean { public static final int age1=3; //常量可以 int age=2; public abstract String value() default "qwer"; //屬性可以 //內(nèi)部類可以 @Component @DependsOn("myBean.EventZ") //依賴事件bean的創(chuàng)建,保證該bean在事件bean之后創(chuàng)建 //細(xì)節(jié):因?yàn)槭莾?nèi)部類,所以默認(rèn)bean的id是類名首字母小寫,不是eventZ而是myBean.EventZ class EventSource { public EventSource(){ System.out.println("事件源創(chuàng)建了..."); } } @Component//("eventZ") public static class EventZ { public EventZ(){ System.out.println("事件創(chuàng)建了..."); } } }
到此,關(guān)于“spring中@ComponentScan注解的使用介紹”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。