Springイベント駆動およびスレッド分離
15476 ワード
Springイベントモデルイベント駆動モデルは観察者モードの典型的な応用であり、あるいはパブリケーション-サブスクリプションモデルと呼ばれ、JavaにおけるawtのイベントメカニズムとSpringのイベントメカニズムは観察者モードの応用である.一般的には、パブリッシャーに変更変更がある場合、サブスクライバはパブリッシャーの変更通知を受信します.一般的な例を挙げると、ネット上でニュースを見るには、まずニュースを購読する必要があります.新しいニュースがあると、サイトは自動的にニュースを購読したユーザーにプッシュします.
次の2つの例の最初の例はスレッド分離ではありません
最終結果main.....message!!!……
次の例では、イベントリスナーを追加します.
プロファイルにListenerを追加
結果はmainスレッドから出力されます
このシナリオが1つの支払いであると仮定すると、2つのリスナーの1つがメール送信であり、1つがメール送信であり、同じトランザクションでメール送信に異常が発生した場合、支払い操作もロールバックされる可能性があります.
springはスレッド分離技術を採用しています.プロファイルを以下に変更します.
最後の出力結果は2つの異なるスレッドが出力しmainスレッドではないことを示した.
これはSimpleApplicationEventMulticasterにスレッドプールの処理を追加し、スレッド実行をリスニングするonApplicationEvent(event)が追加されたためです.
次の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);
}
}
}