Spring注解驱动开发 第二节包扫描等相关功能
Spring注解驱动开发 第二节包扫描等相关功能
在配置类中写入如**解就可以把指定包下的类注入到Spring。
@Configuration
@ComponentScan("com.meng")
public class MainConfig {
@Bean("person")
public Person person(){
return new Person("张三","23");
}
}
@Configuration注解上一节中说明了,表示这是一个注解类,@ComponentScan注解就表示将com.meng包下的所有标注@Controller,@Service,@Repository等注解的类全部注入到Spring容器中。
@Controller
public class BookController {}
@Service
public class BookService {}
@Repository
public class BookDao {}
打印结果:
四月 22, 2019 11:29:33 上午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2f410acf: startup date [Mon Apr 22 11:29:33 GMT+08:00 2019]; root of context hierarchy
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
bookController
bookDao
bookService
person
Process finished with exit code 0
可以看出上面一些springframework的都是在启动spring容器时spring自己注入的组件,看其他的mainConfig、bookController、bookDao、bookSerivce、person都是我们自己注入到Spring容器中的组件。
spring在指定在扫描包时还可以指定排除哪些类注入到spring容器中,代码如下
@ComponentScan(value = "com.meng",excludeFilters = {
@ComponentScan.Filter(
type = FilterType.ANNOTATION,classes = {
Controller.class,Service.class
}
)
上边这段代码在配置类中,表示扫描的包范围在com.meng中,排除过滤器指定的类型是注解类型,整理一下,Filter下type指定过滤类型为注解类型,classes属性可以传入数组,它表示要过滤组件的具体类型,上面过滤的是控制器类型与服务类型。
@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 {};
}
从源码中可以看出classes属性时可以传入数组的。上面就是排除哪些类注入到Spring容器。同时也可以用只包含哪些类注入spring容器。
只包含哪些类注入spring容器的方式
@Configuration
@ComponentScan(value = "com.meng",//excludeFilters = {
// @ComponentScan.Filter(
// type = FilterType.ANNOTATION,classes = {
// Controller.class,Service.class
// }
// )
includeFilters = {
@ComponentScan.Filter(
type = FilterType.ANNOTATION,classes={Controller.class}
)
},useDefaultFilters = false
)
public class MainConfig {
@Bean("person")
public Person person(){
return new Person("张三","23");
}
}
从上图可以看出,excludeFilters是排除,而includeFilters是只包含的意思。所以上图的意思是过滤类型是注解类型,具体的注解是只包含控制器的类型,但需要特别注意的是(注意!注意!注意!)重要的事情说三遍,一定要加useDefaultFilters,他表示spring容器注入的默认规则,spring容器注入的默认规则是true,要改成false,刚才的只包含过滤器才能生效。
打印结果:
四月 22, 2019 1:49:28 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2f410acf: startup date [Mon Apr 22 13:49:28 GMT+08:00 2019]; root of context hierarchy
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
bookController
person
Process finished with exit code 0
从上图中可以看出,只有bookController被注入到spring容器中。
配置多个@ComponentScan
如果配置多个的话就要用到ComponentScans,它可以配置多个ComponentScan
@Configuration
@ComponentScan(value = "com.meng",//excludeFilters = {
// @ComponentScan.Filter(
// type = FilterType.ANNOTATION,classes = {
// Controller.class,Service.class
// }
// )
includeFilters = {
@ComponentScan.Filter(
type = FilterType.ANNOTATION,classes={Controller.class}
)
},useDefaultFilters = false
)
@ComponentScans(
value={
@ComponentScan(value = "com.meng",
excludeFilters = {
@ComponentScan.Filter(
type = FilterType.ANNOTATION,classes={Controller.class}
)
},useDefaultFilters = false
),
@ComponentScan(value = "com.meng",
excludeFilters = {
@ComponentScan.Filter(
type = FilterType.ANNOTATION,classes={Controller.class}
)
},useDefaultFilters = false
)
}
)
public class MainConfig {
@Bean("person")
public Person person(){
return new Person("张三","23");
}
}
其中,@ComponentScans有一个value属性,可以接收一个数组,这个数组中就可以有多个@CompanentScan注解。
注解注入spring容器过滤规则
/**
* 过滤规则
* FilterType.ANNOTATION 按注解类型过滤
* FilterType.ASSIGNABLE_TYPE 按实际的类类型进行过滤
* FilterType.REGEX 按正则表达式进行过滤
* FilterType.ASPECTJ 按ASPECTJ进行过滤
* FilterType.CUSTOM 自定义过滤
*/
includeFilters = {
@ComponentScan.Filter(
type = FilterType.CUSTOM,classes={MyTypeFilter.class}
),
},useDefaultFilters = false
上面的代码列出了注解方式的全部注入规则,由于注解过滤规则我们已经测试过,所以不再进行测试,现在实验一下按实际类型过滤,在配置类中改成如下代码
includeFilters = {
@ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,classes={BookService.class}
),
},useDefaultFilters = false
我们把过滤规则改为按实际类型过滤,classes上写入实际的类型,查看打印结果:
org.springframework.context.event.internalEventListenerFactory
mainConfig
bookService
person
Process finished with exit code 0
可以看到bookService被注入到spring容器中。再次测试一下自定义注入容器。
自定义注入spring容器
public class MyTypeFilter implements TypeFilter {
//metadataReader 可以获取到当前扫描的这个类的信息
//metadataReaderFactory 可以获取其他的所有类信息
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//获取当前注解的所有信息
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
//获取当前类的所有信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前类路径
Resource resource = metadataReader.getResource();
//System.out.println("当前的类路径为:"+resource.getURL());
return false;
}
}
要实现自定义容器注入,要实现一个spring的接口,TypeFilter,实现方法match,其中有两个参数MetadataReader ,MetadataReaderFactory ,第一个表示正在扫描的类信息,第二个表示其他全部的类信息。方法的返回值是布尔类型,根据自己的规则,返回true表示注入到spring容器,false表示不注入到spring容器。我们进行如下规则的定义,注入容器。
public class MyTypeFilter implements TypeFilter {
//metadataReader 可以获取到当前扫描的这个类的信息
//metadataReaderFactory 可以获取其他的所有类信息
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//获取当前注解的所有信息
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
//获取当前类的所有信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前类路径
Resource resource = metadataReader.getResource();
//System.out.println("当前的类路径为:"+resource.getURL());
if(classMetadata.getClassName().contains("er")){
return true;
}
return false;
}
}
表示当前扫描的类名称如果包含er,就注入到spring容器,
includeFilters = {
@ComponentScan.Filter(
type = FilterType.CUSTOM,classes={MyTypeFilter.class}
),
},useDefaultFilters = false
改为自定义规则过滤,classes传入自定义的过滤规则类。查看打印结果:
mainConfig
bookController
myTypeFilter
person
bookService
Process finished with exit code 0
由此结果得知,类名包含er的全部被注入进来,由于bookDao没有er,所以没有被注入。
上一篇: Maven开发中使用注解替换映射文件
下一篇: springmvc接口支持跨域请求