1、必须了解的 Spring 基础概念
1.1 BeanFacotry 与 ApplicationContext
1.1.1 BeanFactory 源码分析
我们回顾下 Spring 的小例子:
/** * <p>spring源码小例子</p> * @date: 2021/1/3 08:59 */@SuppressWarnings("deprecation")public class BeanFactoryTest { @Test public void testSimpleLoad(){ //BeanFactory容器的使用 BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml")); MyTestBean bean = (MyTestBean) bf.getBean("myTestBean"); assertEquals("testBean", bean.getTestStr()); }}
复制代码
BeanFactory 接口的定义方法列表:
BeanFactory.getBean() 源码:
//--------------------------------------------------------------------- // Implementation of BeanFactory interface //---------------------------------------------------------------------
@Override public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); }
@SuppressWarnings("unchecked") protected <T> T doGetBean( String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
String beanName = transformedBeanName(name); Object bean;
// Eagerly check singleton cache for manually registered singletons. //Return the (raw) singleton object registered under the given name. // 从单例池获取Bean对象 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { if (logger.isTraceEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { logger.trace("Returning cached instance of singleton bean '" + beanName + "'"); } } //获取Bean对象的实例 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); }
复制代码
代码分析:
此处,我们通过构造 BeanFactory 的 实例对象 XmlBeanFactory,完成对特定 xml 文件的 Bean 信息加载,然后通过 getBean(String beanName); 方法获取特定的对象。
BeanFactory 在启动的时候不会去实例化 Bean,二是只有从容器中取 Bean 的时候才会去实例化;
BeanFactory 具备延迟实例化的优点;
同时,BeanFactory 也具备不能及时发现一些存在的 Spring 的配置问题的缺点;
1.1.2 ApplicationContext 源码分析
同样我们也回顾下例子 2,如何使用 ApplicationContext 获取特定的 Bean 对象:
/** * <p>自定义标签解析</p> * @date: 2021/1/6 18:31 */public class CustomXSDTagTest { @Test public void testSimpleLoad() { //读取配置文件,ApplicationContext 容器的使用 ApplicationContext bf = new ClassPathXmlApplicationContext("test.xml"); User user = (User) bf.getBean("testbean"); System.out.println(user.getEmail() + " " + user.getUserName() + "" + user.getAge()); }}
复制代码
ApplicationContext 接口的关系架构图:(ApplicationContext 本质是对 BeanFactory 进行了功能拓展)
ApplicationContext 接口的定义方法列表:
ApplicationContext 的构造器源码:
registerListeners();
public ClassPathXmlApplicationContext( String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
super(parent); setConfigLocations(configLocations); if (refresh) { //此处的refresh() 方法,会一次性将所有的bean全部装载到Spring容器 refresh(); } }
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // 解析xml配置文件 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // 注册未来bean实例化的前后置处理的PostProcessor接口实现 postProcessBeanFactory(beanFactory); //执行所有实现BeanFactoryPostProcessor接口实现,对beanFactory进行处理 invokeBeanFactoryPostProcessors(beanFactory); // 注册未来bean实例化的前后置处理的PostProcessor接口实现 registerBeanPostProcessors(beanFactory); // 注册未来bean实例化的前后置处理的PostProcessor接口实现 initMessageSource(); // 实例化spring事件发布监听机制的核心类,SimpleApplicationEventMulticaster initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // 注册事件监听器 registerListeners(); // 实例化非懒加载的bean,完成ioc容器中bean的实例化和反转依赖,并在内部实现动态代理相关的操作 finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex); // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } } }
复制代码
ApplicationContext.getBean()方法源码:
//--------------------------------------------------------------------- // Implementation of BeanFactory interface //---------------------------------------------------------------------
@Override public Object getBean(String name) throws BeansException { assertBeanFactoryActive(); return getBeanFactory().getBean(name); }
复制代码
1.1.3 BeanFacotry 与 ApplicationContext 的区别
如 XMLBeanFactory 就是一种典型的 BeanFactory。原始的 BeanFactory 无法支持 spring 的许多插件,如 AOP 功能、Web 应用等。
ApplicationContext 接口,它由 BeanFactory 接口派生而来,因而提供 BeanFactory 所有的功能。ApplicationContext 以一种更向面向框架的方式工作以及对上下文进行分层和实现继承,ApplicationContext 包还提供了以下的功能:
MessageSource, 提供国际化的消息访问
资源访问,如 URL 和文件
事件传播 (我们这章节的重点)
载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的 web 层
2、Spring 事件发布与监听的应用场景
2.1 自定义事件源和事件 pojo
public class TestEvent extends ApplicationEvent { /** * Create a new {@code ApplicationEvent}. * * @param source the object on which the event initially occurred or with * which the event is associated (never {@code null}) */ public TestEvent(TestInfo source) { super(source); }}
复制代码
public class TestInfo { private String info;
public String getInfo() { return info; }
public void setInfo(String info) { this.info = info; }}
复制代码
2.2 自定义事件监听器
@Componentpublic class TestEventListener implements ApplicationListener<TestEvent> { @Override public void onApplicationEvent(TestEvent event) { TestInfo testInfo = (TestInfo) event.getSource(); System.out.println("testInfo = " + testInfo); }}
复制代码
2.3 发布自定义事件
@Autowired private ApplicationEventPublisher applicationEventPublisher;
private void publishEvent() { TestInfo testInfo = new TestInfo(); testInfo.setInfo("zk-init"); TestEvent testEvent = new TestEvent(testInfo); applicationEventPublisher.publishEvent(testEvent); }
复制代码
2.4 代码分析
ApplicationContext 事件机制是观察者设计模式的实现。
通过 ApplicationEvent 类和 ApplicationListener 接口,可以实现 ApplicationContext 事件处理。 如果容器中有一个 ApplicationListener Bean,每当 ApplicationContext 发布 ApplicationEvent 时,ApplicationListener Bean 将自动被触发(同步/异步的方式)。
两个重要成员
ApplicationEvent:容器事件,必须由 ApplicationContext 发布;
ApplicationListener:监听器,可由容器中的任何监听器 Bean 担任。
3、源码剖析
源码剖析分为 3 个组件:
3.1 组件一:事件 ApplicationEvent 的 5 种实现
ContextRefreshedEvent :当 ApplicationContext 初始化或者刷新,将会发布,例如使用 ConfigurableApplicationContext 接口调用 refresh 方法,初始化意味着加载所有的 bean,同时
ContextStartedEvent:当 ApplicationContext 启动的时候,将会调用 start 方法,发布此事件。
ContextStoppedEvent:当容器停止的时候,发布事件。
ContextClosedEvent:当容器关闭的时候,发布事件。
RequestHandledEvent:http 请求完成后,发布事件。
ApplicationEvent 是所有事件的基础抽象类,自定义事件也是继承了它。
3.2 组件二:监听器 ApplicationListener
ApplicationListener:ApplicationContext 容器内部自定义事件监听器接口,继承自 java.util.EventListener,ApplicationContext 容器在启动时,会自动识别并加载 EventListener 类型 bean 的定义,一旦容器事件发布,将会通知注册到容器的监听器。
3.3 组件三:广播器 ApplicationEventMulticaster
3.3.1 发布器 ApplicationEventPublisher 和 广播器 ApplicationEventMulticaster
ApplicationContext 委托给了 AbstractApplicationEventMulticaster 来实现事件监听器(ApplicationListener)的管理。
3.3.2 发布事件 - ApplicationEventPublisher
源码
使用了 applicationEventPublisher.publishEvent() 的代码段,可以将事件发布出去。
protected void publishEvent(Object event, @Nullable ResolvableType eventType) { Assert.notNull(event, "Event must not be null");
// Decorate event as an ApplicationEvent if necessary ApplicationEvent applicationEvent; if (event instanceof ApplicationEvent) { applicationEvent = (ApplicationEvent) event; } else { applicationEvent = new PayloadApplicationEvent<>(this, event); if (eventType == null) { eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType(); } }
// Multicast right now if possible - or lazily once the multicaster is initialized if (this.earlyApplicationEvents != null) { this.earlyApplicationEvents.add(applicationEvent); } else { //获取到广播器,并且将自定义事件告诉广播器。 getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType); }
// Publish event via parent context as well... if (this.parent != null) { if (this.parent instanceof AbstractApplicationContext) { ((AbstractApplicationContext) this.parent).publishEvent(event, eventType); } else { this.parent.publishEvent(event); } } }
复制代码
源码分析:
获取到广播器(SimpleApplicationEventMulticaster),并且将自定义事件告诉广播器。
3.3.3 广播器 - SimpleApplicationEventMulticaster
ApplicationEventMulticaster 接口实现类是 SimpleApplicationEventMulticaster,它的 multicastEvent() 方法功能是:实现了遍历监听器列表,逐个发布事件到监听器中(观察者模式的应用场景)。
final Map<ListenerCacheKey, CachedListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64);
复制代码
@Override public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); Executor executor = getTaskExecutor(); for (ApplicationListener<?> listener : getApplicationListeners(event, type)) { if (executor != null) { //调用监听器的 onApplicationEvent 方法,处理事件 executor.execute(() -> invokeListener(listener, event)); } else { //调用监听器的 onApplicationEvent 方法,处理事件 invokeListener(listener, event); } } }
复制代码
解析:最终调用 SimpleApplicationEventMulticaster 的 invokeListener() 方法进行实质事件处理。
最终会调用监听器的 onApplicationEvent 方法,实现监听效果。这里注意可能会抛出 ClassCastException 异常,因为事件源被业务处理时可能发生类型转换失败的情况,这样也能够捕获到这类运行时异常。
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) { ErrorHandler errorHandler = getErrorHandler(); if (errorHandler != null) { try { doInvokeListener(listener, event); } catch (Throwable err) { errorHandler.handleError(err); } } else { doInvokeListener(listener, event); } }
@SuppressWarnings({"rawtypes", "unchecked"}) private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) { try { //若是匹配上监听器,则会调用该监听器类的 onApplicationEvent 方法 listener.onApplicationEvent(event); } catch (ClassCastException ex) { String msg = ex.getMessage(); if (msg == null || matchesClassCastMessage(msg, event.getClass()) || (event instanceof PayloadApplicationEvent && matchesClassCastMessage(msg, ((PayloadApplicationEvent) event).getPayload().getClass()))) { // Possibly a lambda-defined listener which we could not resolve the generic event type for // -> let's suppress the exception. Log loggerToUse = this.lazyLogger; if (loggerToUse == null) { loggerToUse = LogFactory.getLog(getClass()); this.lazyLogger = loggerToUse; } if (loggerToUse.isTraceEnabled()) { loggerToUse.trace("Non-matching event type for listener: " + listener, ex); } } else { throw ex; } } }
复制代码
那么要怎么实现异步广播器呢???
@Component("applicationEventMulticaster") 注解则声明了 Bean 的 name 为固定的“applicationEventMulticaster”
/** * <p> * 继承 SimpleApplicationEventMulticaster ,实现异步监听器 * 如下我们看到在以上的判断是否自定义了多播器的代码中,判断在ioc容器中是否包含如下名字的bean作为判断条件的,所以只要我们自定义一个bean命名为applicationEventMulticaster,并把异步支持的executor植入就行了 * </p> */@Component("applicationEventMulticaster")public class AsnyTestEventListener extends SimpleApplicationEventMulticaster { public AsnyTestEventListener () { setTaskExecutor(Executors.newSingleThreadExecutor()); }}
复制代码
2.1、我们走读一下 AbstractApplicationContext 的源码,注意到一个静态字符串变量的值为“applicationEventMulticaster”;
2.2、同时定位到 initApplicationEventMulticaster() 方法的作用就是 Initialize the ApplicationEventMulticaster.(初始化事件广播器),如果可以获取到则使用这个“applicationEventMulticaster”Bean,则可以进行注册了(其实就是获取对象引用然后赋值)。
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext { /** * Name of the ApplicationEventMulticaster bean in the factory. * If none is supplied, a default SimpleApplicationEventMulticaster is used. * @see org.springframework.context.event.ApplicationEventMulticaster * @see org.springframework.context.event.SimpleApplicationEventMulticaster */ public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
/** * Initialize the ApplicationEventMulticaster. * Uses SimpleApplicationEventMulticaster if none defined in the context. * @see org.springframework.context.event.SimpleApplicationEventMulticaster */ protected void initApplicationEventMulticaster() { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); //Bean工厂是否可以获取到 applicationEventMulticaster 的Bean if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) { this.applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class); if (logger.isTraceEnabled()) { logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]"); } } else { //获取不到自定义的广播器,那么就使用默认的 SimpleApplicationEventMulticaster this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster); if (logger.isTraceEnabled()) { logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " + "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]"); } } } }
复制代码
当在我们自定义的多播器中设置了 executor 时,SimpleApplicationEventMulticaster 广播器的 exeutor 就不为空了 ,就会走到第一个异步多播的路径。
4、延伸阅读
《源码系列》
《JDK之Object 类》
《JDK之BigDecimal 类》
《JDK之String 类》
《JDK之Lambda表达式》
《JDK之内部类》
《经典书籍》
《Java并发编程实战:第1章 多线程安全性与风险》
《Java并发编程实战:第2章 影响线程安全性的原子性和加锁机制》
《Java并发编程实战:第3章 助于线程安全的三剑客:final & volatile & 线程封闭》
《服务端技术栈》
《Docker 核心设计理念》
《Kafka史上最强原理总结》
《HTTP的前世今生》
《算法系列》
《读懂排序算法(一):冒泡&直接插入&选择比较》
《读懂排序算法(二):希尔排序算法》
《读懂排序算法(三):堆排序算法》
《读懂排序算法(四):归并算法》
《读懂排序算法(五):快速排序算法》
《读懂排序算法(六):二分查找算法》
《设计模式》
《设计模式之六大设计原则》
《设计模式之创建型(1):单例模式》
《设计模式之创建型(2):工厂方法模式》
《设计模式之创建型(3):原型模式》
《设计模式之创建型(4):建造者模式》
《设计模式之创建型(5):抽象工厂模式》
评论