简单的异步框架实现
枚举事件类型
public enum EventType {
LIKE(0),
COMMENT(1),
LOGIN(2),
MAIL(3);
private int value;
EventType(int value) { this.value = value; }
public int getValue() { return value; }
}
定义事件模型
public class EventModel {
private EventType type; //事件类型
private int actorId; //执行者ID
private int entityType;
private int entityId;
private int entityOwnerId;
private Map<String, String> exts = new HashMap<String, String>(); //额外内容
public EventModel() {
}
public EventModel setExt(String key, String value) {
exts.put(key, value);
return this;
}
public EventModel(EventType type) {
this.type = type;
}
public String getExt(String key) {
return exts.get(key);
}
public EventType getType() {
return type;
}
public EventModel setType(EventType type) {
this.type = type;
return this;
}
public int getActorId() {
return actorId;
}
public EventModel setActorId(int actorId) {
this.actorId = actorId;
return this;
}
public int getEntityType() {
return entityType;
}
public EventModel setEntityType(int entityType) {
this.entityType = entityType;
return this;
}
public int getEntityId() {
return entityId;
}
public EventModel setEntityId(int entityId) {
this.entityId = entityId;
return this;
}
public int getEntityOwnerId() {
return entityOwnerId;
}
public EventModel setEntityOwnerId(int entityOwnerId) {
this.entityOwnerId = entityOwnerId;
return this;
}
public Map<String, String> getExts() {
return exts;
}
public EventModel setExts(Map<String, String> exts) {
this.exts = exts;
return this;
}
}
事件生产者
@Service
public class EventProducer {
@Autowired
JedisAdapter jedisAdapter;
public boolean fireEvent(EventModel eventModel) {
try {
String json = JSONObject.toJSONString(eventModel); //以json形式保存事件在redis中,使用Alibaba的fastjson
String key = RedisKeyUtil.getEventQueueKey();
jedisAdapter.lpush(key, json);
return true;
} catch (Exception e) {
return false;
}
}
}
redis操作
封装对redis的操作
@Service
public class JedisAdapter implements InitializingBean { //服务器开启时便初始化
private static final Logger logger = LoggerFactory.getLogger(JedisAdapter.class);
private JedisPool pool; //使用jedis接口连接redis
@Override
public void afterPropertiesSet() throws Exception {
pool = new JedisPool("redis://localhost:6379/10");
}
public long sadd(String key, String value) {
Jedis jedis = null;
try {
jedis = pool.getResource();
return jedis.sadd(key, value);
} catch (Exception e) {
logger.error("发生异常" + e.getMessage());
} finally {
if (jedis != null) {
jedis.close();
}
}
return 0;
}
public long srem(String key, String value) {
Jedis jedis = null;
try {
jedis = pool.getResource();
return jedis.srem(key, value);
} catch (Exception e) {
logger.error("发生异常" + e.getMessage());
} finally {
if (jedis != null) {
jedis.close();
}
}
return 0;
}
public long scard(String key) {
Jedis jedis = null;
try {
jedis = pool.getResource();
return jedis.scard(key);
} catch (Exception e) {
logger.error("发生异常" + e.getMessage());
} finally {
if (jedis != null) {
jedis.close();
}
}
return 0;
}
public boolean sismember(String key, String value) {
Jedis jedis = null;
try {
jedis = pool.getResource();
return jedis.sismember(key, value);
} catch (Exception e) {
logger.error("发生异常" + e.getMessage());
} finally {
if (jedis != null) {
jedis.close();
}
}
return false;
}
public List<String> brpop(int timeout, String key) {
Jedis jedis = null;
try {
jedis = pool.getResource();
return jedis.brpop(timeout, key);
} catch (Exception e) {
logger.error("发生异常" + e.getMessage());
} finally {
if (jedis != null) {
jedis.close();
}
}
return null;
}
public long lpush(String key, String value) {
Jedis jedis = null;
try {
jedis = pool.getResource();
return jedis.lpush(key, value);
} catch (Exception e) {
logger.error("发生异常" + e.getMessage());
} finally {
if (jedis != null) {
jedis.close();
}
}
return 0;
}
}
定义事件处理接口
事件处理器实现该接口
public interface EventHandler {
void doHandle(EventModel model); //具体处理事件的实际操作
List<EventType> getSupportEventTypes(); // 可处理的事件类型
}
事件消费者定义
实现InitializingBean接口为了初始化,实现ApplicationContextAware为了获得应用容器ApplicationContext
@Service
public class EventConsumer implements InitializingBean, ApplicationContextAware {
private static final Logger logger = LoggerFactory.getLogger(EventConsumer.class);
private Map<EventType, List<EventHandler>> config = new HashMap<EventType, List<EventHandler>>();
private ApplicationContext applicationContext;
@Autowired
JedisAdapter jedisAdapter;
@Override
public void afterPropertiesSet() throws Exception {
Map<String, EventHandler> beans = applicationContext.getBeansOfType(EventHandler.class);//扫描获得容器中所实现EventHandler接口的类
if (beans != null) {
for (Map.Entry<String, EventHandler> entry : beans.entrySet()) {
List<EventType> eventTypes = entry.getValue().getSupportEventTypes();//获得事件处理器可处理的事件类型
for (EventType type : eventTypes) {
if (!config.containsKey(type)) {
config.put(type, new ArrayList<EventHandler>());
}
config.get(type).add(entry.getValue());
}
}
}
Thread thread = new Thread(new Runnable() { //创建一个线程处理事件
@Override
public void run() {
while(true) {
String key = RedisKeyUtil.getEventQueueKey();
List<String> events = jedisAdapter.brpop(0, key); //从redis中取出事件进行处理
for (String message : events) {
if (message.equals(key)) {
continue;
}
EventModel eventModel = JSON.parseObject(message, EventModel.class);
if (!config.containsKey(eventModel.getType())) {
logger.error("不能识别的事件");
continue;
}
for (EventHandler handler : config.get(eventModel.getType())) {
handler.doHandle(eventModel);
}
}
}
}
});
thread.start();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
例:登录事件定义
@Component
public class LoginExceptionHandler implements EventHandler {
@Autowired
MailSender mailSender;
@Override
public void doHandle(EventModel model) {
// xxxx判断发现这个用户登陆异常
Map<String, Object> map = new HashMap<String, Object>();
map.put("username", model.getExt("username"));
mailSender.sendWithHTMLTemplate(model.getExt("email"), "登陆IP异常", "mails/login_exception.html", map);
}
@Override
public List<EventType> getSupportEventTypes() {
return Arrays.asList(EventType.LOGIN);
}
}
连接控制器
@Controller
public cliass LoginController{
@RequestMapping(path = {"/login/"}, method = {RequestMethod.POST})
public String login(Model model, @RequestParam("username") String username,
@RequestParam("password") String password,
@RequestParam(value="next", required = false) String next,
@RequestParam(value="rememberme", defaultValue = "false") boolean rememberme,
HttpServletResponse response) {
try {
Map<String, Object> map = userService.login(username, password);
if (map.containsKey("ticket")) {
Cookie cookie = new Cookie("ticket", map.get("ticket").toString());
cookie.setPath("/");
if (rememberme) {
cookie.setMaxAge(3600*24*5);
}
response.addCookie(cookie);
eventProducer.fireEvent(new EventModel(EventType.LOGIN)
.setExt("username", username).setExt("email", "1029472275@qq.com")
.setActorId((int)map.get("userId"))); //生成事件并存入redis中
if (StringUtils.isNotBlank(next)) {
return "redirect:" + next;
}
return "redirect:/";
} else {
model.addAttribute("msg", map.get("msg"));
return "login";
}
} catch (Exception e) {
logger.error("登陆异常" + e.getMessage());
return "login";
}
}
}