Springboot项目实现将类从@ComponentScan中排除

 更新时间:2021年11月05日 10:17:57   作者:SenKnight  
这篇文章主要介绍了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 {};
    }
}
  • basePackagesvalue: 用于指定包的路径,进行扫描
  • 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();
    } 
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • springboot项目监控开发小用例(实例分析)

    springboot项目监控开发小用例(实例分析)

    这篇文章主要介绍了springboot项目监控开发小用例,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • java中Timer定时器的使用和启动方式

    java中Timer定时器的使用和启动方式

    这篇文章主要介绍了java中Timer定时器的使用和启动方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • Spring中的refreshContext源码分析

    Spring中的refreshContext源码分析

    这篇文章主要介绍了Spring中的refreshContext源码分析,在SpringBoot启动流程中,主要的两个阶段是初始化SpringApplication对象以及SpringApplication.run方法执行的内容,今天主要细讲的是SpringApplication.run中的刷新容器refreshContext方法,需要的朋友可以参考下
    2023-12-12
  • 汇总Java中List 去重的 6 种方法

    汇总Java中List 去重的 6 种方法

    这篇文章主要介绍了汇总Java中List 去重的 6 种方法,文章围绕主题展开List去重的方法,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-05-05
  • Java编写实现窗体程序显示日历

    Java编写实现窗体程序显示日历

    这篇文章主要为大家详细介绍了Java编写实现窗体程序显示日历,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • GC算法实现垃圾优先算法

    GC算法实现垃圾优先算法

    为什么会存在那么多的垃圾回收算法呢?我想这个问题的答案可能是没有任何一种内存回收算法是完美的,所以在针对不同的情景需求下,不同的内存回收算法有其独特的优势,所以最后就延续了多种回收算法
    2022-01-01
  • SpringBoot声明式事务的简单运用说明

    SpringBoot声明式事务的简单运用说明

    这篇文章主要介绍了SpringBoot声明式事务的简单运用说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • SpringBoot 实现流控的操作方法

    SpringBoot 实现流控的操作方法

    本文介绍了限流算法的基本概念和常见的限流算法,包括计数器算法、漏桶算法和令牌桶算法,还介绍了如何在Spring Boot中使用Guava库和自定义注解以及AOP实现接口限流功能,感兴趣的朋友一起看看吧
    2024-12-12
  • 详解Java设计模式编程中命令模式的项目结构实现

    详解Java设计模式编程中命令模式的项目结构实现

    这篇文章主要介绍了Java设计模式编程中命令模式的项目结构实现,命令模式将请求与执行分离,可以多个命令接口的实现类,隐藏真实的被调用方,需要的朋友可以参考下
    2016-04-04
  • springboot自动重连Redis的实现方法

    springboot自动重连Redis的实现方法

    由于网络或服务器问题,Redis连接可能会断开,导致应用程序无法继续正常工作,本文主要介绍了springboot自动重连Redis的实现方法,具有一定的参考价值,感兴趣的可以了解一下
    2024-02-02

最新评论