EventBus 와 Spring 이벤트 의 차이 에 대한 상세 한 설명 (EventBus 이벤트 메커니즘, Spring 이벤트 메커니즘)
Guava EventBus
Guava EventBus 실현 은 관찰자 모델 로 용법 이 간단 하 며 먼저 코드 를 올 립 니 다.
/**
* Desc:
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class HelloEvent {
private String eventName;
}
@Data
@NoArgsConstructor
public class WorldEvent extends HelloEvent {
private int eventNo;
public WorldEvent(String name, int no) {
setEventName(name);
setEventNo(no);
}
}
/**
* Desc: , 。 @Subscribe 。
*/
public class GeventListener {
/**
* HelloEvent (Object)
*/
@Subscribe
public void processEvent(HelloEvent event){
System.out.println("process hello event, name:" + event.getEventName());
}
/**
* WorldEvent (HelloEvent Object)
*/
@Subscribe
public void processWorldEvent(WorldEvent event) {
System.out.println("process world eventV1, no:" + event.getEventNo() + ", name:" + event.getEventName());
}
/**
*
* @param event
*/
@Subscribe
public void processWorldEventV2(WorldEvent event) {
System.out.println("process world eventV2, no:" + event.getEventNo() + ", name:" + event.getEventName());
}
@Subscribe
public void processObject(Object object) {
System.out.println("process common event, class:" + object.getClass().getSimpleName());
}
}
public class GuavaTest {
public static void main(String[] args) {
EventBus eventBus = new EventBus();
GeventListener listener = new GeventListener();
eventBus.register(listener);
eventBus.post(new HelloEvent("hello"));
eventBus.post(new WorldEvent("world", 23333));
}
}
결 과 는 다음 과 같다.
//HelloEvent (HelloEvent Object )
process hello event, name:hello
process common event, class:HelloEvent
//WorldEvent ( , )
process world eventV1, no:23333, name:world
process world eventV2, no:23333, name:world
process hello event, name:world
process common event, class:WorldEvent
위 에서 알 수 있 듯 이 Guava EventBus 는 클래스 를 이벤트 로 하고 class 를 key 로 하여 이 벤트 를 등록 하고 관리 하 며 value 는 이벤트 감청 기의 method 입 니 다.이벤트 감청 기 는 특정한 종류의 (부모 클래스) 사건 만 처리 합 니 다.
이벤트 등록 및 발표
//com.google.common.eventbus.EventBus#register
public void register(Object object) {
//key Class, value EventSubscriber(Object target, Method method)【 】。 Multimap HashMultimap, HashMap>
Multimap, EventSubscriber> methodsInListener =
finder.findAllSubscribers(object);
subscribersByTypeLock.writeLock().lock();
try {
subscribersByType.putAll(methodsInListener);
} finally {
subscribersByTypeLock.writeLock().unlock();
}
}
//com.google.common.eventbus.EventBus#post
public void post(Object event) {
// event
Set> dispatchTypes = flattenHierarchy(event.getClass());
boolean dispatched = false;
for (Class> eventType : dispatchTypes) {
subscribersByTypeLock.readLock().lock();
try {
// ( )
Set wrappers = subscribersByType.get(eventType);
if (!wrappers.isEmpty()) {
dispatched = true;
for (EventSubscriber wrapper : wrappers) {
//
enqueueEvent(event, wrapper);
}
}
} finally {
subscribersByTypeLock.readLock().unlock();
}
}
// , DeadEvent
if (!dispatched && !(event instanceof DeadEvent)) {
post(new DeadEvent(this, event));
}
dispatchQueuedEvents();
}
이벤트 격 리
여러 이벤트 버스 는 이 벤트 를 격 리 할 수 있 습 니 다.
public class AnotherListener {
/**
* WorldEvent (HelloEvent Object)
*/
@Subscribe
public void processAnotherWorldEvent(WorldEvent event) {
System.out.println("process another world event, no:" + event.getEventNo() + ", name:" + event.getEventName());
}
}
public class GuavaTest {
public static void main(String[] args) {
EventBus eventBus = new EventBus();
GeventListener listener = new GeventListener();
eventBus.register(listener);
eventBus.post(new HelloEvent("hello"));
EventBus anotherEventBus = new EventBus();
AnotherListener anotherListener = new AnotherListener();
anotherEventBus.register(anotherListener);
anotherEventBus.post(new WorldEvent("AnotherWorld", 666));
}
}
결국
//eventBus
process hello event, name:hello
//anotherEventBus ,
process common event, class:HelloEvent
process another world event, no:666, name:AnotherWorld
적용 필드:
spring 새 이벤트 메커니즘 도 간단 합 니 다. 코드 를 보 세 요.
/**
* ApplicationEvent
*/
@Data
public class HelloEvent extends ApplicationEvent {
private String eventName;
public HelloEvent(String eventName) {
super(eventName);
setEventName(eventName);
}
}
/**
*
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CustomerEvent {
private String name;
private Boolean isCustomer;
}
/**
* ,spring
*/
@Component("springListener")
public class SpringListener {
/**
* ApplicationEvent
*/
@EventListener
public void processApplicationEvent(ApplicationEvent event) {
System.out.println("process common event, class:" + event.getClass().getSimpleName());
}
/**
* HelloEvent
*/
@EventListener
public void processHelloEvent(HelloEvent event) {
System.out.println("process helloEvent, name:" + event.getEventName());
}
/**
* CustomerEvent , condition , isCustomer=true
*/
@EventListener(condition = "#event.isCustomer")
public void processCustomerEvent(CustomerEvent event) {
System.out.println("process customer CustomerEvent, name:" + event.getName());
}
/**
* CustomerEvent , condition , name="miaomiao"
*/
@EventListener(condition = "#event.getName().equals('miaomiao')")
public void processMiaoMiaoEvent(CustomerEvent event) {
System.out.println("process miaomiao's CustomerEvent, name:" + event.getName());
}
/**
*
*/
@Async
@EventListener
public void processAsyncCustomerEvent(CustomerEvent event) {
System.out.println("Async process CustomerEvent, name:" + event.getName());
}
}
// ,
@SpringBootApplication
@ComponentScan(basePackages = {"com.example.manyao.async"})
public class DemoApplication {
public static void main(String[] args) throws TException {
SpringApplication.run(DemoApplication.class, args);
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
String[] names = context.getBeanDefinitionNames();
for(int i=0; i
결국
// spring event, ApplicationContextEvent。 。 ApplicationEvent , , processApplicationEvent 。
process common event, class:ContextRefreshedEvent
process common event, class:EmbeddedServletContainerInitializedEvent
process common event, class:ApplicationReadyEvent
process common event, class:ContextRefreshedEvent
// bean
springListener
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
++++++++++
//HelloEvent ApplicationEvent, processApplicationEvent
process common event, class:HelloEvent
// HelloEvent processHelloEvent
process helloEvent, name:helloEvent
// ApplicationEvent , PayloadApplicationEvent
process common event, class:PayloadApplicationEvent
//isCustomer=true, processCustomerEvent
process customer CustomerEvent, name:customer
// CustomerEvent ,
Async process CustomerEvent, name:customer
process common event, class:PayloadApplicationEvent
// processMiaoMiaoEvent
process miaomiao's CustomerEvent, name:miaomiao
Async process CustomerEvent, name:miaomiao
//spring
process common event, class:ContextClosedEvent
spring 컨 텍스트 이벤트
상술 한 예 중의
ContextRefreshedEvent, Embedded ServletContainer Initialized Event, ApplicationReadyEvent, ContextRefreshedEvent, ContextClosed Event 등 사건 은 모두 spring 컨 텍스트 사건 입 니 다.이 사건 들 을 감청 함으로써 스프링 생명주기 에 참여 할 수 있다.이런 무 침입 성교 방식 은 플랫폼 서 비 스 를 할 때 좋 은 방식 이다.
등록 모니터
org. springframework. context. event. EventListeneMethodProcessor \ # processBean 은 EventListener 를 설명 하 는 모든 방법 을 컨 텍스트 의 applicationListeners 에 저장 합 니 다.Listener 의 패 키 징 클래스 는 ApplicationListener MethodAdapter (String beanName, Class > targetClass, Method method) 입 니 다.
org. springframework. context. support. AbstractApplicationContext \ # refresh 에서 initApplicationEventMulticaster 를 호출 하여 이벤트 발표 관리자 applicationEventMulticaster 를 초기 화하 고 registerListeners () 등록 모니터 를 호출 합 니 다.
게시 이벤트
spring 은 처음에는 애플 리 케 이 션 이벤트 형식 이벤트 만 지원 하 다가 최적화 되면 사용자 정의 이 벤트 를 지원 합 니 다.이벤트 처 리 를 사용자 정의 합 니 다. 기본 값 은 PayloadApplicationEvent 로 EventBus 의 DeadEvent 에 해당 합 니 다.
//org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object, org.springframework.core.ResolvableType)
protected void publishEvent(Object event, ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Publishing event in " + getDisplayName() + ": " + event);
}
// Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
// ApplicationEvent , PayloadApplicationEvent
applicationEvent = new PayloadApplicationEvent
실행 이벤트
@Override
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// ,
for (final ApplicationListener> listener : getApplicationListeners(event, type)) {
// ,
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
invokeListener(listener, event);
}
});
}
else {
//
invokeListener(listener, event);
}
}
}
스프링 의 사건 메커니즘 은 더욱 복잡 하지만 기능 도 마찬가지 로 강하 다 는 것 을 알 수 있다.
적용 필드:
사용 방식 비교
항목
이벤트
발표 자
발표 방법
비동기 여부
감청 자
등록 방식
EventBus
임 의 대상
EventBus
EventBus#post
예.
주해 Subscribe 방법
수 동 등록 EventBus \ # register
Spring Event
임 의 대상
ApplicationEventPublisher
ApplicationEventPublisher#publishEvent
동기 화 비동기 지원
이벤트 Listener 방법 설명
시스템 등록
사용 장면 비교
항목
이벤트 구분
이벤트 클 러 스 터 지원 여부
사용자 정의 이벤트 지원 여부
필터 지원 여부
이벤트 격 리 지원 여부
복잡 도
EventBus
Class
예.
예.
아니.
예.
간단 하 다.
Spring Event
Class
예.
예.
예.
아니.
복잡 하 다.
EventBus 와 Spring Event 에 관 한 더 많은 글 은 아래 의 링크 를 볼 수 있 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.