001/** 002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.jboot.components.event; 017 018import com.jfinal.log.Log; 019import io.jboot.Jboot; 020import io.jboot.core.weight.WeightUtil; 021import io.jboot.utils.*; 022import io.jboot.components.event.annotation.EventConfig; 023 024import java.util.*; 025import java.util.concurrent.*; 026 027 028public class JbootEventManager { 029 030 private static final Log LOG = Log.getLog(JbootEventManager.class); 031 private static JbootEventManager manager = new JbootEventManager(); 032 033 private final Map<String, List<JbootEventListener>> asyncListenerMap; 034 private final Map<String, List<JbootEventListener>> listenerMap; 035 036 037 private ExecutorService threadPool; 038 039 040 private JbootEventManager() { 041 asyncListenerMap = new ConcurrentHashMap<>(); 042 listenerMap = new ConcurrentHashMap<>(); 043 threadPool = NamedThreadPools.newFixedThreadPool("jboot-event"); 044 045 initListeners(); 046 } 047 048 public static JbootEventManager me() { 049 return manager; 050 } 051 052 private void initListeners() { 053 List<Class<JbootEventListener>> classes = ClassScanner.scanSubClass(JbootEventListener.class, true); 054 if (ArrayUtil.isNullOrEmpty(classes)) { 055 return; 056 } 057 for (Class<JbootEventListener> clazz : classes) { 058 registerListener(clazz); 059 } 060 } 061 062 public void unRegisterListener(Class<? extends JbootEventListener> listenerClass) { 063 064 deleteListner(listenerMap, listenerClass); 065 deleteListner(asyncListenerMap, listenerClass); 066 067 if (Jboot.isDevMode()) { 068 LOG.debug(String.format("listener[%s]-->>unRegisterListener.", listenerClass)); 069 } 070 071 } 072 073 private void deleteListner(Map<String, List<JbootEventListener>> map, Class<? extends JbootEventListener> listenerClass) { 074 for (Map.Entry<String, List<JbootEventListener>> entry : map.entrySet()) { 075 JbootEventListener deleteListener = null; 076 for (JbootEventListener listener : entry.getValue()) { 077 if (listener.getClass() == listenerClass) { 078 deleteListener = listener; 079 } 080 } 081 if (deleteListener != null) { 082 entry.getValue().remove(deleteListener); 083 } 084 } 085 } 086 087 public void registerListener(Class<? extends JbootEventListener> listenerClass) { 088 089 if (listenerClass == null) { 090 return; 091 } 092 093 EventConfig listenerAnnotation = listenerClass.getAnnotation(EventConfig.class); 094 if (listenerAnnotation == null) { 095 //当未配置 EventConfig 的时候,可以手动注册 096 return; 097 } 098 099 String[] actions = AnnotationUtil.get(listenerAnnotation.action()); 100 if (actions == null) { 101 LOG.warn("listenerClass[" + listenerAnnotation + "] register fail, because action is null or blank."); 102 return; 103 } 104 105 if (listenerHasRegisterBefore(listenerClass)) { 106 return; 107 } 108 109 JbootEventListener listener = ClassUtil.newInstance(listenerClass); 110 if (listener == null) { 111 return; 112 } 113 114 registerListener(listener, listenerAnnotation.async(), actions); 115 116 } 117 118 119 public void unRegisterListener(JbootEventListener eventListener) { 120 unRegisterListener(eventListener.getClass()); 121 } 122 123 /** 124 * 手从初始化 EventListener ,手动注册 125 * 126 * @param eventListener 127 * @param async 128 * @param actions 129 */ 130 public void registerListener(JbootEventListener eventListener, boolean async, String... actions) { 131 132 for (String action : actions) { 133 List<JbootEventListener> list = async ? asyncListenerMap.get(action) : listenerMap.get(action); 134 135 if (null == list) { 136 list = new ArrayList<>(); 137 } 138 139 if (list.contains(eventListener)) { 140 continue; 141 } 142 143 list.add(eventListener); 144 145 WeightUtil.sort(list); 146 147 if (async) { 148 asyncListenerMap.put(action, list); 149 } else { 150 listenerMap.put(action, list); 151 } 152 } 153 154 if (Jboot.isDevMode()) { 155 LOG.debug(String.format("listener[%s]-->>registered.", eventListener)); 156 } 157 } 158 159 160 private boolean listenerHasRegisterBefore(Class<? extends JbootEventListener> listenerClass) { 161 return findFromMap(listenerClass, listenerMap) 162 || findFromMap(listenerClass, asyncListenerMap); 163 } 164 165 private boolean findFromMap(Class<? extends JbootEventListener> listenerClass, Map<String, List<JbootEventListener>> map) { 166 for (Map.Entry<String, List<JbootEventListener>> entry : map.entrySet()) { 167 List<JbootEventListener> listeners = entry.getValue(); 168 if (listeners == null || listeners.isEmpty()) { 169 continue; 170 } 171 for (JbootEventListener ml : listeners) { 172 if (listenerClass == ml.getClass()) { 173 return true; 174 } 175 } 176 } 177 return false; 178 } 179 180 public void publish(final JbootEvent event) { 181 String action = event.getAction(); 182 183 List<JbootEventListener> syncListeners = listenerMap.get(action); 184 if (syncListeners != null && !syncListeners.isEmpty()) { 185 invokeListeners(event, syncListeners); 186 } 187 188 List<JbootEventListener> listeners = asyncListenerMap.get(action); 189 if (listeners != null && !listeners.isEmpty()) { 190 invokeListenersAsync(event, listeners); 191 } 192 193 } 194 195 private void invokeListeners(final JbootEvent event, List<JbootEventListener> syncListeners) { 196 for (final JbootEventListener listener : syncListeners) { 197 try { 198 listener.onEvent(event); 199 } catch (Throwable e) { 200 LOG.error(String.format("listener[%s] onEvent is error! ", listener.getClass()), e); 201 } 202 } 203 } 204 205 private void invokeListenersAsync(final JbootEvent event, List<JbootEventListener> listeners) { 206 for (final JbootEventListener listener : listeners) { 207 threadPool.execute(() -> { 208 try { 209 listener.onEvent(event); 210 } catch (Throwable e) { 211 LOG.error(String.format("listener[%s] onEvent is error! ", listener.getClass()), e); 212 } 213 }); 214 } 215 } 216 217 public ExecutorService getThreadPool() { 218 return threadPool; 219 } 220 221 public void setThreadPool(ExecutorService threadPool) { 222 this.threadPool = threadPool; 223 } 224}