栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

基于注解开发的Spring入门指南03

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

基于注解开发的Spring入门指南03

包的扫描操作
  • @ComponentScan注解的介绍
      • 该注解包含的参数
  • @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 nameGenerator() default BeanNameGenerator.class;

	Class scopeResolver() default AnnotationScopemetadataResolver.class;

	ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;

	String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;

	boolean useDefaultFilters() default true;

	Filter[] includeFilters() default {};

	Filter[] excludeFilters() default {};

	boolean lazyInit() default false;

	@Retention(RetentionPolicy.RUNTIME)
	@Target({})
	@interface Filter {

		FilterType type() default FilterType.ANNOTATION;

		@AliasFor("classes")
		Class[] value() default {};

		@AliasFor("value")
		Class[] classes() default {};

		String[] pattern() default {};

	}

}

我们挑出上面比较重要的几个参数来说明一下

  1. value:指定要扫描的包
  2. excludeFilters = Filter[]:指定要排除那些包
    1. type:根据什么来排除
      1. FilterType.ANNOTATION:根据注解排除
      2. FilterType.ASSIGNABLE_TYPE:根据类型排除
      3. FilterType.ASPECTJ:根据表达式排除
      4. FilterType.REGEX:根据正则表达式排除
      5. FilterType.CUSTOM:自定义排除规则
    2. classes:只需要写对应排除类型的class
  3. includeFilters = Filter[]:指定要包含那些包
    1. type:根据什么来包含
      1. FilterType.ANNOTATION:根据注解包含
      2. FilterType.ASSIGNABLE_TYPE:根据类型包含
      3. FilterType.ASPECTJ:根据表达式包含
      4. FilterType.REGEX:根据正则表达式包含
      5. FilterType.CUSTOM:自定义包含规则
    2. classes:只需要写对应包含类型的class
  4. useDefaultFilters:是否默认扫描所有包

以上就是该注解参数的详细描述

@ComponentScan注解的使用 使用范例 范例一

直接拿根据注解扫描对应包下的class的范例来演示

  1. 首先建立一个配置类
@Configuration
@ComponentScan(value = "com.ioc", includeFilters = {
        @Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})
},useDefaultFilters = false)
public class MainConfig02 {
}

分析一下上面配置类的注解@ComponentScan,我们可以看到value代表着我们要扫描的是com.ioc包下的类,同时从includeFilters 可以看出我们包含的规则是根据注解来扫描类的,对于根据哪些注解,我们可以冲classes中看到有以下两个注解:@Controller @Service.
最后我们把useDefaultFilters 设置为false不扫描所有包
然后为了让我们的配置类能够扫描到有指定注解的类,我们先建立两个分别带有@Controller @Service的类

  1. 建立能够被扫描到的类
package com.ioc.controller;

import org.springframework.stereotype.Controller;


@Controller
public class PersonController {
}
package com.ioc.service;

import org.springframework.stereotype.Service;


@Service
public class PersonService {
}

这两个类都带有注解,然后我们来测试以下是否能够扫描并注入这些class

  1. 编写测试类获取被扫描到的bean
public class Test02 {

    public static void main(String[] args) {
    	//获取容器
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig02.class);
        //输出容器中bean的名称
        for (String beanDefinitionName : annotationConfigApplicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
    }
}

运行之后得到的结果如下

可以看到后面两个就是我们需要注入的class了

范例二

同样的我们把配置类上面的注解稍作修改,用另一种方式来扫描class

  1. 编写配置类
@ComponentScan(value = "com.ioc", includeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = {MyFilterType.class})
},useDefaultFilters = false)
public class MainConfig02 {
}

可以看到我们把type改为了CUSTOM自定义的扫描规则,自定义的逻辑都写在MyFilterType这个类中.那么我们看看这个类需要怎样编写.

  1. 编写自定义过滤规则类
public class MyFilterType implements TypeFilter {

    
    @Override
    public boolean match(metadataReader metadataReader, metadataReaderFactory metadataReaderFactory) throws IOException {
        //获取当前扫描类的注解信息
        Annotationmetadata annotationmetadata = metadataReader.getAnnotationmetadata();
        //获取当前扫描类的类信息
        Classmetadata classmetadata = metadataReader.getClassmetadata();
        //获取当前类的资源信息(比如类路径)
        Resource resource = metadataReader.getResource();

        //如果是包含规则,那就把类名包含er的类全部全部扫描到位
        if(classmetadata.getClassName().contains("er")) {
            return true;
        }

        return false;
    }
}

以上的参数信息在注释中解释的很详细了,重点介绍下运行过程.首先扫描到的类都会经过这个match方法,根据我对源码的跟踪

可以看到上方的for循环获取到了扫描到的所有类资源进行遍历,为了证明Resource就是类的资源信息,我特地翻译了一下

然后循环调用isCandidateComponent方法,正是这个方法调用了match

这个方法分为排除的情况调用match方法和包含情况的调用match方法,传入对应的参数,然后我们重写这个方法,利用这两个参数可以获取类的信息,这样就可以判断该类是否可以被注入到容器中,可以看到match方法返回true时,当前的class就可以被注入到容器中,为false时则忽略,在我们自定义的过滤规则类中,我们获取了类的名称,并让类名中含有er的类被注入到容器中.

  1. 测试类
public class Test02 {

    public static void main(String[] args) {
    	//获取容器
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig02.class);
        //输出容器中bean的名称
        for (String beanDefinitionName : annotationConfigApplicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
    }
}

和上面的测试类还是一样,最后的输出结果是

可以看到所有带有er的类名都被注入到容器中去了

以上我就列举了根据注解的方式排除或者包含的扫描方式和自定义的方式排除或者包含的扫描,希望大家有一定的收获

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/434219.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号