纯净、安全、绿色的下载网站

首页|软件分类|下载排行|最新软件|IT学院

当前位置:首页IT学院IT技术

@ComponentScan注解使用 基于@ComponentScan注解的使用详解

Code0cean   2021-08-16 我要评论
想了解基于@ComponentScan注解的使用详解的相关内容吗Code0cean在本文为您仔细讲解@ComponentScan注解使用的相关知识和一些Code实例欢迎阅读和指正我们先划重点:@ComponentScan注解,注解的使用下面大家一起来学习吧。

@ComponentScan注解的使用

一、注解定义

@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可以自定义实现命名Bean
    * 1、@ComponentScan(value = "spring.annotation.componentscan",nameGenerator = MyBeanNameGenerator.class)
    * MyBeanNameGenerator.class 需要实现 BeanNameGenerator 接口所有实现BeanNameGenerator 接口的实现类都会被调用
    * 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 方法重新设定处理类
    * ScopeMetadataResolver scopeMetadataResolver = definition -> new ScopeMetadata();  这里只是new了一个对象作为演示没有做实际的逻辑操作
    * AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
    * annotationConfigApplicationContext.setScopeMetadataResolver(scopeMetadataResolver);
    * annotationConfigApplicationContext.register(MainConfig2.class);
    * annotationConfigApplicationContext.refresh();
    * 也可以通过@ComponentScan 的 scopeResolver 属性设置
    *@ComponentScan(value = "spring.annotation.componentscan",scopeResolver = MyAnnotationScopeMetadataResolver.class)
    */
   Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
   /**
    * 用来设置类的代理模式
    */
   ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
   /**
    * 扫描路径 如 resourcePattern = "**/*.class"
    * 使用  includeFilters 和 excludeFilters 会更灵活
    */
   String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;
   /**
    * 指示是否应启用对带有{@code @Component}{@ code @Repository}
    * {@ code @Service}或{@code @Controller}注释的类的自动检测。
    */
   boolean useDefaultFilters() default true;
   /**
    * 对被扫描的包或类进行过滤若符合条件不论组件上是否有注解Bean对象都将被创建
    * @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 必须设为 false
    */
   Filter[] includeFilters() default {};
   /**
    * 指定哪些类型不适合进行组件扫描。
    * 用法同 includeFilters 一样
    */
   Filter[] excludeFilters() default {};
   /**
    * 指定是否应注册扫描的Bean以进行延迟初始化。
    * @ComponentScan(value = "spring.annotation.componentscan",lazyInit = true)
    */
   boolean lazyInit() default false;
   /**
    * 用于 includeFilters 或 excludeFilters 的类型筛选器
    */
   @Retention(RetentionPolicy.RUNTIME)
   @Target({})
   @interface Filter {
      /**
       * 要使用的过滤器类型默认为 ANNOTATION 注解类型
       * @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})
       */
      FilterType type() default FilterType.ANNOTATION;
      /**
       * 过滤器的参数参数必须为class数组单个参数可以不加大括号
       * 只能用于 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 参数为注解类如  Controller.class, Service.class, Repository.class
       * ASSIGNABLE_TYPE 参数为类如 SchoolDao.class
       * CUSTOM  参数为实现 TypeFilter 接口的类 如 MyTypeFilter.class
       * MyTypeFilter 同时还能实现 EnvironmentAwareBeanFactoryAwareBeanClassLoaderAwareResourceLoaderAware 
       * 这四个接口
       * EnvironmentAware
       * 此方法用来接收 Environment 数据 主要为程序的运行环境Environment 接口继承自 PropertyResolver 接口
       * 详细内容在下方
       * @Override
       * public void setEnvironment(Environment environment) {
       *    String property = environment.getProperty("os.name");
       * }
       * 
       * BeanFactoryAware
       * BeanFactory Bean容器的根接口用于操作容器如获取bean的别名、类型、实例、是否单例的数据
       * @Override
       * public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
       *     Object bean = beanFactory.getBean("BeanName")
       * }
       * 
       * BeanClassLoaderAware
       * ClassLoader 是类加载器在此方法里只能获取资源和设置加载器状态
       * @Override
       * public void setBeanClassLoader(ClassLoader classLoader) {
       *     ClassLoader parent = classLoader.getParent();
       * }
       * 
       * ResourceLoaderAware
       * ResourceLoader 用于获取类加载器和根据路径获取资源
       * public void setResourceLoader(ResourceLoader resourceLoader) {
       *     ClassLoader classLoader = resourceLoader.getClassLoader();
       * }
       */
      @AliasFor("value")
      Class<?>[] classes() default {};
      /**
       * 这个参数是 classes 或 value 的替代参数主要用于 ASPECTJ 类型和  REGEX 类型
       * ASPECTJ  为 ASPECTJ 表达式
       * @ComponentScan.Filter(type = FilterType.ASPECTJ, pattern = "spring.annotation..*")
       * REGEX  参数为 正则表达式
       * @ComponentScan.Filter(type = FilterType.REGEX, pattern = "^[A-Za-z.]+Dao$")
       */
      String[] pattern() default {};
   }
}

二、使用

1.环境准备

创建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>

创建beancontrollerdaoservice层并在类上加上对应的注解项目结构如下:

在这里插入图片描述

编写测试类如下:

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);
	       }
	}
}

2.excludeFilters的使用

使用excludeFilters不扫描com.learn包中的Controller、Service注解如下:

@Configuration
@ComponentScan(basePackages = "com.learn",excludeFilters = {
  @Filter(type = FilterType.ANNOTATION,classes = {Controller.class,Service.class})
})
public class SpringConfig {
}

上面使用的excludeFilters用于设置排除的过滤条件实现Filter接口的type属性用于设置过滤类型默认值为FilterType.ANNOTATION提供了这几个过滤类型:

  • FilterType.ANNOTATION:按照注解过滤
  • FilterType.ASSIGNABLE_TYPE:按照给定的类型过滤
  • FilterType.ASPECTJ:按照ASPECTJ表达式过滤
  • FilterType.REGEX:按照正则表达式过滤
  • FilterType.CUSTOM:按照自定义规则过滤

classes和value属性为过滤器的参数必须为class数组类只能为以下三种类型:

  • ANNOTATION 参数为注解类如 Controller.class, Service.class,Repository.class
  • ASSIGNABLE_TYPE 参数为类如 SchoolDao.class
  • CUSTOM 参数为实现 TypeFilter 接口的类 如 MyTypeFilter.class

3.includeFilters的使用

includeFilters属性用于定义扫描过滤条件满足该条件才进行扫描。用法与excludeFilters一样。

但是因为useDefaultFilters属性默认为true即使用默认的过滤器启用对带有@Component@Repository@Service@Controller注释的类的自动检测。会将带有这些注解的类注册为bean装配到IoC容器中。所以使用includeFilters时需要把useDefaultFilters设置为false如下:

@Configuration
@ComponentScan(basePackages = "com.learn",includeFilters = {
  @Filter(type = FilterType.ANNOTATION,classes = {Controller.class,Service.class})
},useDefaultFilters = false)
public class SpringConfig {
}

结果如下只扫描了带有ControllerService注解的自定义的类:

在这里插入图片描述

4.自定义过滤规则

@ComponentScan注解扫描或解析的bean只能是Spring内部所定义的比如@Component、@Service、@Controller或@Repository。如果要扫描一些自定义的注解就可以自定义过滤规则来完成这个操作。

自定义一个类MyTypeFilter实现TypeFilter接口这样这个TypeFilter就扫描所有类并只通过类名包含了controller的类如下:

public class MyTypeFilter implements TypeFilter {
    /**
     * 两个参数的含义:
     * metadataReader:包含读取到的当前正在扫描的类的信息
     * metadataReaderFactory:可以获取到当前正在扫描的类的其他类信息(如父类和接口)
     * match方法返回false即不通过过滤规则true通过过滤规则
     */
	@Override
	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
			throws IOException {
		// TODO Auto-generated method stub
	     //获取当前类注解的信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        //获取当前正在扫描的类的类信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        //获取当前类资源(类的路径)
        Resource resource = metadataReader.getResource();
        String className = classMetadata.getClassName();
        if(className.contains("controller")){
            return true;
        }
        return false;
	}
}

在@ComponentScan注解中进行配置如下:

@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 {
}

经过上面的配置第一个@Filter通过FilterType.ASSIGNABLE_TYPE规定了只扫描Person类型的类第二个@Filter通过FilterType.CUSTOM自定义过滤规则规定了只扫描类名包含controller的类。结果:

在这里插入图片描述

关于@ComponentScan注解的一些细节

@ComponentScan注解可以扫描 任意 类 或者 注解 中内部类bean;

要想被扫描的前提是内部类标注了@Component及其相关衍生注解、内部类必须是static修饰否则扫描不到;如果是注解的内部类则只能是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"; //属性可以
    //内部类可以
    @Component
    @DependsOn("myBean.EventZ") //依赖事件bean的创建保证该bean在事件bean之后创建
        //细节:因为是内部类所以默认bean的id是类名首字母小写不是eventZ而是myBean.EventZ
    class EventSource {
        public EventSource(){
            System.out.println("事件源创建了...");
        }
    }
    @Component//("eventZ")
    public static class EventZ {
        public EventZ(){
            System.out.println("事件创建了...");
        }
    }
}

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


相关文章

猜您喜欢

网友评论

Copyright 2020 www.Shellfishsoft.com 【贝软下载站】 版权所有 软件发布

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 点此查看联系方式