注解概括
ComponentScan注解
该注解加注在配置类上,用于告诉Spring扫描哪些包,并把这些包中加注了@Controller
、@Service
、@Component
和@Repository
的类生成bean放入到容器中。
同时,还可以指定一些过滤器来过滤不扫描或者只扫描哪些包。
Filter和FilterType
在ComponentScan注解中有两个过滤器数组,名为includeFilters和excludeFilters,它们的都是Filter数组类型,Filter其中有一个属性叫做type,它的类型是FilterType枚举类,通过给它赋值,可以定义过滤器的性质;其中value(或classes)数组可以赋值一些注解让过滤器过滤。
FilterType的类型:
- ANNOTATION:注解,默认值。官方注释:Filter candidates marked with a given annotation.大概意思是被指定注解注的组件会被过滤器过滤。
- ASSIGNABLE_TYPE:类似diy,给定什么值就过滤什么值。官方注释:Filter candidates assignable to a given type.大概意思是过滤给定的条件。
- ASPECTJ:aspectJ表达式,不常用。官方注释:Filter candidates matching a given AspectJ type pattern expression.
- REGEX:正则表达式。官方注释:Filter candidates matching a given regex pattern.
- CUSTOM:自定义。官方注释:Filter candidates using a given custom org.springframework.core.type.filter.TypeFilter implementation.大概意思是自己定义的类型需要实现TypeFilter接口,然后覆写match方法进行匹配。
代码演示
演示组件扫描注解配合排除过滤器
项目代码沿用上个文章
增加以下四个类
同时在这四个类上加注概括中的注解
编写测试类
package cc.fireflyhut.study;
import cc.fireflyhut.study.config.MyConfig;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class IOCTest {
@Test
public void test01() {
// 获得注解配置容器类
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
// 获取容器中所有的BeanDefinition的名字
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
}
}
}
修改配置类
package cc.fireflyhut.study.config;
import cc.fireflyhut.study.dao.MyRepository;
import cc.fireflyhut.study.entity.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
@Configuration
/*
value值指定扫描cc.fireflyhut.study包
excludeFilters指定排除过滤器
*/
@ComponentScan(value = "cc.fireflyhut.study.*", excludeFilters = {
// 该过滤器指定为按注解过滤,过滤被Service注解的类和被Repository注解的类,加注两类注解的类将不再被扫描
@Filter(type = FilterType.ANNOTATION, classes = {Repository.class, Service.class})
})
public class MyConfig {
/**
* 向容器中注册一个id未user类型为User的Bean
* 该Bean的id默认为方法名(user)如果想指定id,需要在@Bean注解中传入value值指定id
*/
@Bean
public User user() {
return new User("admin", "123456");
}
/**
* 指定注册到容器中的bean的id为user111
*/
@Bean("user111")
public User user1() {
return new User("admin", "123456");
}
}
执行测试类测试方法打印结果
不难发现,容器中只有myController类和myComponent的单例bean了。
演示组件扫描注解配合只包括过滤器
当使用includeFilters过滤器时,需要关闭Spring默认开启的默认过滤器,只需将ComponentScan注解中的useDefaultFilters属性设置为false即可。
修改配置类
package cc.fireflyhut.study.config;
import cc.fireflyhut.study.dao.MyRepository;
import cc.fireflyhut.study.entity.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
@Configuration
/*
value值指定扫描cc.fireflyhut.study包
excludeFilters指定排除过滤器
*/
@ComponentScan(value = "cc.fireflyhut.study.*",
/// 注释掉排除过滤器
/*
excludeFilters = {
// 该过滤器指定为按注解过滤,过滤被Service注解的类和被Repository注解的类,加注两类注解的类将不再被扫描
@Filter(type = FilterType.ANNOTATION, classes = {Repository.class, Service.class})
},
*/
includeFilters = {
// 该过滤器指定为按注解过滤,指定被Service注解的类和被Repository注解的类,只有加注两类注解的类才能被扫描
@Filter(type = FilterType.ANNOTATION, classes = {Repository.class, Service.class})
},
useDefaultFilters = false)
public class MyConfig {
/**
* 向容器中注册一个id未user类型为User的Bean
* 该Bean的id默认为方法名(user)如果想指定id,需要在@Bean注解中传入value值指定id
*/
@Bean
public User user() {
return new User("admin", "123456");
}
/**
* 指定注册到容器中的bean的id为user111
*/
@Bean("user111")
public User user1() {
return new User("admin", "123456");
}
}
再次执行测试类测试方法
很容易发现容器中只有名为myRepository的bean和名为myService的bean了。
自定义TypeFilter
编写自定义的TypeFilter
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
import java.io.IOException;
/**
* 自定义TypeFilter
*/
public class MyTypeFilter implements TypeFilter {
/**
* 匹配方法
* @param metadataReader 当前被扫描的类信息
* @param metadataReaderFactory 任何其他的信息
* @return 匹配结果
* @throws IOException 抛出io异常
*/
@Override
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("My")) {
return true;
}
return false;
}
}
将其应用在ComponentScan注解中
import cc.fireflyhut.study.custom.MyTypeFilter;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
@Configuration
/*
value值指定扫描cc.fireflyhut.study包
excludeFilters指定排除过滤器
*/
@ComponentScan(value = "cc.fireflyhut.study.*",
includeFilters = {
// 通过自定义规则过滤
@Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})
},
useDefaultFilters = false)
public class MyConfig {
}
测试主类
public class MyTest {
public static void main(String[] args) {
// 获得注解配置容器类
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
// 从容器中获得所有指定类型的bean的名字即id
String[] beanNames = applicationContext.getBeanDefinitionNames();
// 遍历打印id
for (String beanName : beanNames) {
System.out.println(beanName);
}
}
}
结果:
预期是只要是类名包含“My”字符就放入容器。