在使用Spring框架开发应用的过程当中,你们都知道使用Spring开发应用程序,咱们应用程序中大多数的Bean都是经过Spring的IOC容器来管理。将Bean注入到Spring IOC容器中的方式多种多样,如经过传统的XML方式注入,经过注解的方式注入等。本文咱们就来详细的探索一下在使用注解配置的方式注入Bean时,@ComponentScan注解组件扫描的应用。正则表达式
顾名思义,@ComponentScan注解提供给咱们的功能就是自动组件扫描,将指定包下的被@Repository、@Service、@Controller、@RestController、@Component、@Configuration注解所标注的Bean自动扫描注入到Spring IOC容器中,由Spring IOC容器统一管理这些Bean。
注解中的属性项:spring
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.5.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies>
在com.training.componentscan包下咱们分别建立component、controller、repository、service、config、filter包。app
在component包中建立SoftWareComponent类,加@Component注解:框架
@Component public class SoftWareComponent { //... ... }
在controller包中建立SoftWareController类,加@Controller注解:单元测试
@Controller public class SoftWareController { //... ... }
在repository包中建立SoftWareRepository类,加@Repository注解:测试
@Repository public class SoftWareRepository { //... ... }
在service包中建立SoftWareService类,加@Service注解:spa
@Service public class SoftWareService { //... ... }
在config包中建立ComponentScanConfig类,写入以下内容:.net
@Configuration //告诉Spring这是一个配置类 @ComponentScan(basePackages = "com.training.componentscan") //扫描com.training.componentscan包及其子包中被@Repository、@Service、@Controller、@RestController、@Component、@Configuration注解所标注的Bean public class ComponentScanConfig { //... ... }
咱们建立一个单元测试类IOCTest,用来测试看有哪些组件被注入到了Spring IOC容器中。code
public class IOCTest { @Test public void test() { AnnotationConfigApplicationContext application = new AnnotationConfigApplicationContext(ComponentScanConfig.class); String[] names = application.getBeanDefinitionNames(); for (String name : names) { System.out.println(name); } } }
执行单元测试咱们获得以下结果:component
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
componentScanConfig
softWareComponent
softWareController
softWareRepository
softWareService
从执行结果咱们能够看到,容器启动后,咱们全部加了@Repository、@Service、@Controller、@Component、@Configuration注解的Bean都被注入到了Spring IOC容器中。
在上面的例子中,在使用组件扫描时,若是咱们想过滤某些Bean,不但愿全部加了@Repository、@Service、@Controller、@RestController、@Component、@Configuration这些注解的Bean都被注入到Spring IOC中,咱们该怎么处理呢?
@ComponentScan注解有一个excludeFilters属性,经过给该属性设置对应的值能够过滤掉指定条件的Bean自动注入到Spring IOC容器中,可过滤的类型咱们在上文中已经说明,这里再也不赘述。
使用注解方式过滤指定注解的Bean很简单,咱们修改配置类ComponentScanConfig以下,过滤掉@Controller注解的Bean自动注入Spring IOC容器中。
@Configuration //告诉Spring这是一个配置类 @ComponentScan(basePackages = "com.training.componentscan",excludeFilters={ @Filter(type=FilterType.ANNOTATION,classes={Controller.class}) }) //扫描com.training.componentscan包及其子包中被@Repository、@Service、@Controller、@RestController、@Component、@Configuration注解所标注的Bean public class ComponentScanConfig { }
执行单元测试咱们能够获得以下结果:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
componentScanConfig
softWareComponent
softWareRepository
softWareService
从执行结果咱们能够看到,容器启动后,被@Controller注解的Bean被过滤掉了。
使用给定类型的方式过滤,即过滤指定的Bean,咱们修改配置类ComponentScanConfig以下,过滤掉SoftWareRepository这个Bean。
@Configuration //告诉Spring这是一个配置类 @ComponentScan(basePackages = "com.training.componentscan",excludeFilters={ @Filter(type=FilterType.ANNOTATION,classes={Controller.class}), @Filter(type=FilterType.ASSIGNABLE_TYPE,classes={SoftWareRepository.class}) }) //扫描com.training.componentscan包及其子包中被@Repository、@Service、@Controller、@RestController、@Component、@Configuration注解所标注的Bean public class ComponentScanConfig { }
执行单元测试咱们能够获得以下结果:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
componentScanConfig
softWareComponent
softWareService
从执行结果咱们能够看到,容器启动后,SoftWareRepository这个Bean被过滤掉了。
使用ASPECTJ表达式的方式过滤Bean,首先咱们须要加入切面aspectj的依赖。
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.2</version> </dependency>
咱们使用ASPECTJ表达式的方式过滤掉以Component结尾的Bean,修改ComponentScanConfig以下:
@Configuration //告诉Spring这是一个配置类 @ComponentScan(basePackages = "com.training.componentscan",excludeFilters={ @Filter(type=FilterType.ANNOTATION,classes={Controller.class}), @Filter(type=FilterType.ASSIGNABLE_TYPE,classes={SoftWareRepository.class}), @Filter(type=FilterType.ASPECTJ,pattern={"com.training.componentscan..*Component"}) }) //扫描com.training.componentscan包及其子包中被@Repository、@Service、@Controller、@RestController、@Component、@Configuration注解所标注的Bean public class ComponentScanConfig { }
执行单元测试,咱们获得以下结果:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
componentScanConfig
softWareService
从执行结果咱们能够看到,容器启动后,以Component结尾的SoftWareComponent这个Bean被过滤掉了。
咱们使用正则表达式的方式过滤掉以Service结尾的Bean,修改ComponentScanConfig以下:
@Configuration //告诉Spring这是一个配置类 @ComponentScan(basePackages = "com.training.componentscan",excludeFilters={ @Filter(type=FilterType.ANNOTATION,classes={Controller.class}), @Filter(type=FilterType.ASSIGNABLE_TYPE,classes={SoftWareRepository.class}), @Filter(type=FilterType.ASPECTJ,pattern={"com.training.componentscan..*Component"}), @Filter(type=FilterType.REGEX,pattern=".*Service") }) //扫描com.training.componentscan包及其子包中被@Repository、@Service、@Controller、@RestController、@Component、@Configuration注解所标注的Bean public class ComponentScanConfig { }
执行单元测试,获得以下结果:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
componentScanConfig
从执行结果咱们能够看到,容器启动后,以Service结尾的SoftWareService这个Bean被过滤掉了。
咱们使用自定义过滤器过滤类名中不含有"Co"的Bean。
自定义过滤器要实现org.springframework.core.type.filter.TypeFilter接口,定义本身的过滤器ComponentFilter实现TypeFilter接口以下:
public class ComponentFilter implements TypeFilter { /** * metadataReader:读取到的当前正在扫描的类的信息 metadataReaderFactory:能够获取到其余任何类信息 */ public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { // 获取当前类注解的信息 AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); // 获取当前正在扫描的类的类信息 ClassMetadata classMetadata = metadataReader.getClassMetadata(); // 获取当前类资源(类的路径) Resource resource = metadataReader.getResource(); String className = classMetadata.getClassName(); System.out.println("---->>>>>"+className); if(!className.contains("Co")){ return true; } return false; } }
修改ComponentScanConfig以下:
@Configuration //告诉Spring这是一个配置类 @ComponentScan(basePackages = "com.training.componentscan",excludeFilters={ @Filter(type=FilterType.CUSTOM,classes={ComponentFilter.class}) }) //扫描com.training.componentscan包及其子包中被@Repository、@Service、@Controller、@RestController、@Component、@Configuration注解所标注的Bean public class ComponentScanConfig { }
执行单元测试咱们获得以下结果:
---->>>>>com.training.componentscan.IOCTest ---->>>>>com.training.componentscan.IOCTest1 ---->>>>>com.training.componentscan.component.SoftWareComponent ---->>>>>com.training.componentscan.controller.SoftWareController ---->>>>>com.training.componentscan.filter.ComponentFilter ---->>>>>com.training.componentscan.repository.SoftWareRepository ---->>>>>com.training.componentscan.service.SoftWareService org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory componentScanConfig softWareComponent softWareController
从执行结果可知,全部没有包含“Co”的Bean已经被所有过滤,只有类名包含"Co"的Bean注入到了Spring IOC容器中。
只包含includeFilters属性的使用与excludeFilters属性的使用基本一致,这里再也不赘述。
小结:
本文咱们经过注解的方式讲述了@ComponentScan的应用,以及经过实例演示的方式向你们展现了自动扫描注入时如何经过不一样方式排除、包含知足指定条件的Bean,但愿你们共勉。