Blame view

技术分享/com.yoho.core事件及系统监控机制的实现逻辑.md 6.7 KB
wangshijie authored
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
yohobuy事件及系统监控机制的实现逻辑
----
## 一、大致思路

 基于spring事件机制,根据需要监控的内容(数据库操作、rabitMQ、服务调用、log、异常等)定义各类事件和监听器,通过AOP或者直接方式捕获并发布事件,各监听器处理事件并通过包装在监听器内部的EventReporter报告处理过的事件并通过InfluxDB将信息保存到数据库中,供各相关系统查询。

## 二、具体实现
### 1.spring事件机制
#### Spring事件体系包括一下组件:
- 事件:ApplicationEvent
- 事件监听器:ApplicationListener,对监听到的事件进行处理,具体的监听器要该接口onApplicationEvent方法。
- 事件广播器:ApplicationEventMulticaster,有保存所有事件监听器的监听器注册表,负责将Springpublish的事件广播给所有的监听器。
- 事件发布者:ApplicationEventPublisher,spring提供了默认实现AbstractApplicationContext

#### 初始化:
wangshijie authored
17
在容器启动的时候,AbstractApplicationContext会首先找有没有用户配置的事件广播器ApplicationEventMulticaster,\n
wangshijie authored
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
如果有则加载进来,没有则new一个事件广播器SimpleApplicationEventMulticaster。具体代码如下:
```java
 protected void initApplicationEventMulticaster() {
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
			this.applicationEventMulticaster =
					beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
			if (logger.isDebugEnabled()) {
				logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
			}
		}
		else {
			this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
			beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
			if (logger.isDebugEnabled()) {
				logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
						APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
						"': using default [" + this.applicationEventMulticaster + "]");
			}
		}
```	
wangshijie authored
39
然后spring会通过反射机制将所有实现了事件监听器接口ApplicationListener的bean注册到事件广播器的监听器注册表中。
wangshijie authored
40 41 42
    
#### 事件发布和处理:
wangshijie authored
43 44 45
只要是实现了ApplicationEventPublisherAware接口的bean,spring会将事件发布者实际就是ApplicationContext设置到该bean中。
要发布事件就调用ApplicationEventPublisher的publishEvent方法,在该方法中spring会委托事件广播器发布事件。
事件广播器会遍历注册的每个监听器,并启动来调用每个监听器的onApplicationEvent方法进行事件的处理。
wangshijie authored
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
由于spring自动new的事件广播器SimpleApplicationEventMulticaster的taskExecutor为null,因此,事件监听器对事件的处理,是同步进行的。
要等所有监听器处理完事件才能返回。
```java
    @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);
			}
		}
	}
	
	@SuppressWarnings({"unchecked", "rawtypes"})
	protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {
		ErrorHandler errorHandler = getErrorHandler();
		if (errorHandler != null) {
			try {
				listener.onApplicationEvent(event);
			}
			catch (Throwable err) {
				errorHandler.handleError(err);
			}
		}
		else {
			listener.onApplicationEvent(event);
		}
	}
```

如果想用异步的,可以自己实现ApplicationEventMulticaster接口,并在Spring容器中注册id为 **applicationEventMulticaster** 的Bean。
wangshijie authored
86
Spring发布一个事件之后,所有注册的事件监听器,都会收到该事件,因此,事件监听器在处理事件时,需要先判断该事件是否是自己关心的。
wangshijie authored
87
    
wangshijie authored
88
### 2.yoho.core的实现
wangshijie authored
89 90 91 92 93
- 定义CommonEvent,扩展自ApplicationEvent增加了name属性,在com.yoho.error.event包中。
- 定义了各个具体事件(DatabaseAccessEvent、GatewayAccessEvent、ServiceCallEvent等)都继承自CommonEvent。
- 定义抽象类AbstractEventHandler并实现ApplicationListener接口的onApplicationEvent方法进行各事件的公共处理。
- 针对各个事件定义对应的事件监听器(DatabaseAccessEventHandler、GatewayAccessEventHandler等)都继承自AbstractEventHandler。
- 各个需要发布事件的bean实现ApplicationEventPublisherAware接口,调用ApplicationEventPublisher.publishEvent()发布事件。
wangshijie authored
94
- 由于是异步的,所以要实现ApplicationEventMulticaster接口,故在spring-core-alarm.xml中定义了如下bean,id必须是**applicationEventMulticaster**
wangshijie authored
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125

```xml
    <!--支持异步的事件-->
    <bean id="applicationEventMulticaster"
          class="org.springframework.context.event.SimpleApplicationEventMulticaster">
        <property name="taskExecutor">
            <bean class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"/>
        </property>
    </bean>
```
- 各监听器中在xml都设置了eventReporter属性,示例如下:

```xml
    <bean id="databaseAccessEventHandler" class="com.yoho.core.common.alarm.event.DatabaseAccessEventHandler">
        <property name="eventReporter" ref="eventReporter"/>
        <property name="tag_context" value="${web.context:default}"/>
    </bean>
```
- eventReporter定义如下:

```xml
    <bean id="eventReporter" class="com.yoho.core.common.alarm.InfluxDataReporter" init-method="init">
       <property name="dbName" value="yoho-monitor"/>
        <property name="dbUrl" value="${alarm.influxdb.url:http://influxdb.yohoops.org:8086}"/>
        <property name="user" value="${alarm.influxdb.user:root}"/>
        <property name="password" value="${alarm.influxdb.password:root}"/>
        <property name="enable" value="${alarm.influxdb.enable:true}"/>
    </bean>
```
- InfluxDataReporter实现了EventReporter自定义接口,在init初始化方法中创建了InfluxDB链接并设置了一些参数。
- 实现report方法,进行具体的InfluxDB写入。
wangshijie authored
126 127 128 129 130 131 132 133 134
- 要使用InfluxDB功能,pom中要加入

```xml
    <dependency>
		<groupId>org.influxdb</groupId>
		<artifactId>influxdb-java</artifactId>
		<version>2.1</version>
	</dependency>
```