前一篇文章我们讲到了spring IOC的注解式注入,有关于bean对象的注入,我们对比了xml注入和通过配置@Configuration 注解标注的配置类进行@bean 的注入。其中注解的方式为我们节省了大量的xml配置工作。但是有一个问题就是,我们如何实现构造器呢,如何进行包扫描呢,这是我们接下来需要探讨的问题。我们在这里先讨论包扫描的问题。包扫描是通过@ComponentScan 注解实现的。如何在扫描的同时,添加我们的过滤条件,这种过滤条件又有哪些实现方式呢?我们一起来看下
1,@ComponentScan 无过滤条件
1.1.1 新建一个配置类:
@ComponentScan("pierce.sustar.controller")
@Configuration
public class MainConfig {
}
1.1.2 新建一个组件对象:
@Controller
public class BookController {
}
1.1.3 先建一个主类,查看容器中已经装配的bean对象
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String[] names = applicationContext.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
1.1.4 输出结果:
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
mainConfigTest
bookService ##我们在容器中注入了这一个service
1.1.5 总结
@ComponentScan 注解类似我们在spring的配置文件中这样一个配置:
<context:component-scan base-package="pierce.sustar.controller"></context:component-scan>
2,@ComponentScan 有过滤条件
查看源码(部分):
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class) ## 说明这个注解同一个地方可以多次使用
public @interface ComponentScan {
@AliasFor("basePackages") ## 使用basePackages作为别名进行包路径的装载
String[] value() default {};
@AliasFor("value") ## 使用value进行多个包路径的装载
String[] basePackages() default {};
String resourcePattern() default "**/*.class";
boolean useDefaultFilters() default true; ## 使用默认的过滤器
ComponentScan.Filter[] includeFilters() default {}; ## 包含的过滤器
ComponentScan.Filter[] excludeFilters() default {}; ## 排除的过滤器
boolean lazyInit() default false;
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Filter { ## 包扫描可能使用的过滤器
FilterType type() default FilterType.ANNOTATION;
@AliasFor("classes")
Class<?>[] value() default {};
@AliasFor("value")
Class<?>[] classes() default {};
String[] pattern() default {};
}
}
2.1 排除某些包不扫描
2.1.1 新建一个配置类
@ComponentScan(value = "pierce.sustar.demo.bean",excludeFilters = {
@Filter(type=FilterType.,classes = {Controller.class, Service.class})
})
public class MainConfig {
//给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
@Bean("person")
public Person person01(){
return new Person("lisi", 20);
}
}
2.1.2 创建测试类
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
String[] names = context.getBeanDefinitionNames();
for (String name: names
) {
System.out.println(name);
}
}
2.1.3 测试结果
mainConfig
bookDao
person
工程结构如图:

2.2 扫描时只要某些组件
2.2.1 配置类:
@ComponentScan(value = "com.atguigu.demo.bean",includeFilters = {
@Filter(type=FilterType.ANNOTATION,classes = {Controller.class, Service.class})
},useDefaultFilters = false) ## 注意这里的useDefaultFilters = false 表示禁用默认的过滤器,否则不生效
public class MainConfig {
//给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
@Bean("person")
public Person person01(){
return new Person("lisi", 20);
}
}
2.3 @ComponentScans 多扫描包方式
2.3.1 配置类
//配置类==配置文件
@Configuration //告诉Spring这是一个配置类
@ComponentScans(
value = {
@ComponentScan(value="com.atguigu.demo.bean",includeFilters = {
@Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
)
},useDefaultFilters = false)
}
)
public class MainConfig {
@Bean("person")
public Person person01(){
return new Person("lisi", 20);
}
2.4 包扫描过滤方式之自定义过滤器
2.4.1 配置类
@Configuration //告诉Spring这是一个配置类
@ComponentScans(
value = {
@ComponentScan(value="com.atguigu.demo.bean",includeFilters = {
@Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
@Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class}) #注意过滤类型
},useDefaultFilters = false)
}
)
public class MainConfig {
@Bean("person")
public Person person01(){
return new Person("lisi", 20);
}
2.4.2 自定义过滤器
public class MyTypeFilter implements TypeFilter {
/**
* metadataReader:读取到的当前正在扫描的类的信息
* metadataReaderFactory:可以获取到其他任何类信息的
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
// TODO Auto-generated method stub
//获取当前类注解的信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//获取当前正在扫描的类的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前类资源(类的路径)
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println("--->"+className);
if(className.contains("er")){ ## 过滤器中表示类名包含er的即可作为有效过滤器
return true;
}
return false;
}
}
2.4.3 其他类型的过滤方式
//FilterType.ANNOTATION:按照注解
//FilterType.ASSIGNABLE_TYPE:按照给定的类型;
//FilterType.ASPECTJ:使用ASPECTJ表达式
//FilterType.REGEX:使用正则指定
//FilterType.CUSTOM:使用自定义规则