Spring注解02 您所在的位置:网站首页 componentscan默认扫描 Spring注解02

Spring注解02

2023-09-17 05:22| 来源: 网络整理| 查看: 265

该系列文章主要学习 雷丰阳老师的《Spring注解驱动》课程总结。 原课程地址:课程地址

包括了自己阅读其他书籍《Spring揭秘》《Spring Boot 实战》等课程。该系列文档会不断的完善,欢迎大家留言及提意见。

文章目录 1. 增加包扫描注解2. 高级过滤规则1. excludeFilters 使用1. includeFilters 使用 3. 各种类型过滤总结

以前可以通过xml来控制包扫描的范围,如今如果只是利用注解,如何合理的控制包扫描的范围呢?

注意:凡是在指定的包或其子包中的类上标注了@Repository、@Service、@Controller、@Component注解的类都会被扫描到,并将这个类注入到Spring容器中。其他的比如 @Configuration、@Bean是不受影响的。

定义两个演示的类,分别标注有 @Repository、@Service,其余的注解跟该方法类似

@Repository public class BookDao { } @Service public class BookService { }

还是继续利用之前定义的配置类

@Configuration(value = "mainConfig") public class MainConfig { // @Bean注解是给IOC容器中注册一个bean,类型自然就是返回值的类型,id默认是用方法名作为id @Primary @Bean(value = "child") public Person personChild() { return new Person("张三", 20); } @Bean(value = "adult") public Person personAdult() { return new Person("蜡笔小新", 20); } }

在不加包扫描的前提下查看容器中所有的组件信息

public class TestMain { public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); printAllBean(applicationContext); } private static void printAllBean(ApplicationContext applicationContext) { System.out.println("=====所有的Bean对象====="); String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames(); for (String s : beanDefinitionNames) { System.out.println(s); } } }

查看现有组件列表

=====所有的Bean对象===== org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalRequiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory mainConfig bookDao bookService child adult 1. 增加包扫描注解

在 MainConfig 类上增加包扫描注解信息,只想扫描 com.hone.learn.dao 路径下的组件

@Configuration(value = "mainConfig") @ComponentScan(value = "com.hone.learn.dao") public class MainConfig { // @Bean注解是给IOC容器中注册一个bean,类型自然就是返回值的类型,id默认是用方法名作为id @Primary @Bean(value = "child") public Person personChild() { return new Person("张三", 20); } @Bean(value = "adult") public Person personAdult() { return new Person("蜡笔小新", 20); } }

查看输出结果发现 bookService 已经不输出了

=====所有的Bean对象===== org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalRequiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory mainConfig bookDao child adult 2. 高级过滤规则

可以指定只包含或者排除某些条件

Filter[] includeFilters() default {}; Filter[] excludeFilters() default {};

两个方法的返回值都是Filter[]数组,在ComponentScan注解类的内部存在Filter注解类,大家可以看下上面的代码。

1. excludeFilters 使用

现在有这样一个需求,除了@Controller和@Service标注的组件之外,IOC容器中剩下的组件我都要,即相当于是我要排除@Controller和@Service这俩注解标注的组件。要想达到这样一个目的,我们可以在MainConfig类上通过@ComponentScan注解的excludeFilters()方法实现。例如,我们在MainConfig类上添加了如下的注解。

@Configuration(value = "mainConfig") @ComponentScan(value = "com.hone.learn", excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Repository.class})}) public class MainConfig {

最后 扫描容器中所有的组件,发现已经不包括 bookDao 了,已经根据规则合理的排除了。

=====所有的Bean对象===== //省略自带的bean输出结果 mainConfig bookService child adult 1. includeFilters 使用

当我们使用includeFilters()方法来指定只包含哪些注解标注的类时,需要禁用掉默认的过滤规则,如果只想扫描备注有 @Repository 的组件。

/** * 只想获取 Repository 组件 */ @ComponentScan(value = "com.hone.learn", includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Repository.class}) }, useDefaultFilters = false) @Configuration(value = "mainConfig") public class MainConfig {

在输出的结果中,只包含了@Repository注解标注的组件名称,并没有输出@Service注解标注的组件名称。

=====所有的Bean对象===== // 省略Spring自带的组件 mainConfig bookDao child adult 3. 各种类型过滤

上面只是使用了 FilterType.ANNOTATION ,根据名称知道这个肯定是根据注解名称来判断的。但是Spring本身提供了多种方式

分别有

ANNOTATION:按照是否注解名称来判断ASSIGNABLE_TYPE:按照给定的类型是否是指定类型的类或者子类进行包含或者排除ASPECTJ:按照ASPECTJ表达式进行包含或者排除REGEX:按照正则表达式进行包含或者排除CUSTOM:按照自定义规则进行包含或者排除

前四种的使用方式基本上跟 第一种按照注解的方式类似,使用上没有什么区别。值得说明的是第五种自定义的类型。

该匹配规则只是定义了一个抽象的方法,如果用户需要自定义,可以实现该方法。

比如这里我定义一个属于自己的过滤规则器

当我们实现TypeFilter接口时,需要实现该接口中的match()方法,match()方法的返回值为boolean类型。当返回true时,表示符合规则,会包含在Spring容器中;当返回false时,表示不符合规则,那就是一个都不匹配,自然就都不会被包含在Spring容器中。另外,在match()方法中存在两个参数,分别为MetadataReader类型的参数和MetadataReaderFactory类型的参数,含义分别如下。

metadataReader:读取到的当前正在扫描的类的信息metadataReaderFactory:可以获取到其他任何类的信息的工厂

比如我下面实现一个自定义的 filter,规则是:只有类名包含 “Dao” 才注入到容器中

public class SelfTypeFilter implements TypeFilter { @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { ClassMetadata classMetadata = metadataReader.getClassMetadata(); String className = classMetadata.getClassName(); if (className.contains("Dao")) { return true; } return false; } }

然后定义配置类

@ComponentScan(value = "com.hone.learn", includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {SelfTypeFilter.class}) }, useDefaultFilters = false) @Configuration(value = "mainConfig") public class MainConfig { // @Bean注解是给IOC容器中注册一个bean,类型自然就是返回值的类型,id默认是用方法名作为id @Primary @Bean(value = "child") public Person personChild() { return new Person("张三", 20); } @Bean(value = "adult") public Person personAdult() { return new Person("蜡笔小新", 20); } }

最后还是利用测试类,输出所有的 组件

public class TestMain { public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); printAllBean(applicationContext); } private static void printAllBean(ApplicationContext applicationContext) { System.out.println("=====所有的Bean对象====="); String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames(); for (String s : beanDefinitionNames) { System.out.println(s); } } }

通过输出结果可以发现,BookService 已经不包括在内部了

=====所有的Bean对象===== // 忽略自带组件 mainConfig bookDao child adult 总结

我们可以使用 @ComponentScan 注解来指定 Spring 扫描哪些包,可以使用 excludeFilters() 方法来指定扫描时排除哪些组件;也可以使用 includeFilters() 方法来指定扫描时只包含哪些组件。

当使用includeFilters()方法指定只包含哪些组件时,需要禁用掉默认的过滤规则。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有