spring 事件驱动 以及线程分离

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);
            }
        }
    }

你可能感兴趣的:(spring)