Mecanismo de manejo de eventos de primavera-ApplicationEvent

El manejo de eventos en ApplicationContext se proporciona a través de la clase ApplicationEvent y la interfaz ApplicationListener. Si un bean que implementa la interfaz ApplicationListener está registrado en ApplicationContext, se notificará al bean cada vez que se publique un ApplicationEvent en ApplicationContext. Básicamente, este es el patrón de diseño estándar del observador. A partir de Spring 4.2, la estructura de eventos se ha mejorado significativamente, proporcionando un modelo basado en anotaciones y la capacidad de publicar eventos arbitrarios (es decir, objetos que no necesariamente se extienden desde ApplicationEvent). Cuando se publica un objeto de este tipo, lo envolvemos en un evento. Comprender el mecanismo de eventos de Spring es de gran ayuda para la integración de Spring y otros marcos de terceros. Dubbo publica servicios a través del mecanismo de eventos de Spring. Spring y Spring también proporcionan muchos eventos integrados, como se muestra en la siguiente tabla:

evento

Descripción

ContextRefreshedEvent

Se publica cuando se inicializa o actualiza ApplicationContext (por ejemplo, mediante el método refresh () en la interfaz ConfigurableApplicationContext). Aquí, "inicializar" significa cargar todos los beans, detectar y activar el bean posprocesador, crear una instancia previa del singleton y el objeto ApplicationContext está listo para su uso. Siempre que el contexto no esté cerrado, siempre que el ApplicationContext seleccionado realmente admita este tipo de actualización "en caliente", la actualización se puede activar varias veces. Por ejemplo, XMLWebApplicationContext admite la actualización en caliente, pero GenericApplicationContext no.

ContextStartedEvent

Publicado cuando se inicia ApplicationContext utilizando el método start () en la interfaz configurable ConfigurableApplicationContext. Aquí, "inicio" significa que todos los beans de ciclo de vida recibirán una clara señal de inicio. Esta señal se utiliza para reiniciar después de una parada explícita, pero también se puede utilizar para iniciar un componente que no se ha configurado para iniciarse automáticamente (por ejemplo, un componente que no se ha iniciado durante la inicialización).

ContextStoppedEvent

Se publica cuando se detiene ApplicationContext mediante el método stop () en la interfaz ConfigurableApplicationContext. Aquí, "detener" significa que todos los beans de ciclo de vida recibirán una clara señal de detención. El contexto detenido se puede reiniciar llamando a start ().

ContextClosedEvent

Lanzado cuando ApplicationContext se cierra mediante el método close () en la interfaz ConfigurableApplicationContext. Aquí, "cerrar" significa que se destruyen todos los granos singleton. El ambiente cerrado ha llegado al final de su vida. No se puede actualizar o reiniciar.

RequestHandledEvent

Un evento web específico le dice a todos los beans que la solicitud HTTP ha sido procesada. Este evento se publica después de que se completa la solicitud. Este evento solo se aplica a las aplicaciones web que aplican Spring DispatcherServlet

También podemos crear nuestros propios eventos a través de la clase ApplicationEvent y la interfaz ApplicationListener. El siguiente ejemplo muestra una clase simple que extiende la clase base ApplicationEvent de Spring:

public class BlackListEvent extends ApplicationEvent {
    private final String address;
    private final String content;

    public BlackListEvent(Object source, String address, String content) {
        super(source);
        this.address = address;
        this.content = content;
    }
    // 其他方法
}

Para publicar un ApplicationEvent personalizado, debe llamar al método PublishEvent () en ApplicationEventPublisher. Por lo general, esto se hace creando una clase que implemente ApplicationEventPublisheraware y registrándola como Spring Bean. Como se muestra en el siguiente ejemplo:

public class EmailService implements ApplicationEventPublisherAware {

    private List<String> blackList;
    private ApplicationEventPublisher publisher;

    public void setBlackList(List<String> blackList) {
        this.blackList = blackList;
    }

    public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    public void sendEmail(String address, String content) {
        if (blackList.contains(address)) {
            publisher.publishEvent(new BlackListEvent(this, address, content));
            return;
        }
        // send email...
    }
}

Durante la configuración, el contenedor Spring detecta que EmailService implementa ApplicationEventPublisheraware y llama automáticamente a setApplicationEventPublisher () para inyectar la instancia de ApplicationEventPublisher. De hecho, el parámetro pasado es el propio contenedor Spring. Para recibir un ApplicationEvent personalizado, puede crear una clase que implemente ApplicationListener y registrarla como Spring Bean. El código es el siguiente:

public class BlackListNotifier implements ApplicationListener<BlackListEvent> {
    private String notificationAddress;
    public void setNotificationAddress(String notificationAddress) {
        this.notificationAddress = notificationAddress;
    }
    public void onApplicationEvent(BlackListEvent event) {
        // notify appropriate parties via notificationAddress...
    }
}

Tenga en cuenta que ApplicationListener generalmente se parametriza con el tipo de evento personalizado (BackListEvent en el ejemplo anterior). Esto significa que el método onApplicationEvent () puede garantizar la seguridad de los tipos y evitar cualquier necesidad de conversión descendente. Puede registrar tantos oyentes de eventos como desee, pero tenga en cuenta que, de forma predeterminada, los oyentes de eventos reciben eventos sincrónicamente. Esto significa que el método publishEvent () se bloqueará hasta que todos los oyentes hayan terminado de procesar el evento. Una ventaja de este enfoque síncrono y de un solo subproceso es que cuando el oyente recibe un evento, si el contexto de la transacción está disponible, operará en el contexto de la transacción del editor. Si necesita otra estrategia para la publicación de eventos, consulte la interfaz ApplicationEventMulticaster. La siguiente es la configuración de Spring en el ejemplo anterior:

<bean id="emailService" class="example.EmailService">
    <property name="blackList">
        <list>
            <value>[email protected]</value>
            <value>[email protected]</value>
            <value>[email protected]</value>
        </list>
    </property></bean>
<bean id="blackListNotifier" class="example.BlackListNotifier">
    <property name="notificationAddress" value="[email protected]"/>
</bean>

Cuando se llama al método sendemail () de emailServicebean, si algún correo electrónico debe incluirse en la lista negra, se publicará un evento personalizado de tipo BlackListEvent. El bean blackListNotifier se registra como ApplicationListener y recibe BlackListEvent, momento en el que puede notificar a la parte correspondiente.

Además de publicar eventos usando ApplicationEventPublisher, podemos publicar eventos a través de instancias de ApplicationContext. ApplicationContext proporciona el método publishEvent () para publicar eventos. El código es el siguiente:

public class MessageEvent extends ApplicationEvent {
    private static final long serialVersionUID = 1L;
    private String eventType;
    public String getEventType() {
	return eventType;
    }
    public void setEventType(String eventType) {
	this.eventType = eventType;
    }
    public MessageEvent(Object source) {
	super(source);
    }
}
@Component
public class MessageEventListener implements ApplicationListener<MessageEvent> {
    public void onApplicationEvent(MessageEvent event) {
        String eventType = event.getEventType();
	//发布事件的对象
	Object object = event.getSource();
    }
}
public class SpringEventTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext("cn.org.microservice.spring.ioc.event");
	MessageEvent event = new MessageEvent(applicationContext);
	event.setEventType("发布");
	applicationContext.publishEvent(event);
    }
}

El mecanismo de eventos de Spring está diseñado para una comunicación simple entre SpringBeans en el mismo contexto de aplicación. Sin embargo, para requisitos de integración empresarial más complejos, el proyecto Spring Integration mantenido por separado proporciona soporte completo para construir una arquitectura liviana, orientada a patrones e impulsada por eventos basada en el modelo de programación Spring. A partir de Spring 4.2, puede usar la anotación EventListener para registrar un detector de eventos en cualquier método público del bean administrado. El programa BlackListNotifier se puede reescribir de la siguiente manera:

public class BlackListNotifier {
    private String notificationAddress;
    public void setNotificationAddress(String notificationAddress) {
        this.notificationAddress = notificationAddress;
    }
    @EventListener
    public void processBlackListEvent(BlackListEvent event) {
        // notify appropriate parties via notificationAddress...
    }
}

La firma del método vuelve a declarar el tipo de evento que quiere escuchar, pero esta vez con un nombre flexible en lugar de implementar una interfaz de escucha específica. Siempre que el tipo de evento real resuelva los parámetros genéricos en su jerarquía de implementación, los genéricos pueden limitar el tipo de evento. Si su método debe escuchar varios eventos, o si desea definirlo sin usar ningún parámetro, también puede especificar el tipo de evento en la anotación. El siguiente ejemplo muestra cómo hacer esto:

@EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})
public void handleContextStart() {
    ...
}

Si desea que un oyente específico procese eventos de forma asincrónica, puede reutilizar el soporte @Async habitual . El siguiente ejemplo muestra cómo hacer esto:

@EventListener
@Async
public void processBlackListEvent(BlackListEvent event) {
    // BlackListEvent is processed in a separate thread
}

Si necesita llamar a un oyente primero y luego llamar a otro oyente, puede agregar la anotación @Order a la declaración del método, como se muestra en el siguiente ejemplo:

@EventListener
@Order(42)
public void processBlackListEvent(BlackListEvent event) {
    // notify appropriate parties via notificationAddress...
}

También puede utilizar genéricos para definir mejor la estructura del evento. Considere usar EntityCreatedEvent, donde t es el tipo de entidad real creada. Por ejemplo, puede crear la siguiente definición de escucha para recibir solo EntityCreatedEvent de Person:

@EventListener
public void onPersonCreated(EntityCreatedEvent<Person> event) {
    ...
}

Debido a la eliminación de tipos, esta operación solo es válida cuando el evento desencadenado resuelve los parámetros genéricos filtrados por el detector de eventos (es decir, la clase PersonCreatedEvent extiende EntityCreatedEvent <Person> {…}). En algunos casos, si todos los eventos siguen la misma estructura (como los eventos del ejemplo anterior), esto puede volverse bastante tedioso. En este caso, puede implementar ResolvableTypeProvider para guiar el marco para proporcionar contenido sobre el entorno de ejecución. Los siguientes eventos muestran cómo hacer esto:

public class EntityCreatedEvent<T> extends ApplicationEvent implements ResolvableTypeProvider {

    public EntityCreatedEvent(T entity) {
        super(entity);
    }

    @Override
    public ResolvableType getResolvableType() {
        return ResolvableType.forClassWithGenerics(getClass(), ResolvableType.forInstance(getSource()));
    }
}

 

Supongo que te gusta

Origin blog.csdn.net/wk19920726/article/details/108717994
Recomendado
Clasificación