1. XML配置包扫描路径
在传统的Spring程序中,我们会在XML文件中配置包扫描路径,将扫描到的被@Controller ,@Serrvice,@Repository,@Component等注解注释的组件加入IOC容器中去。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 包扫描,只要标注了@Controller ,@Serrvice,@Repository,@Component 自动扫描加入容器中 -->
<context:component-scan base-package="com.baiding"/>
</beans>
使用JavaConfig方式配置的话,我们可以用@ComponentScan注解替换上述XML配置。
2. @ComponentScan的使用
@ComponentScan:在容器中注册组件的第二种方式,包扫描加上给组件标注注解—@Controller、@Service、@Component等
@ComponentScan有几个属性,其中value指定扫描的包路径,includeFilters指定扫描哪些组件,excludeFilters指定不扫描哪些组件,useDefaultFilters默认的过滤规则是开启的,若要使用includeFilters,则要将useDefaultFilters的值置为false。
配置类:
@Configuration
@ComponentScan(value = "com.baiding")
public class BeanConfig {
/**
* 给容器中注册一个bean 类型为返回值的类型 id默认为方法名或者直接用属性name配置id
* @return
*/
@Bean(name = "wangwu")
public Person person(){
return new Person("wangwu",22);
}
}
测试类:
@Test
void test03(){
ApplicationContext ac = new AnnotationConfigApplicationContext(BeanConfig.class);
// 得到所有Bean的name
String[] names = ac.getBeanDefinitionNames();
for(String name :names){
System.out.println(name);
}
}
结果:
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
beanConfig
personController
personDAO
personService
wangwu
结果上面的是IOC容器自己要装配的组件,下面的就是配置的扫描路径下扫出来的bean.
3. 指定扫描过滤规则
3.1 @excludeFilters
当使用excludeFilters指定不扫描哪些内容的时候,我们需要用到@Filter注解,这是一个位于@ComponentScan注解内部的一个注解,用来配置过滤规则。@Filter有一个type属性,它的值是一个枚举值,用来说明过滤的方式 — 按照什么规则进行过滤。
FilterType.ANNOTATION:按照注解
FilterType.ASSIGNABLE_TYPE:按照给定的类型
FilterType.ASPECTJ:使用ASPECTJ表达式
FilterType.REGEX:使用正则指定
FilterType.CUSTOM:使用自定义规则
例如:我们需要过滤所有的使用Controller注解和Service注解的类,采用FilterType.ANNOTATION过滤
@Configuration
@ComponentScan(value = "com.baiding",
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class})
}
)
public class BeanConfig {
/**
* 给容器中注册一个bean 类型为返回值的类型 id默认为方法名或者直接用属性name配置id
* @return
*/
@Bean(name = "wangwu")
public Person person(){
return new Person("wangwu",22);
}
}
结果:
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
beanConfig
personDAO
wangwu
3.2 @includeFilters
includeFilters指定扫描的时候只需要包含哪些组件,它的使用方式和excludeFilters基本一样,只是在使用includeFilters时,我们需要关闭默认的扫描规则,即将useDefaultFilters的值置为false.
例子:使用FilterType.ANNOTATION规则制定只扫描@Controller注解的组件,
使用FilterType.ASSIGNABLE_TYPE按照给定的类型去扫描注册组件(这时候不需要给定的类型有任何注解注释都会被注册到容器中)。
@Configuration
@ComponentScan(value = "com.baiding",
includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class}),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,
classes = {PersonService.class})
},
useDefaultFilters = false
)
public class BeanConfig {
/**
* 给容器中注册一个bean 类型为返回值的类型 id默认为方法名或者直接用属性name配置id
* @return
*/
@Bean(name = "wangwu")
public Person person(){
return new Person("wangwu",22);
}
}
结果:
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
beanConfig
personController
personService
wangwu
其中 personDAO组件都没有被扫描注册到IOC容器中去。
3.3 自定义过滤规则
FilterType枚举有一个值为FilterType.CUSTOM ,它表示以自定义的规则进行组件的扫描。首先你要定义一个实现TypeFilter接口的类,在其中实现过滤规则的匹配。
实现类:
public class ServiceFilterType implements TypeFilter {
/**
* @param metadataReader
* 读取到当前正在扫描的类的信息
* @param metadataReaderFactory
* 能够获取到其他任何类的信息
* @return
* 返回true的话,说明匹配成功
* @throws IOException
*/
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
// 获取当前类注解的信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// 获取当前正在扫描的类的信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 获取当前类资源(类的路径)
Resource resource = metadataReader.getResource();
//获取当前扫描类的完整类名 com.baiding.filter.ServiceFilterType
String className = classMetadata.getClassName();
return className.contains("PersonService");
}
}
配置类:
@Configuration
@ComponentScan(value = "com.baiding",
includeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM,
classes = {ServiceFilterType.class})
},
useDefaultFilters = false
)
public class BeanConfig {
/**
* 给容器中注册一个bean 类型为返回值的类型 id默认为方法名或者直接用属性name配置id
* @return
*/
@Bean(name = "wangwu")
public Person person(){
return new Person("wangwu",22);
}
}
结果:
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
beanConfig
personService
wangwu
结果中只扫描到了personService这一个组件