@ComponentScan主要就是定义扫描的路径从中找出标识了需要装配的类自动装配到spring的bean容器中。@ComponentScan默认会装配标识了@Controller,@Service,@Repository,@Component注解的类到spring容器中。如果你指定了路径,Spring将会将在被指定的包及其子的包中寻找bean。如果没有指定路径Spring默认的在@ComponentScan注解所在的包及其子包中寻找bean。@ComponentScan注解相当于在配置文件中的 <context:component-scan>标签。
@ComponentScan注解
配置类:
import org.springframework.context.annotation.ComponentScan;
@ComponentScan
public class MyConfig {
}
测试类:
import io.mieux.config.BeanConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(MyConfig.class);
// 使用 ApplicationContext的getBeanDefinitionNames()方法获取已经注册到容器中的bean的名称。
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanName : beanDefinitionNames) {
System.out.println("beanName: " + beanName);
}
}
}
结果:
beanName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanName: org.springframework.context.annotation.internalRequiredAnnotationProcessor
beanName: org.springframework.context.annotation.internalCommonAnnotationProcessor
beanName: org.springframework.context.event.internalEventListenerProcessor
beanName: org.springframework.context.event.internalEventListenerFactory
beanName: myConfig
除了 spring 本身注册的一些 bean 之外,可以看到最后一行,已经将 MyConfig 这个类注册进容器中了。
属性 | 作用 |
---|---|
value | 用于指定包的路径,进行扫描 |
basePackages | 用于指定包的路径,进行扫描 |
basePackageClasses | 用于指定某个类的包的路径进行扫描 |
nameGenerator | bean的名称的生成器 |
useDefaultFilters | 是否开启对@Component,@Repository,@Service,@Controller的类进行检测 |
includeFilters | 包含的过滤条件(使用@Filter注解) |
excludeFilters | 排除的过滤条件,用法和includeFilters一样 |
添加多种扫描规则
1.如果使用的 jdk8,则可以直接添加多个 @ComponentScan 来添加多个扫描规则,但是在配置类中要加上 @Configuration 注解,否则无效。
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@ComponentScan(value = "com.czx.controller")
@ComponentScan(value = "com.czx.service")
@Configuration
public class MyConfig {
...
}
2.使用 @ComponentScans 来添加多个 @ComponentScan,从而实现添加多个扫描规则。同样,也需要加上 @Configuration 注解,否则无效。
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.context.annotation.Configuration;
@ComponentScans(value =
{@ComponentScan(value = "com.czx.controller"),
@ComponentScan(value = "com.czx.service")})
@Configuration
public class MyConfig {
}
@Filter注解
过滤器的扫描条件:
1,type=FilterType.ANNOTATION 按照注解的方式进行扫描.后面classes属性为注解的类型,如:
@Configuration//标记此类为配置类
@ComponentScan(value="com.wxj",excludeFilters= {
@Filter(type=FilterType.ANNOTATION,classes= {Controller.class})
})
public class MainConfig {
//将标有@Controller注解的类排除在外不会加载到容器中来
}
2,type=FilterType.ASSIGNABLE_TYPE,按照指定的类,进行过滤,后面的classes属性的值为"类名.class".如:
@Configuration//标记此类为配置类
@ComponentScan(value="com.wxj",
includeFilters= {
@Filter(type=FilterType.ASSIGNABLE_TYPE,classes= {BookService.class})
},useDefaultFilters=false)
public class MainConfig {
//只会加载BookService,以及BookService的子类或者其实现类
}
3,type=FilterType.CUSTOM,按照自己自定义的方式来进行过滤和筛选(使用此过滤类型,虽然比较繁琐,但是使用起来完全可以由自己来定义扫描的规则)
首先定义@Filter注解的类型:
@Configuration//标记此类为配置类
@ComponentScan(value="com.wxj",
includeFilters= {@Filter(type=FilterType.CUSTOM,classes{MyTypeFilter.class})
},useDefaultFilters=false)
public class MainConfig {
}
MyTypeFilter即为自己定义的匹配方法,其中MyTypeFilter类中的match方法的返回值为true时,为符合过滤条件,如果返回为false,则不符合过滤条件,代码如下:
public class MyTypeFilter implements TypeFilter {
/**
* MetadataReader metadataReader:获取当前正在扫描的类的信息
* MetadataReaderFactory metadataReaderFactory,获取带其他任何类的信息
*/
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();//获取当前类的注解信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();//获取当前扫描的类信息
Resource resource = metadataReader.getResource();//获取当前扫描的资源信息
String name = classMetadata.getClassName();//获取类的名字
if(name.contains("er")) {
return true;//如果类的名字中带有"er",则符合过滤的要求
}
return false;
}
}
注:TypeFilter中的ASPECTJ和REGEX(正则方式),没有介绍,使用较少,有兴趣可以自行研究.