Springイベント駆動およびスレッド分離

15476 ワード

Springイベントモデルイベント駆動モデルは観察者モードの典型的な応用であり、あるいはパブリケーション-サブスクリプションモデルと呼ばれ、JavaにおけるawtのイベントメカニズムとSpringのイベントメカニズムは観察者モードの応用である.一般的には、パブリッシャーに変更変更がある場合、サブスクライバはパブリッシャーの変更通知を受信します.一般的な例を挙げると、ネット上でニュースを見るには、まずニュースを購読する必要があります.新しいニュースがあると、サイトは自動的にニュースを購読したユーザーにプッシュします.
次の2つの例の最初の例はスレッド分離ではありません
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());
        }
    }
}

プロファイルにListenerを追加

<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!!!......

このシナリオが1つの支払いであると仮定すると、2つのリスナーの1つがメール送信であり、1つがメール送信であり、同じトランザクションでメール送信に異常が発生した場合、支払い操作もロールバックされる可能性があります.
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>

最後の出力結果は2つの異なるスレッドが出力し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);
            }
        }
    }