持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情
1. TypeFilter 类
这个类是一个注解类,包含 注解, 正则表达式 用户自定义等等过滤规则
public enum FilterType {
ANNOTATION,
ASSIGNABLE_TYPE,
ASPECTJ,
REGEX,
CUSTOM
}
在 @Filter 指定过滤规则,其中 type 来表示过滤的类型
FilterType.ASSIGNABLE_TYPE 表示按照给定的类型进行包含或者排除
@ComponentScan(value = {"com.shanggushenlong"},
includeFilters = {
@Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {BookService.class})
}))
- 表示 当 BookService 是一个java类的时候,该类及其子类都会被加载到 spring 容器中
- 表示 当 BookService 是一个接口的时候,其子接口及其实现类都会被加载到 spring 容器中
FilterType.CUSTOM:按照自定义规则进行包含或者排除
如果实现自定义规则进行过滤时,自定义规则的类必须是实现 org.springframework.core.type.filter.TypeFilter 接口的类
2. 用户自定义过滤类
自定义规则进行过滤的时候,首先创建 MyFilterType 实现 TypeFilter 接口,重写 match 匹配方法
public class MyTypeFilter implements TypeFilter {
// 使用 @ComponentScan 注解,type = FilterType.ASSIGNABLE_TYPE 用户自定义规则过滤
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
return false;
}
}
MetadataReader:对一个类的各种元数据都封装成一个 MetadataReader 对象
/**
* Factory interface for MetadataReader instances.
* Allows for caching a MetadataReader per original resource.
*/
public interface MetadataReaderFactory { }
MetadataReaderFactory:上面注释的意思是 MetadataReaderFactory 是 MetadataReader 的 instance 实例工厂
自定义实现过滤规则,match() 方法规则匹配,返回 true 表示符合规则,会被 spring 扫描包含在容器中;返回 false,表示不匹配,则不会被包含
3. 创建 MyTypeFilter 自定义过滤类
@ComponentScan(value = {"com.shanggushenlong"} ,
includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM,
classes = {MyTypeFilter.class})} ,
useDefaultFilters = false)
@Configuration
public class MainBeanConfig {
@Bean(value = {"person01"})
public Person person() {
return new Person("张三", 28);
}
}
现在设置 type = FilterType.CUSTOM 用户自定义,classes 指向自定义创建的类,记住要设置 useDefaultFilters = false
由于 match() 返回值为 false, 表示所有的都不匹配,所以可以看到没有任何 controller service dao 等被扫描出来
现在设置一个自己规则
比如设置 含有 er 字符串的,会被扫描到
public class MyTypeFilter implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
// 获取当前类注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// 获取当前正在扫描类的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 获取类名
String className = classMetadata.getClassName();
// 设置一个规则,如果类名中含有 er ,则将被 spring 扫描进容器中
if (className.contains("er")) {
System.out.println("className = " + className);
return true;
}
return false;
}
}
由于 controller 与 service 都含有 er ,所以此处都能被扫描
4 单实例 组件作用域
1、 spring 容器中的组件默认是单实例,在 spring 容器启动的时候就会去初始化这些对象,并不是等需要的时候再去初始化这些对象
2、 spring 默认是单实例对象,那么默认情况下,每次从容器中获取对象的时候,都不再重新创建,都是同一个对象
3、如果通过 xml 配置文件来配置 组件的作用域 可以在 <bean> 标签设置 scope 属性
<bean id="person" class="com.shanggushenlong.bean.Person" scope="prototype">
4、在 ConfigurableBeanFactory 中值: singleton 单实例 prototype 多实例
- 如果单实例:那么 spring 容器创建的时候,就会将 @Scope 注解标注为 singleton 组件进行了实例化,并加载到了 spring 容器中
5. 多实例
public class MainBeanConfig {
@Scope("prototype")
@Bean(value = {"person01"})
public Person person() {
return new Person("张三", 28);
}
}
使用 @Scope 注解设置为 prototype 多实例的时候:
- 当向 spring 容器获取 person 实例对象的时候,spring 容器才会实例化 person 对象,并且再加载到 spring 容器中去
- 当设置为多实例的时候,每次向spring容器获取对象的时候,都会创建一个新的对象
6. @Lazy 懒加载
spring 在启动时,默认会将单实例 bean 进行实例化,并加载到 spring 容器;如果想要对某个 bean 进行延迟记载,使用 @Lazy 注解
懒加载就是 spring 在启动的时候,先不创建对象,在第一次使用获取bean的时候再来创建对象,并进行初始化;注意:依旧是单实例,有点类似于 按需加载 ,但是不会重复创建