# Spring – 应用事件

> 原文： [https://howtodoinjava.com/spring-core/how-to-publish-and-listen-application-events-in-spring/](https://howtodoinjava.com/spring-core/how-to-publish-and-listen-application-events-in-spring/)

了解在 Spring 应用程序中创建基于[发布者-订阅者](https://howtodoinjava.com/jms/jms-publish-subscribe-message-example/)的事件。 Spring 创建应用程序事件，发布它们然后在事件处理器中监听提供了内置支持。 要创建/监听应用程序事件，需要遵循一些简单的准则：

1.  **事件**应该扩展`ApplicationEvent`
2.  **发布者**应该注入`ApplicationEventPublisher`对象
3.  **监听器**应该实现`ApplicationListener`接口

## 1\. 为什么是 Spring 事件

有时在 Spring 应用程序中，您可能需要**添加用于监听特定应用程序事件**的功能，以便可以根据应用程序逻辑处理这些事件。

这些事件的示例可以是添加/删除员工时； 或某种事务完成或回滚。 您始终可以将事件处理代码编写为现有应用程序代码中的另一种方法，但是它会与您现有的代码紧密结合，并且您以后将没有太多处理方法来更改它（假设您不想为这些事件处理这些事件）。 一定的时间）。

如果可以通过应用程序上下文文件**配置事件处理器**，则在大多数情况下，您无需更改应用程序代码以及事件处理器代码。 任何时候您需要关闭事件处理； 或者，您想要为该事件添加另一个事件处理器，那么只需更改上下文文件的配置即可。 听起来不错 ！！

在基于 Spring 事件的通信模型中，**发送方组件仅发布事件，而不知道谁将是**。 实际上，**可能有多个接收器组件**。 同样，接收者也不必知道谁在发布事件。 **监听器可以同时监听来自不同发送者的多个事件。 这样，发送方和接收方组件松散耦合。**

让我们学习，**如何在您的 Spring 应用程序**中实现此发布和监听事件。

## 2\. 发布和监听 Spring 应用程序事件

#### 2.1. 创建自定义应用程序事件类

所有事件类都必须扩展`ApplicationEvent`类。

`EmployeeEvent.java`

```java
public class EmployeeEvent extends ApplicationEvent
{
	private static final long serialVersionUID = 1L;

	private String eventType;
	private EmployeeDTO employee;

	//Constructor's first parameter must be source
	public EmployeeEvent(Object source, String eventType, EmployeeDTO employee) 
	{
		//Calling this super class constructor is necessary
		super(source);
		this.eventType = eventType;
		this.employee = employee;
	}

	public String getEventType() {
		return eventType;
	}

	public EmployeeDTO getEmployee() {
		return employee;
	}
}

```

#### 2.2. 发布者 – 实现`ApplicationEventPublisherAware`接口

任何实现`ApplicationEventPublisherAware`接口的 bean，都可以使用其`publishEvent()`方法将事件发送给监听器。

`EmployeeManagerImpl.java`

```java
@Service ("employeeManager")
public class EmployeeManagerImpl implements EmployeeManager, ApplicationEventPublisherAware
{
	@Autowired
	private EmployeeDAO dao;

	private ApplicationEventPublisher publisher;

	//You must override this method; It will give you acces to ApplicationEventPublisher
	public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
		this.publisher = publisher;
	}

	public EmployeeDTO createNewEmployee()
	{
		EmployeeDTO employee =  dao.createNewEmployee();

		//publishing the veent here
		publisher.publishEvent(new EmployeeEvent(this, "ADD", employee));

		return employee;
	}
}

```

#### 2.3. 订阅者/监听器 – 实现`ApplicationListener`接口

为了使 bean 监听某些事件，它必须实现`ApplicationListener`接口并以`onApplicationEvent()`方法处理事件。 实际上，Spring 会将所有事件通知给监听器，因此您必须自己过滤事件。

如果使用泛型，Spring 将仅传递与泛型类型参数匹配的消息。 在此示例中，我使用泛型代码仅监听`EmployeeEvent`。

`UserEventsProcessor.java`

```java
public class UserEventsProcessor implements ApplicationListener<EmployeeEvent> 
{
	public void onApplicationEvent(EmployeeEvent event) 
	{
		EmployeeEvent employeeEvent = (EmployeeEvent) event;

		System.out.println("Employee " + employeeEvent.getEventType() 
                          + " with details : " + employeeEvent.getEmployee());

		// Do more processing as per application logic
	}
}

```

#### 2.4. 在应用程序上下文文件中配置 Bean

`applicationContext.xml`

```java
<context:component-scan base-package="com.howtodoinjava.demo" />

<bean class="com.howtodoinjava.demo.processors.UserEventsProcessor" />

```

#### 2.5. 示例

`TestSpringContext.java`

```java
public class TestSpringContext 
{
	@SuppressWarnings("resource")
	public static void main(String[] args) throws Exception 
	{
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

		EmployeeController controller = context.getBean(EmployeeController.class);

		controller.createNewEmployee();
	}
}

```

观察输出。

`Console`

```java
INFO: Loading XML bean definitions from class path resource [applicationContext.xml]
Employee ADD with details : Employee [id=1, firstName=Lokesh, lastName=Gupta, type=null]

```

很棒。 我们现在可以收听事件，然后可以按照自己的方式进行处理。

> 请注意，应用程序上下文本身还会发布容器事件，例如`ContextClosedEvent`，`ContextRefreshedEvent`和`RequestHandledEvent`。 如果您的任何 bean 希望收到这些事件的通知，则可以实现`ApplicationListener`接口。

## 3\. 本示例中使用的其他类文件

这里的`EmployeeDTO`类如下所示：

`EmployeeDTO.java`

```java
public class EmployeeDTO 
{
	private Integer id;
	private String firstName;
	private String lastName;
	private String designation;

	public EmployeeDTO(String designation) 
	{
		this.id = -1;
		this.firstName = "dummy";
		this.lastName = "dummy";
		this.designation = designation;
	}

	public EmployeeDTO() {
		// TODO Auto-generated constructor stub
	}

	//Setters and Getters

	@Override
	public String toString() {
		return "Employee [id=" + id + ", firstName=" + firstName
				+ ", lastName=" + lastName + ", type=" + designation + "]";
	}
}

```

`EmployeeDAO.java`

```java
public interface EmployeeDAO 
{
	public EmployeeDTO createNewEmployee();
}

```

`EmployeeDAOImpl.java`

```java
@Repository ("employeeDao")
public class EmployeeDAOImpl implements EmployeeDAO
{
	public EmployeeDTO createNewEmployee()
	{
		EmployeeDTO e = new EmployeeDTO();
		e.setId(1);
		e.setFirstName("Lokesh");
		e.setLastName("Gupta");
		return e;
	}

	public void initBean() {
		System.out.println("Init Bean for : EmployeeDAOImpl");
	}

	public void destroyBean() {
		System.out.println("Init Bean for : EmployeeDAOImpl");
	}
}

```

`EmployeeManager.java`

```java
public interface EmployeeManager 
{
	public EmployeeDTO createNewEmployee();
}

```

学习愉快！