一,Spring启动流程概述
Spring的IoC容器在实现控制反转和依赖注入的过程中,可以划分为两个阶段:
-
容器启动阶段
-
Bean实例化阶段
容器初始化
-
加载配置
-
分析配置信息
-
将Bean信息装配到BeanDefinition
-
将Bean信息注册到相应的BeanDefinitionRegistry
-
其他后续处理
容器实例化
-
根据策略实例化对象
-
装配依赖
-
Bean初始化前处理
-
对象初始化
-
对象其他处理
-
注册回调接口
二,Spring启动流程详解
初始化事件广播
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 检查配置中是否有applicationEventMulticaster的Bean定义
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
// 如果有则获取(实例化Bean)
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isDebugEnabled()) {
logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
// 如果没有手动创建SimpleApplicationEventMulticaster的实例
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
// 把创建的SimpleApplicationEventMulticaster注册到BeanFactory
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
"': using default [" + this.applicationEventMulticaster + "]");
}
}
}
ApplicationContext中的事件处理是通过ApplicationEvent抽象类和ApplicationListener接口实现的。将实现ApplicationListener接口的Bean部署到上下文中,那么每次将ApplicationEvent发布到ApplicationContext时,该Bean都会得到通知。本质上,这是标准的观察者设计模式。
观察者模式
-
Subject:抽象主题类。保存对所有观察者对象的引用,每个主题都可以有任意数量的观察者。该接口可以添加和删除观察者对象
-
ConcreteSubject:具体主题。将状态保存到具体观察者对。在主题内部发生改变时,给所有登记的观察者发出通知。
-
Observer:抽象观察者。为所有具体的观察者定义接口,在得到主题通知时更新自己。
-
ConcreteObserver:具体观察者。实现更新接口,以使自身状态和主题状态同步。
具体实现
抽象被观察者接口
public interface Subject {
// 添加观察者
public void addObserver(Observer o);
// 删除观察者
public void removeObserver(Observer o);
// 通知观察者
public void notifyObserver();
}
抽象观察者接口
public interface Observer {
// 当被观察者调用notify()方法时,观察者的update()方法会被回调
public void update(String message);
}
定义被观察者,实现了Observerable接口,对Observerable接口的三个方法进行了具体实现,同时有一个List集合,用以保存注册的观察者,等需要通知观察者时,遍历该集合即可。
/**
* 被观察者
* 实现了Subject接口,对Subject接口的三个方法进行了具体实现
*/
public class ConcreteSubject implements Subject {
// 保存观察者的集合
private List<Observer> list;
private String message;
public ConcreteSubject() {
list = new ArrayList<Observer>();
}
@Override
public void addObserver(Observer o) {
list.add(o);
}
@Override
public void removeObserver(Observer o) {
if(!list.isEmpty())
list.remove(o);
}
//遍历
@Override
public void notifyObserver() {
for(int i = 0; i < list.size(); i++) {
Observer oserver = list.get(i);
oserver.update(message);
}
}
public void setMessage(String s) {
this.message = s;
System.out.println("服务消息: " + s);
//消息更新,通知所有观察者
notifyObserver();
}
}
具体观察者
public class User implements Observer {
private String name;
private String message;
public User(String name) {
this.name = name;
}
@Override
// 实现update方法
public void update(String message) {
this.message = message;
read();
}
public void read() {
System.out.println(name + " 收到推送消息: " + message);
}
}
测试类
public class Test {
public static void main(String[] args) {
ConcreteSubject cs = new ConcreteSubject();
Observer user1 = new User("Zhangsan");
Observer user2 = new User("Lisi");
Observer user3 = new User("Wangwu");
cs.addObserver(user1);
cs.addObserver(user2);
cs.addObserver(user3);
cs.setMessage("发布了消息1");
System.out.println("----------------------------------------------");
cs.removeObserver(userZhang);
cs.setMessage("发布了消息2");
}
}
事件驱动机制
事件驱动的常见形式便是发布-订阅模式。
在跨进程的通信间,我们通常采用引入 MQ (消息队列) 来实现消息的发布和订阅。目前主流应用的架构中,均采用消息的发布-订阅模式来进行大型分布式系统的解耦。使得数据生产方和使用方分离,同时 MQ 还可起到削峰等作用。
同一进程内很多时候也需要这种事件驱动机制来进行逻辑解耦。
事件机制主要由三个部分组成:
-
事件对象:事件实体。封装事件源对象和事件,在事件源和监听器之间传递信息
-
监听器:监听事件对象。事件发生时处理回调
-
事件源:事件发生的起源。注册监听,对事件进行响应。
Java的事件机制
Java 提供了事件相关的接口定义:
-
事件对象:EventObject 自定义事件对象需要继承该类
-
监听器:EventListener 事件监听器接口
-
事件源:不需要实现任何接口,Java 中也没给出相应的定义
示例
事件对象
public class JDKEventObject extends EventObject {
private Object source;
/**
* Constructs a prototypical Event.
*
* @param source The object on which the Event initially occurred.
* @throws IllegalArgumentException if source is null.
*/
public JDKEventObject(JDKEventSource source) {
super(source);
this.source = source;
}
@Override
public Object getSource() {
return source;
}
}
监听器
public interface JDKEventListener extends EventListener {
public void handleEvent(JDKEventObject event);
}
事件源
public class JDKEventSource {
private Set<EventListener> listeners = new HashSet();
private String message;
public void addListener(EventListener event) {
listeners.add(event);
}
public void removeListener(EventListener event) {
if (listeners.contains(event))
listeners.remove(event);
}
public void fireEvent() {
Iterator<EventListener> iter = listeners.iterator();
while (iter.hasNext()) {
JDKEventListener listener = (JDKEventListener) iter.next();
listener.handleEvent(new JDKEventObject(this));
}
}
}
测试类
public class JDKEventTest {
public static void main(String[] args) {
JDKEventSource eventSource = new JDKEventSource();
eventSource.addListener(new JDKEventListener() {
@Override
public void handleEvent(JDKEventObject event) {
System.out.println("事件1......");
}
});
eventSource.addListener(new JDKEventListener() {
@Override
public void handleEvent(JDKEventObject event) {
System.out.println("事件2......");
}
});
eventSource.fireEvent();
}
}
事件处理机制在某种程度上与发布-订阅模式非常相似,事件监听器的角色与观察者类似,事件源则充当了被观察对象。事件源状态触发后,主动发起通知给监听器,监听器完成各种后续处理。
Spring事件机制
Spring内置事件:
事件类 | 说明 |
ContextRefreshedEvent | ApplicationContext初始化或刷新时触发该事件。通常在Spring加载或刷新应用上下文时,同事也想刷新预加载的资源,就可以通过监听ContextRefreshedEvent来做这样的事情。这里的“初始化”是指所有Bean均已加载,检测到并激活了BeanPostProcessors,已预先实例化单例并且可以使用ApplicationContext对象。只要上下文尚未关闭,选用的ApplicationContext支持这种“热”刷新(如:XmlWebApplicationContext支持热刷新,但GenericApplicationContext不支持),刷新可以被多次触发。 |
ContextStartedEvent | ApplicationContext启动时触发该事件。"Started" 意味着所有Lifecycle Bean会获得启动事件。 通常,此事件用于在显式停止后重新启动Bean时,也可以用于启动尚未配置为自动启动的组件。 |
ContextStoppedEvent | ApplicationContext被停止时触发该事件。"Stopped"是指所有Lifecycle Bean都收到一个明确的停止事件。已停止的上下文可以通过start()调用重新启动 |
ContextClosedEvent | ApplicationContext被关闭时触发该事件。 "Closed" 意味着容器管理的所有单例Bean都被销毁。关闭的上下文表示容器生命周期结束,它不能刷新或重新启动。 |
RequestHandledEvent | 基于Web应用的事件,当一个HTTP请求完成后,触发该事件。该事件仅适用于使用DispatcherServlet的Web应用程序。 |
容器生命周期
BeanPostProcessor及Bean的初始和销毁回调这些事件都是建立在容器已经成功启动的基础上,如果我们想在容器本身的生命周期。
// 生命周期接口,任何Spring管理的对象都可以实现该接口
public interface Lifecycle {
void start();
void stop();
boolean isRunning();
}
// 管理ApplicationContext生命周期
public interface LifecycleProcessor extends Lifecycle {
void onRefresh();
void onClose();
}
public interface SmartLifecycle extends Lifecycle, Phased {
// Lifecycle Bean是否自动启动
boolean isAutoStartup();
// 停止的时候执行回调,默认超时时间30秒
void stop(Runnable callback);
}
// Phased最小的对象首先启动,停止时,顺序和启动时相反
public interface Phased {
// SmartLifecycle的实现类默认Phase为0
int getPhase();
}
常规的Lifecycle接口只在容器上下文显式的调用start()/stop()方法时,才会去回调Lifecycle实现类的start/stop方法逻辑。并不意味着在上下文刷新时自动启动。
另外,LifeCycle Bean在销毁之前不能保证会收到停止通知。正常关闭时,所有Lifecycle Bean在销毁回调之前首先会收到停止通知,但是在上下文的生命周期内进行热刷新或中止刷新尝试时,只会调用destroy方法。
// 实现Lifecycle的测试类
public class TestLifeCycle implements Lifecycle {
private boolean running = false;
public TestLifeCycle() {
System.out.println("TestLifeCycle.......");
}
@Override
public void start() {
System.out.println("TestLifeCycle.start().......");
running = true;
}
@Override
public void stop() {
System.out.println("TestLifeCycle.start().......");
running = false;
}
@Override
public boolean isRunning() {
return running;
}
}
// 实现SmartLifecycle的测试类
public class TestSmartLifecycle implements SmartLifecycle {
private boolean running = false;
public TestSmartLifecycle() {
System.out.println("TestSmartLifecycle.......");
}
@Override
public boolean isAutoStartup() {
return true;
}
@Override
public int getPhase() {
return 10000;
}
@Override
public void start() {
System.out.println("TestSmartLifecycle.start().......");
running = true;
}
@Override
public void stop() {
System.out.println("TestSmartLifecycle.stop().......");
running = false;
}
@Override
public void stop(Runnable callback) {
System.out.println("TestSmartLifecycle.stop(Runnable callback).......");
running = false;
}
@Override
public boolean isRunning() {
return running;
}
}
事件机制
Spring事件机制中除了事件对象和监听者者两个角色之外,“事件广播器”则负责把事件转发给监听者:
类名 | 描述 |
ApplicationEvent | Spring提供的事件类,继承自 EventObject 类 |
ApplicationListener | 事件监听者,该类接收一个泛型,供 ApplicationEventPublisher 在发布事件时选择 EventListener |
ApplicationEventPublisher | 封装事件发布功能的接口,通知所有在 Spring 中注册的该事件的监听者进行处理 |
ApplicationEventPublisherAware | Spring 提供的 Aware 接口之一,实现该接口的 Bean 可以获取 ApplicationEventPublisher 并进行发布事件 |
ApplicationEventMulticaster | 管理多个ApplicationListener对象并向其发布事件的接口 |
示例
Spring 中,不需要我们手动进行监听器注册。ApplicationListener 对象一旦在 Spring 容器中被注册,Spring 会进行监听器的注册,实现事件的监听。
服务类
// Spring容器检测到Service实现了ApplicationEventPublisherAware接口,会自动调用setApplicationEventPublisher
public class SpringService implements ApplicationEventPublisherAware {
private List<String> nameList;
private ApplicationEventPublisher publisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
public void setNameList(List<String> list) {
this.nameList = list;
}
// 要发布自定义ApplicationEvent,需要在ApplicationEventPublisher上调用publishEvent方法
public void sendMessage(String name) {
if (nameList.contains(name)) {
publisher.publishEvent(new SpringEvent(this, name));
return;
}
}
}
监听器
// 要接收自定义的ApplicationEvent,需要实现ApplicationListener监听器
public class SpringListener implements ApplicationListener<SpringEvent> {
String notifier;
public void setNotifier(String notifier) {
this.notifier = notifier;
}
@Override
public void onApplicationEvent(SpringEvent event) {
System.out.println("onApplicationEvent: "+ notifier);
}
}
事件类
public class SpringEvent extends ApplicationEvent {
String name;
/**
* Create a new ApplicationEvent.
*
* @param source the object on which the event initially occurred (never {@code null})
*/
public SpringEvent(Object source, String name) {
super(source);
this.name = name;
}
}