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(); } }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。