Java 理论知识整理
过滤器
数据准备
-
DAO 层 UserDao、AccountDao、BookDao、EquipmentDao
public interface UserDao { public void save(); }
@Component("userDao") public class UserDaoImpl implements UserDao { public void save() { System.out.println("user dao running..."); } }
-
Service 业务层
public interface UserService { public void save(); }
@Service("userService") public class UserServiceImpl implements UserService { @Autowired private UserDao userDao;//...........BookDao等 public void save() { System.out.println("user service running..."); userDao.save(); } }
过滤器
名称:TypeFilter
类型:接口
作用:自定义类型过滤器
示例:
-
config / filter / MyTypeFilter
public class MyTypeFilter implements TypeFilter { @Override /** * metadataReader:读取到的当前正在扫描的类的信息 * metadataReaderFactory:可以获取到任何其他类的信息 */ //加载的类满足要求,匹配成功 public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { //获取当前类注解的信息 AnnotationMetadata am = metadataReader.getAnnotationMetadata(); //获取当前正在扫描的类的类信息 ClassMetadata classMetadata = metadataReader.getClassMetadata(); //获取当前类资源(类的路径) Resource resource = metadataReader.getResource(); //通过类的元数据获取类的名称 String className = classMetadata.getClassName(); //如果加载的类名满足过滤器要求,返回匹配成功 if(className.equals("service.impl.UserServiceImpl")){ //返回true表示匹配成功,返回false表示匹配失败。此处仅确认匹配结果,不会确认是排除还是加入,排除/加入由配置项决定,与此处无关 return true; } return false; } }
-
SpringConfig
@Configuration //设置排除bean,排除的规则是自定义规则(FilterType.CUSTOM),具体的规则定义为MyTypeFilter @ComponentScan( value = {"dao","service"}, excludeFilters = @ComponentScan.Filter( type= FilterType.CUSTOM, classes = MyTypeFilter.class ) ) public class SpringConfig { }
导入器
bean 只有通过配置才可以进入 Spring 容器,被 Spring 加载并控制
-
配置 bean 的方式如下:
- XML 文件中使用 标签配置
- 使用 @Component 及衍生注解配置
导入器可以快速高效导入大量 bean,替代 @Import({a.class,b.class}),无需在每个类上添加 @Bean
名称: ImportSelector
类型:接口
作用:自定义bean导入器
-
selector / MyImportSelector
public class MyImportSelector implements ImportSelector{ @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { // 1.编程形式加载一个类 // return new String[]{"dao.impl.BookDaoImpl"}; // 2.加载import.properties文件中的单个类名 // ResourceBundle bundle = ResourceBundle.getBundle("import"); // String className = bundle.getString("className"); // 3.加载import.properties文件中的多个类名 ResourceBundle bundle = ResourceBundle.getBundle("import"); String className = bundle.getString("className"); return className.split(","); } }
-
import.properties
#2.加载import.properties文件中的单个类名 #className=dao.impl.BookDaoImpl #3.加载import.properties文件中的多个类名 #className=dao.impl.BookDaoImpl,dao.impl.AccountDaoImpl #4.导入包中的所有类 path=dao.impl.*
-
SpringConfig
@Configuration @ComponentScan({"dao","service"}) @Import(MyImportSelector.class) public class SpringConfig { }
注册器
可以取代 ComponentScan 扫描器
名称:ImportBeanDefinitionRegistrar
类型:接口
作用:自定义 bean 定义注册器
-
registrar / MyImportBeanDefinitionRegistrar
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /** * AnnotationMetadata:当前类的注解信息 * BeanDefinitionRegistry:BeanDefinition注册类,把所有需要添加到容器中的bean调用registerBeanDefinition手工注册进来 */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { //自定义注册器 //1.开启类路径bean定义扫描器,需要参数bean定义注册器BeanDefinitionRegistry,需要制定是否使用默认类型过滤器 ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry,false); //2.添加包含性加载类型过滤器(可选,也可以设置为排除性加载类型过滤器) scanner.addIncludeFilter(new TypeFilter() { @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { //所有匹配全部成功,此处应该添加实际的业务判定条件 return true; } }); //设置扫描路径 scanner.addExcludeFilter(tf);//排除 scanner.scan("dao","service"); } }
-
SpringConfig
@Configuration @Import(MyImportBeanDefinitionRegistrar.class) public class SpringConfig { }
处理器
通过创建类继承相应的处理器的接口,重写后置处理的方法,来实现拦截 Bean 的生命周期来实现自己自定义的逻辑
BeanPostProcessor:bean 后置处理器,bean 创建对象初始化前后进行拦截工作的
BeanFactoryPostProcessor:beanFactory 的后置处理器
-
加载时机:在 BeanFactory 初始化之后调用,来定制和修改 BeanFactory 的内容;所有的 bean 定义已经保存加载到 beanFactory,但是 bean 的实例还未创建
-
执行流程:
-
ioc 容器创建对象
-
invokeBeanFactoryPostProcessors(beanFactory):执行 BeanFactoryPostProcessor
- 在 BeanFactory 中找到所有类型是 BeanFactoryPostProcessor 的组件,并执行它们的方法
- 在初始化创建其他组件前面执行
-
BeanDefinitionRegistryPostProcessor:
-
加载时机:在所有 bean 定义信息将要被加载,但是 bean 实例还未创建,优先于 BeanFactoryPostProcessor 执行;利用 BeanDefinitionRegistryPostProcessor 给容器中再额外添加一些组件
-
执行流程:
-
ioc 容器创建对象
-
refresh() → invokeBeanFactoryPostProcessors(beanFactory)
-
从容器中获取到所有的 BeanDefinitionRegistryPostProcessor 组件
- 依次触发所有的 postProcessBeanDefinitionRegistry() 方法
- 再来触发 postProcessBeanFactory() 方法
-
监听器
基本概述
ApplicationListener:监听容器中发布的事件,完成事件驱动模型开发
public interface ApplicationListener<E extends ApplicationEvent>
所以监听 ApplicationEvent 及其下面的子事件
应用监听器步骤:
-
写一个监听器(ApplicationListener实现类)来监听某个事件(ApplicationEvent及其子类)
-
把监听器加入到容器 @Component
-
只要容器中有相关事件的发布,就能监听到这个事件;
-
ContextRefreshedEvent:容器刷新完成(所有 bean 都完全创建)会发布这个事件
-
ContextClosedEvent:关闭容器会发布这个事件
-
-
发布一个事件:
applicationContext.publishEvent()
@Component
public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {
//当容器中发布此事件以后,方法触发
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("收到事件:" + event);
}
}
实现原理
ContextRefreshedEvent 事件:
-
容器初始化过程中执行
initApplicationEventMulticaster()
:初始化事件多播器- 先去容器中查询
id = applicationEventMulticaster
的组件,有直接返回 - 没有就执行
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory)
并且加入到容器中 - 以后在其他组件要派发事件,自动注入这个 applicationEventMulticaster
- 先去容器中查询
-
容器初始化过程执行 registerListeners() 注册监听器
- 从容器中获取所有监听器:
getBeanNamesForType(ApplicationListener.class, true, false)
- 将 listener 注册到 ApplicationEventMulticaster
- 从容器中获取所有监听器:
-
容器刷新完成:finishRefresh() → publishEvent(new ContextRefreshedEvent(this))
发布 ContextRefreshedEvent 事件:
-
获取事件的多播器(派发器):getApplicationEventMulticaster()
-
multicastEvent 派发事件
-
获取到所有的 ApplicationListener
-
遍历 ApplicationListener
- 如果有 Executor,可以使用 Executor 异步派发
Executor executor = getTaskExecutor()
- 没有就同步执行 listener 方法
invokeListener(listener, event)
,拿到 listener 回调 onApplicationEvent
- 如果有 Executor,可以使用 Executor 异步派发
-
-
容器关闭会发布 ContextClosedEvent
转载自:https://juejin.cn/post/7173654654205558820