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 自定义事件监听器
@Component
public 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):抽象工厂模式》
评论