Spring事件模型事件驱动模型是一种观察者模式的典型应用,或者叫发布——订阅模型,Java中awt的事件机制和Spring的事件机制都是观察者模式的应用。一般都是发布者有更改变动时,订阅者会接收到发布者的变动通知。举个通用的例子网上看新闻,首先我们需要去订阅新闻,当有新的新闻时,网站会自动推送新闻给已经订阅过该新闻的用户
下面一个两个例子
第一个例子非线程分离
import org.springframework.context.ApplicationEvent;
public class TestEvent extends ApplicationEvent {
private static final long serialVersionUID = 1L;
private String message;
public TestEvent(Object source) {
super(source);
}
public TestEvent(Object source,String message) {
super(source);
this.message=message;
}
public void print(String threadName){
System.out.println(threadName+"....."+this.message+"......");
}
}
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
public class TestListener implements ApplicationListener<ApplicationEvent>{
@Override
public void onApplicationEvent(ApplicationEvent event) {
if(event instanceof TestEvent){
TestEvent testevent=(TestEvent)event;
testevent.print(Thread.currentThread().getName());
}
}
}
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
public class AppUtil implements ApplicationContextAware {
private static ApplicationContext appContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
appContext = applicationContext;
}
public static Object getBean(String paramString) {
return appContext.getBean(paramString);
}
public static void sendEvent(ApplicationEvent event){
appContext.publishEvent(event);
}
}
public static void main(String[] args) {
ApplicationContext ctx=new ClassPathXmlApplicationContext("spring-context2.xml");
AppUtil.sendEvent(new TestEvent("", "message!!!"));
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<bean id="appUtil" class="com.eroadsf.springdemo.applicationAware.AppUtil" />
<bean id="testListener" class="com.eroadsf.springdemo.applicationAware.TestListener">bean>
beans>
最后结果
main…..message!!!……
下面的例子增加一个事件监听器
public class TestListener1 implements ApplicationListener<ApplicationEvent>{
@Override
public void onApplicationEvent(ApplicationEvent event) {
if(event instanceof TestEvent){
TestEvent testevent=(TestEvent)event;
testevent.print(Thread.currentThread().getName());
}
}
}
配置文件增加一个监听器
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<bean id="appUtil" class="com.eroadsf.springdemo.applicationAware.AppUtil" />
<bean id="testListener" class="com.eroadsf.springdemo.applicationAware.TestListener">bean>
<bean id="testListener1" class="com.eroadsf.springdemo.applicationAware.TestListener1">bean>
beans>
结果都是由main线程输出
main.....message!!!......
main.....message!!!......
假设这个场景是一个支付,2个监听器 一个是邮件发送一个是短信发送,并且在同一个事务中,如果短信发送出现异常可能连支付操作都回滚了。
所以spring采取了线程分离技术
我们将配置文件修改如下:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<bean id="appUtil" class="com.eroadsf.springdemo.applicationAware.AppUtil" />
<bean id="testListener" class="com.eroadsf.springdemo.applicationAware.TestListener">bean>
<bean id="testListener1" class="com.eroadsf.springdemo.applicationAware.TestListener1">bean>
<bean id="taskExecutor"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5">property>
bean>
<bean id="applicationEventMulticaster"
class="org.springframework.context.event.SimpleApplicationEventMulticaster">
<property name="taskExecutor" ref="taskExecutor">property>
bean>
beans>
最后的输出结果看到是两个不同的线程输出的而且不是main线程
taskExecutor-3.....message!!!......
taskExecutor-4.....message!!!......
这是因为SimpleApplicationEventMulticaster里增加了线程池的处理一个监听开一个线程执行onApplicationEvent(event);
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public void multicastEvent(final ApplicationEvent event) {
for (final ApplicationListener listener : getApplicationListeners(event)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
listener.onApplicationEvent(event);
}
});
}
else {
listener.onApplicationEvent(event);
}
}
}