标签:需要 为我 null extend end cycle roc port spring容器
一 . 概述
在这里我们不去说事件机制的好处还有一个基础概念性的问题,我们专注于spring的容器事件的问题.
使用事件机制,我们可以完成异步的方法调用,另外使用线程的机制,我们还可以获得并发的好处.
二 .容器事件的开始
我们看一下spring源码之中是如何发布容器事件的.
在refresh()方法之中,我们进入之后可以看到如下的方法.
// Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh();
我们可以看到.spring容器首先注册了一个应用事件多播器,然后注册的事件的监听器对象.
在这里我们知道了spring完成了事件的发布者和监听者的注册.
现在我们比较关系的是,spring到底发布了什么样的事件.
protected void finishRefresh() { // Initialize lifecycle processor for this context. initLifecycleProcessor(); // Propagate refresh to lifecycle processor first. getLifecycleProcessor().onRefresh(); // Publish the final event. publishEvent(new ContextRefreshedEvent(this)); // Participate in LiveBeansView MBean, if active. LiveBeansView.registerApplicationContext(this); }
进入到finishRefresh()方法之中,我们注意到了publishEvent()方法.
这个方法发布了一个容器刷新的事件.
也就是说,ioc容器在初始化完成之后,就会自动发布一个刷新的事件.
三 . 实现一个监听器,完成刷新事件的监听
Spring为我们提供了ApplicationListener接口,我们的POJO只要实现了该接口就具备了事件监听的能力.
//创建一个自己的监听器 public class MyListener implements ApplicationListener<ApplicationEvent>{ @Override public void onApplicationEvent(ApplicationEvent event) { //在这里我们监听了所有的容器事件 if(event instanceof ContextRefreshedEvent) { //此时发出了容器的刷新事件 if(((ApplicationContextEvent) event).getApplicationContext().getParent() == null) { // 为什么要进行这样的判断呢 ? 因为在我们的springmvc和spring整合的时候,会发出两次该事件. //我们需要保证必须使spring容器完成之后才能进行事件的响应 System.out.println("容器刷新了...."); } } } }
现在我们开启容器之后,看看是否有容器刷新的打印信息.
配置信息:
@Configuration @Import(MyListener.class) public class Config { }
测试代码:
public class MainTest { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class); } }
四 . 概念描述
[1]事件发布者 :
在spring之中,事件的发布者就是IOC容器,也就是说我们只要获取了IOC容器的引用就能发布事件.
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
原因就是ApplicationContext实现了事件发布的接口.
public interface ApplicationEventPublisher { void publishEvent(ApplicationEvent event); void publishEvent(Object event); }
在这个接口之中,我们拥有了发布事件的方法.
[2]事件对象
在上面我们看到了ApplicationEvent对象,我们首先看一下它的结构.
public abstract class ApplicationEvent extends EventObject { private final long timestamp; public ApplicationEvent(Object source) { super(source); this.timestamp = System.currentTimeMillis(); } public final long getTimestamp() { return this.timestamp; } }
我们看到了事件对象本身并没有特殊的地方,而且spring的事件对象还是JDK的事件对象的子类.
另外需要我们注意的就是Object 对象,这个对象表示发生事件的源.
[3]事件的监听器
就是实现了ApplicationListener的对象
五 .异步
到底我们现在的事件是否是异步的呢?
看下面的这个测试.
public class MainTest { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class); System.out.println("执行完容器的初始化"); } }
在我们的测试代码之中,加上一个打印语句.
我们还需要修改Listener.
//创建一个自己的监听器 public class MyListener implements ApplicationListener<ApplicationEvent>{ @Override public void onApplicationEvent(ApplicationEvent event) { //在这里我们监听了所有的容器事件 if(event instanceof ContextRefreshedEvent) { //此时发出了容器的刷新事件 if(((ApplicationContextEvent) event).getApplicationContext().getParent() == null) { // 为什么要进行这样的判断呢 ? 因为在我们的springmvc和spring整合的时候,会发出两次该事件. //我们需要保证必须使spring容器完成之后才能进行事件的响应 System.out.println("容器刷新了...."); } } try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } }
我们仅仅是增加了一个休眠的操作.
我们运行代码,就会发现打印语句需要在事件完成之后才能运行,明显这不是异步的.
那么如何才能实现异步的操作呢?
很简单,spring为我们提供了异步的实现方式.
@Configuration @EnableAsync @Import(MyListener.class) public class Config { }
首先开启异步支持.
然后我们需要将我们的监听器注册为异步执行.
@Async public class MyListener implements ApplicationListener<ApplicationEvent>{
仅仅就是一个注解,就能完成异步操作.
标签:需要 为我 null extend end cycle roc port spring容器
原文地址:https://www.cnblogs.com/trekxu/p/9095298.html