Spring之容器初始化refresh()

一、前置知识

1 后置处理器 - PostProcessor

  • PostProcessor本身也是一种需要注册到容器里的Bean
    • 其里面的方法会在特定的实际被容器调用
    • 它能实现在不改变容器或者Bean核心逻辑的情况下对Bean进行扩展
    • 例如:对Bean进行包装,影响其行为、修改Bean的内容甚至替换掉整个Bean等

PostProcessor的种类

  • BeanDefinitionRegistryPostProcessor
  • BeanFactoryPostProcessor
  • BeanPostProcessor
1.1 BeanDefinitionRegistryPostProcessor
  • BeanDefinitionRegistryPostProcessor,它继承了BeanFactoryPostProcessor
    • 允许在正常的 BeanFactoryPostProcessor检测开始之前注册更多的自定义beandefinition
    • 可以利用它扫描其它第三放工具类,将其注册进容器,实现框架的整合
    public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
    	void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
    
    }
    

代码示例:往容器中多注册一个User类的BeanDefination

@Configuration
public class CustomizedBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
		Class<?> clazz = User.class;
		BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
		GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition();
		registry.registerBeanDefinition("user5", definition);
	}

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

	}
}
1.2 BeanPostProcessor
  • BeanPostProcessor
    public interface BeanPostProcessor {
    	//该方法在bean实例化完毕(且已经注入完毕),在afterPropertiesSet或自定义init方法执行之前
    	@Nullable
    	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    		return bean;
    	}
    	//在afterPropertiesSet或自定义init方法执行之后
    	@Nullable
    	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    		return bean;
    	}
    
    }
    

代码示例:每个Bean在初始化前后都会调用

@Configuration
public class CustomizedBeanPostProcessor implements BeanPostProcessor {
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException{
		System.out.println(beanName + "调用了 postProcessBeforeInitialization() ");
		return bean;
	}
	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException{
		System.out.println(beanName + "调用了 postProcessAfterInitialization() ");
		return bean;
	}
}

2 Aware

  • 从Bean中获取到容器实例并对其进行操作
    在这里插入图片描述

代码示例:ApplicationContext、BeanNameAware

@Controller
public class WelcomeController implements ApplicationContextAware, BeanNameAware {
	private String myName;
	private ApplicationContext myContainer;
	@Autowired
	private WelcomeService welcomeService;
	
	public void handleRequest(){
		welcomeService.sayHello("来自Controller的问候");
		System.out.println("我是谁:" + myName);
		String[] beanDefinitionNames = myContainer.getBeanDefinitionNames();
		for(String beanDefinitionName : beanDefinitionNames) {
			System.out.println("召唤容器神兽,通过神兽获得:" + beanDefinitionName);
		}
	}

	@Override
	public void setBeanName(String name) {
		this.myName = name;
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.myContainer = applicationContext;
	}
}

3 Spring事件驱动模型

3.1 回调函数
  • 回调函数:往组件注册自定义的方法以便组件在特定场景下调用
  • Runnable接口的run方法就是很好的回调函数例子
    • 先让线程休眠2s,2s之后run()继续执行,这就是一种回调
    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("我要休息啦");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("我被回调啦");
        }
    });
    thread.start();
    
3.2 事件监听器模式
  • 监听器将监听自己感兴趣的时间,一旦时间发生,便做出响应
  • 它有三个组件
    • 事件源(Event Source):负责产生事件的对象。比如我们常见的按钮,按钮就是一个事件源,能够产生“点击”这个事件
    • 事件监听器(Event Listener):负责处理事件的对象
    • 事件对象(Event Object):或者称为事件对象,是事件源和事件监听器之间的信息桥梁。是整个事件模型驱动的核心

代码示例

  • 创建事件对象

    @Getter@Setter
    public class Event {
        private String type;
    }
    
    
  • 创建事件监听器接口

    public interface EventListener {
        public void processEvent(Event event);
    }
    
  • 创建两个事件监听器接口的实现类

    public class SingleClickEventListener implements EventListener {
        @Override
        public void processEvent(Event event) {
            if("singleclick".equals(event.getType())){
                System.out.println("单击被触发了");
            }
        }
    }
    
    public class DoubleClickEventListener implements EventListener {
        @Override
        public void processEvent(Event event) {
            if("doubleclick".equals(event.getType())){
                System.out.println("双击被触发了");
            }
        }
    }
    
  • 创建事件源

    public class EventSource {
        private List<EventListener> listenerList = new ArrayList<>();
        public void register(EventListener listener){
            listenerList.add(listener);
        }
        public void publishEvent(Event event){
            for(EventListener listener: listenerList){
                listener.processEvent(event);
            }
        }
    }
    
  • 测试

    public static void main(String[] args) {
        EventSource eventSource = new EventSource();
        SingleClickEventListener singleClickEventListener = new SingleClickEventListener();
        DoubleClickEventListener doubleClickEventListener = new DoubleClickEventListener();
        Event event = new Event();
        event.setType("doubleclick");
        eventSource.register(singleClickEventListener);
        eventSource.register(doubleClickEventListener);
        eventSource.publishEvent(event);
    }
    

    在这里插入图片描述

3.3 Spring事件驱动模型
3.3.1 事件 - ApplicationEvent抽象类
  • 可以通过ApplicationEvent中的source属性获得事件源
    在这里插入图片描述
3.3.2 事件监听器 - ApplicationListener

在这里插入图片描述

  • 可以自己实现ApplicationListener接口或者使用注解@EventListener实现监听器
3.3.3 事件发布器 - Publisher & Multicaster

在这里插入图片描述

  • ApplicationEventPublisher只拥有发布事件的功能。ApplicationContext继承了此接口,也就是说ApplicationContext拥有事件发布的能力

    • 可以看到ApplicationEventPublisher中只有两个和发布事件相关的方法
    @FunctionalInterface
    public interface ApplicationEventPublisher {
    
    	default void publishEvent(ApplicationEvent event) {
    		publishEvent((Object) event);
    	}
    
    	void publishEvent(Object event);
    }
    
  • ApplicationEventMulticaster,拥有更丰富的功能,它除了拥有发布事件的方法之外还拥有添加和删除ApplicationListener的方法

    public interface ApplicationEventMulticaster {
    }
    
  • 我们可以通过ApplicationEventPublisherAware获取到ApplicationEventPublisher,也就是ApplicationContext,从而发布自定义事件给容器中注册的自定义的ApplicationListener去处理

ApplicationEventPublisher和ApplicationEventMulticaster之间的关系

  • 如果Bean和容器本身只想发布事件,而不想维护事件本身,比如事件监听器等,于是Spring将抽象出事件发布器接口ApplicationEventPublisher,而ApplicationEventMulticaster则作为代理,让Multicaster实现Publisher里面的publishEvent()逻辑

二、Spring容器初始化逻辑

在这里插入图片描述

1 总体分析

  • 以AnnotationConfigApplicationContext为例,它会执行AbstractApplicationContext的refresh()方法
    在这里插入图片描述

    @Override
    public void refresh() throws BeansException, IllegalStateException {
    	// 给容器refresh加锁,避免容器处在refresh阶段时,容器进行了初始化或者销毁的操作
    	synchronized (this.startupShutdownMonitor) {
    		// 调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识,具体方法
    		prepareRefresh();
    
    		//告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从
    		//子类的refreshBeanFactory()方法启动,里面有抽象方法
    		//针对xml配置,最终创建内部容器,该容器负责 Bean 的创建与管理,此步会进行BeanDefinition的注册
    		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
    		// 注册一些容器中需要的系统Bean.例如classloader,beanfactoryPostProcessor等
    		prepareBeanFactory(beanFactory);
    
    		try {
    			//允许容器的子类去注册postProcessor  ,钩子方法
    			postProcessBeanFactory(beanFactory);
    
    			// 激活在容器中注册为bean的BeanFactoryPostProcessors
    			//对于注解容器,org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
    			//方法扫描应用中所有BeanDefinition并注册到容器之中
    			invokeBeanFactoryPostProcessors(beanFactory);
    
    			// 注册拦截bean创建过程的BeanPostProcessor
    			registerBeanPostProcessors(beanFactory);
    
    			// 找到“messageSource”的Bean提供给ApplicationContext使用,
    			// 使得ApplicationContext具有国际化能力。
    			initMessageSource();
    
    			// 初始化ApplicationEventMulticaster该类作为事件发布者,
    			// 可以存储所有事件监听者信息,并根据不同的事件,通知不同的事件监听者。
    			initApplicationEventMulticaster();
    
    			// 预留给 AbstractApplicationContext 的子类用于初始化其他特殊的 bean,
    			// 该方法需要在所有单例 bean 初始化之前调用
    			// 比如Web容器就会去初始化一些和主题展示相关的Bean(ThemeSource)
    			onRefresh();
    
    			// 注册监听器(检查监听器的bean并注册它们)
    			registerListeners();
    
    			//设置自定义的类型转化器ConversionService,
    			// 设置自定义AOP相关的类LoadTimeWeaverAware,
    			// 清除临时的ClassLoader
    			// ,实例化所有的类(懒加载的类除外)
    			finishBeanFactoryInitialization(beanFactory);
    
    			// 初始化容器的生命周期事件处理器,(默认使用DefaultLifecycleProcessor),调用扩展了SmartLifecycle接口的start方法
    			// 当Spring容器加载所有bean并完成初始化之后,会接着回调实现该接口的类中对应的方法(start()方法)
    			// 并发布容器刷新完毕事件ContextRefreshedEvent给对应的事件监听者
    			finishRefresh();
    		}
    
    		catch (BeansException ex) {
    			if (logger.isWarnEnabled()) {
    				logger.warn("Exception encountered during context initialization - " +
    						"cancelling refresh attempt: " + ex);
    			}
    
    			// Destroy already created singletons to avoid dangling resources.
    			//销毁已创建的Bean
    			destroyBeans();
    
    			// Reset 'active' flag.
    			//取消refresh操作,重置容器的同步标识
    			cancelRefresh(ex);
    
    			// Propagate exception to caller.
    			throw ex;
    		}
    
    		finally {
    			// 重置Spring内核中的共用的缓存,因为我们可能再也不需要单例bean的元数据了……
    			resetCommonCaches();
    		}
    	}
    }
    

2 prepareRefresh()

3 obtainFreshBeanFactory()

  • 如果是AnnotationConfigApplicationContext,它实际调用的是GenericApplicationContext的refreshBeanFactory()方法
    • DefaultListableBeanFactory在调用AnnotationConfigApplicationContext的时候就创建了
    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    	// 用的是GenericApplicationContext的refreshBeanFactory()方法
    	refreshBeanFactory();
    	// 返回 DefaultListableBeanFactory 实例
    	return getBeanFactory();
    }
    
  • 针对xml配置,最终创建内部容器,该容器负责 Bean 的创建与管理,此步会进行BeanDefinition的注册

4 prepareBeanFactory()

  • 向内部容器中注册添加一些需要的系统Bean。例如classloader,beanfactoryPostProcessor等
    • 这里的内部容器指的是DefaultListableBeanFactory
  • 设置AnnotationConfigApplicationContext的类加载器实例,这样内部容器就能通过此类加载器去加载外部容器的资源
  • 设置临时类加载器
    // 设置临时类加载器
    // 1.用于AbstractApplicationContext中的临时类型匹配
    // 2.在进行AOP的时候会生成代理类,这些代理类是临时的,将临时的代理类放入临时的类加载器
    beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    

5 postProcessBeanFactory()

  • 允许容器的子类去注册postProcessor ==> 钩子方法,子类可以实现也可以不实现

6 invokeBeanFactoryPostProcessors()

  • 它会激活在容器中注册为bean的BeanFactoryPostProcessors
    • 对于注解容器,最终会调用ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry,该方法扫描应用中所有BeanDefinition并注册到容器之中

7 registerBeanPostProcessors()

  • 注册BeanPostProcessor

8 initMessageSource()

  • 国际化配置,针对不同的地区展示不同的语言

9 initApplicationEventMulticaster()

  • 初始化ApplicationEventMulticaster该类作为事件发布者, 可以存储所有事件监听者信息,并根据不同的事件,通知不同的事件监听者。
  • 该方法会判断容器是否已经注册了ApplicationEventMulticaster, 如果容器存在ApplicationEventMulticaster的bean实例,则赋值给容器的applicationEventMulticaster;没有则新建 SimpleApplicationEventMulticaster,并完成 SimpleApplicationEventMulticaster Bean 的注册
    • SimpleApplicationEventMulticaster既支持同步发布也支持异步发布

10 onRefresh()

  • 该方法是一个钩子方法,是AbstractApplicationContext 预留其子类用于初始化其他特殊的 Bean,该方法需要在所有单例 Bean 初始化之前调用
    • 比如Web容器就会去初始化一些和主题展示相关的Bean(ThemeSource)

11 registerListeners()

  • 向前面创建的ApplicationEventMulticaster注册监听器(检查监听器的Bean并注册它们)

12 finishBeanFactoryInitialization()

  • 在此方法中会实例化所有剩余的(非延时加载的)单例Bean
    // 实例化所有剩余的(non-lazy-init非延时加载的)单例
    beanFactory.preInstantiateSingletons();
    
  • 调用的是 DefaultListableBeanFactory 的 preInstantiateSingletons() 方法
    • 该方法中会遍历BeanDefinationNames,执行getBean()方法创建Bean

13 finishRefresh()

  • 初始化容器的生命周期事件处理器,(默认使用DefaultLifecycleProcessor)

14 resetCommonCaches()

  • 重置Spring内核中的共用的缓存
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

熠熠98

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值