Java 理论知识整理

1,497 阅读5分钟

过滤器

数据准备
  • 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

容器关闭会发布 ContextClosedEvent

本文正在参加「金石计划 . 瓜分6万现金大奖」