Springboot項目實現將類從@ComponentScan中排除
將類從@ComponentScan中排除
問題描述
最近在學習SpringCloud的Ribbon,在使用
@RibbonClient(name = "SPRINGCLOUD-P-DEPT", configuration = RibbonConfig.class)
為服務指定負載均衡策略的時候,根據Ribbon官方文檔介紹,自定義的Ribbon配置類不允許被Springboot的**@ComponentScan**註解掃描到,所以需要將自定義的配置類RibbonConfig從在Springboot自動註入的范圍內排除
方案一
我們都知道,Springboot的**@SpringBootApplication**會自動掃描本類所在包下的所有類和子類,所以隻需要將RibbonConfig定義在Springboot啟動類所在包外面即可
方案二
通過在啟動類中添加
@ComponentScan(excludeFilters = @ComponentScan.Filter( type = FilterType.ASSIGNABLE_TYPE, classes = RibbonConfig.class))
通過FilterType.ASSIGNABLE_TYPE來指定要排除的類
如果需要排除的類太多瞭這個就很麻煩
方案三
通過自定義註解實現
@ComponentScan(excludeFilters = @ComponentScan.Filter( type = FilterType.ANNOTATION, classes = ScanIgnore.class))
與方案二不同的是,這裡用的是FilterType.ANNOTATION
方案四
通過實現TypeFilter類來自定義過濾器
@ComponentScan(excludeFilters = { @Filter( type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter( type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
此處給出的就是**@SpringbootApplication中的實現方式,通過FilterType.CUSTOM**來根據自動一過濾器來排除bean
最後貼出枚舉類FilterType:
/* * Copyright 2002-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.context.annotation; /** * Enumeration of the type filters that may be used in conjunction with * {@link ComponentScan @ComponentScan}. * * @author Mark Fisher * @author Juergen Hoeller * @author Chris Beams * @since 2.5 * @see ComponentScan * @see ComponentScan#includeFilters() * @see ComponentScan#excludeFilters() * @see org.springframework.core.type.filter.TypeFilter */ public enum FilterType { /** * Filter candidates marked with a given annotation. * @see org.springframework.core.type.filter.AnnotationTypeFilter */ ANNOTATION, /** * Filter candidates assignable to a given type. * @see org.springframework.core.type.filter.AssignableTypeFilter */ ASSIGNABLE_TYPE, /** * Filter candidates matching a given AspectJ type pattern expression. * @see org.springframework.core.type.filter.AspectJTypeFilter */ ASPECTJ, /** * Filter candidates matching a given regex pattern. * @see org.springframework.core.type.filter.RegexPatternTypeFilter */ REGEX, /** Filter candidates using a given custom * {@link org.springframework.core.type.filter.TypeFilter} implementation. */ CUSTOM }
@ComponentScan 詳解
@ComponentScan 的作用就是根據定義的掃描路徑,把符合掃描規則的類裝配到spring容器中,註解定義如下。
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) @Documented @Repeatable(ComponentScans.class) public @interface ComponentScan { @AliasFor("basePackages") String[] value() default {}; @AliasFor("value") String[] basePackages() default {}; Class<?>[] basePackageClasses() default {}; Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class; Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class; ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT; String resourcePattern() default "**/*.class"; boolean useDefaultFilters() default true; ComponentScan.Filter[] includeFilters() default {}; ComponentScan.Filter[] excludeFilters() default {}; boolean lazyInit() default false; @Retention(RetentionPolicy.RUNTIME) @Target({}) public @interface Filter { FilterType type() default FilterType.ANNOTATION; @AliasFor("classes") Class<?>[] value() default {}; @AliasFor("value") Class<?>[] classes() default {}; String[] pattern() default {}; } }
basePackages
與value
: 用於指定包的路徑,進行掃描basePackageClasses
: 用於指定某個類的包的路徑進行掃描nameGenerator
: bean的名稱的生成器useDefaultFilters
: 是否開啟對@Component,@Repository,@Service,@Controller的類進行檢測includeFilters
: 包含的過濾條件
FilterType.ANNOTATION
:按照註解過濾
FilterType.ASSIGNABLE_TYPE
:按照給定的類型
FilterType.ASPECTJ
:使用ASPECTJ表達式
FilterType.REGEX
:正則
FilterType.CUSTOM
:自定義規則
excludeFilters
: 排除的過濾條件,用法和includeFilters一樣
我的工程結構如下,測試對controller和service的掃描,其中HelloController沒有加@Controller等任何註解,就是一個普通類。
修改配置類如下:應用默認的過濾器,掃描service包:
@Configuration @ComponentScan(value = "com.xhx.spring.service", useDefaultFilters = true ) public class MyConfig { }
系統註入瞭兩個service進去
改成如下所示:HelloController所在的包的類也被掃描瞭進去
@Configuration @ComponentScan(value = "com.xhx.spring.service", useDefaultFilters = true, basePackageClasses = HelloController.class ) public class MyConfig { }
系統中會註入下面就給類
把默認的過濾器關掉,掃描帶Controller註解的。
@Configuration @ComponentScan(value = "com.xhx.spring", useDefaultFilters = false, includeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class}) } ) public class MyConfig { }
按照類的類型掃描,雖然HelloController沒有加註解,但是被註入到瞭spring容器中
@Configuration @ComponentScan(value = "com.xhx.spring", useDefaultFilters = false, includeFilters = { @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {HelloController.class}) } ) public class MyConfig { }
自定義掃描過濾器
package com.xhx.spring.componentscan.config; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.filter.TypeFilter; import java.io.IOException; /** * xuhaixing * 2018/9/18 23:07 **/ public class MyTypeFilter implements TypeFilter { @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { String className = metadataReader.getClassMetadata().getClassName(); if(className.contains("Controller")){ return true; } return false; } }
修改配置類
@Configuration @ComponentScan(value = "com.xhx.spring", useDefaultFilters = false, includeFilters = { @ComponentScan.Filter(type = FilterType.CUSTOM,classes = {MyTypeFilter.class}) } ) public class MyConfig { }
輸出結果:
輸出spring容器中的bean的測試類:隻過濾輸出瞭名字中含有hello的類。
package com.xhx.spring.componentscan; import com.xhx.spring.componentscan.config.MyConfig; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.test.context.junit4.SpringRunner; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @RunWith(SpringRunner.class) @SpringBootTest public class ComponentScanApplicationTests { @Test public void testLoads() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class); List<String> hello = Arrays.stream(context.getBeanDefinitionNames()).collect(Collectors.toList()); hello.stream().filter(name->name.contains("hello")).peek(System.out::println).count(); } }
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- 詳解Spring系列之@ComponentScan自動掃描組件
- 基於@ComponentScan註解的使用詳解
- SpringBoot默認包掃描機制及@ComponentScan指定掃描路徑詳解
- Spring Boot 排除某個類加載註入IOC的操作
- springboot 啟動如何排除某些bean的註入