美文网首页java
基于guava event的事件机制

基于guava event的事件机制

作者: AbsurdOS | 来源:发表于2017-06-25 15:05 被阅读170次

    我们知道有很多业务场景下,大量繁琐的次流程需要处理,比如更新索引等操作。但是这样一来业务主流程和次流程揉在一起显得就没那么干净。如果一些比较重的东西可能使用mq来做比较好,但是我这里就讲一下比较轻量级的做法。利用guava event来处理一些次流程。
    首先我们先看下guava event的最小demo

    final EventBus eventBus = new EventBus();
            eventBus.register(new Object(){
                @Subscribe
                public void lister(Integer integer) {
                    System.out.printf("%s from int%n", integer);
                }
            });
            eventBus.post(1);
    

    我们一个个来看,EventBus其实是运用了观察者模式,我们往他注册一个事件订阅者,只要事件被投递,投入的类型相匹配就会被订阅者处理。如果是异步的事件

    ExecutorService executorService = Executors.newFixedThreadPool( 2 * Runtime.getRuntime().availableProcessors());
            final AsyncEventBus asyncEventBus = new AsyncEventBus(executorService);
            asyncEventBus.register(new Object(){
                @Subscribe
                public void listerLong(Long num) {
                    System.out.printf("%s from long%n", num);
                }
            });
            asyncEventBus.post(1L);
    

    现在我们把它和spring相结合,让spring托管事件
    EventBus注入spring容器

    @Configuration
    public class EventBusConfig {
        @Bean
        public EventBus eventBus(){
            return new EventBus();
        }
    
        @Bean
        public AsyncEventBus asyncEventBus(){
            return new AsyncEventBus(Global.executors);
        }
    }
    
    

    注册带有@Subscribe的bean

    @Component
    public class EventPostProcessor implements BeanPostProcessor{
        @Autowired
        private EventBus eventBus;
    
        @Autowired
        private AsyncEventBus asyncEventBus;
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            Field[] fields = bean.getClass().getFields();
            Method[] methods = bean.getClass().getDeclaredMethods();
            if (methods == null || methods.length == 0) {
                return bean;
            }
            for (Method method : methods){
                Subscribe subscribe =  method.getAnnotation(Subscribe.class);
                if (subscribe == null) continue;
                eventBus.register(bean);
                asyncEventBus.register(bean);
            }
    
    
    
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            Method[] methods = bean.getClass().getDeclaredMethods();
            if (methods == null || methods.length == 0) {
                return bean;
            }
            return bean;
        }
    }
    

    统一抽象事件实体

    @Data
    public class Event {
        private List<Object> data;
    
        private String operator;
    
    }
    
    

    事件订阅者

    public interface Handler {
        @Subscribe
        void handler(Event event);
    }
    

    自定义注解

    @Retention(value = RetentionPolicy.RUNTIME)
    @Target(value = {ElementType.METHOD,ElementType.TYPE})
    public @interface GuavaEvent {
        boolean enable() default true;
    
        String value();
    
        GuavaEventPostEnum advice() default GuavaEventPostEnum.AFTER;
    
        boolean async() default true;
    }
    
    public enum GuavaEventPostEnum {
        BEFORE,AFTER
    }
    

    自定义注解处理器

    @Aspect
    @Component
    public class GuavaEventResolver {
        @Autowired
        private EventBus eventBus;
        @Autowired
        private AsyncEventBus asyncEventBus;
    
        @Pointcut("@annotation(com.absurd.rick.annotation.GuavaEvent)")
        public void execute(){}
    
        @Before(value = "execute()")
        public void handlerEventBefore(JoinPoint joinPoint){
            MethodSignature ms = (MethodSignature) joinPoint.getSignature();
            Method method = ms.getMethod();
            GuavaEvent guavaEvent = method.getAnnotation(GuavaEvent.class);
            if (guavaEvent == null) {
                return;
            }
    
            if (!guavaEvent.enable()) return;
            if (GuavaEventPostEnum.BEFORE.equals(guavaEvent.advice())){
                postEvent(guavaEvent,joinPoint.getArgs());
            }
    
        }
    
        @AfterReturning(value = "execute()")
        public void handlerEventAfter(JoinPoint joinPoint){
            MethodSignature ms = (MethodSignature) joinPoint.getSignature();
            Method method = ms.getMethod();
            GuavaEvent guavaEvent = method.getAnnotation(GuavaEvent.class);
            if (guavaEvent == null) {
                return;
            }
    
            if (!guavaEvent.enable()) return;
            if (GuavaEventPostEnum.AFTER.equals(guavaEvent.advice())){
                postEvent(guavaEvent,joinPoint.getArgs());
            }
    
        }
    
        private void postEvent(GuavaEvent guavaEvent, Object[] args) {
            Event event = new Event();
            event.setOperator(guavaEvent.value());
            List<Object> data = new ArrayList<Object>();
            if (args == null || args.length == 0) {
                event.setData(data);
            }
            for (Object arg : args) {
                data.add(arg);
            }
            event.setData(data);
            event.setOperator(guavaEvent.value());
    
            if (guavaEvent.async()){
                asyncEventBus.post(event);
            }else{
                eventBus.post(event);
            }
    
        }
    
    }
    

    如何使用?
    业务方法上注解

        @GuavaEvent(value = "auth.login")
        String login(String username, String password);
    

    实现Handler

    @Slf4j
    @Component
    public class EventHandler implements Handler{
        @Subscribe
        @Override
        public void handler(Event event) {
            List<Object> args = event.getData();
            String operator = event.getOperator();
            switch (operator){
                case "auth.login":
                    log.info("{},{}",args.get(0),args.get(1));
                    break;
                case "car.get":
                    log.info("{}",args.get(0));
                    break;
                default:
                    break;
            }
    
        }
    }
    

    event.getData()就是方法的参数

    github地址:https://github.com/www1350/Rick

    实际运用中还发现了有些需要被同步变量的异步事件,做了一个兼容

    @Data
    public class Event {
        private List<Object> data;
    
        private String operator;
    
        private Map<String,Object> extraData;
    }
    
    
    public interface EventSyncExtra {
        Object getExtra();
    
        void setExtra(Object extra);
    }
    

    GuavaEventResolver的postEvent

            Collection<Object> eventSyncs = SpringContextUtil.getBeanByType(EventSyncExtra.class);
            for(Object eventSync : eventSyncs){
                if (eventSync instanceof EventSyncExtra){
                    extraMap.put(eventSync.getClass().getName(),((EventSyncExtra)eventSync).getExtra());
                }
            }
    
    public interface Handler {
        default void initExtra(Event event){
            Map<String,Object> map =  event.getExtraData();
            Collection<Object> eventSyncs = SpringContextUtil.getBeanByType(EventSyncExtra.class);
            for(Object eventSync : eventSyncs){
                if (eventSync instanceof EventSyncExtra){
                    EventSyncExtra eventSyncExtra =  (EventSyncExtra) eventSync;
                    eventSyncExtra.setExtra(map.get(eventSync.getClass().getName()));
                }
            }
        }
    
        @Subscribe
        void handler(Event event);
    }
    

    运用

    @Component
    public class AuthEventSyncExtra  implements EventSyncExtra{
        @Override
        public Object getExtra() {
            return AuthHolder.getThreadMap();
        }
    
        @Override
        public void setExtra(Object extra) {
            AuthHolder.set((Map<String, Object>)extra);
    
        }
    }
    
    @Slf4j
    @Component
    public class EventHandler implements Handler{
        @Subscribe
        @Override
        public void handler(Event event) {
            initExtra(event);
            List<Object> args = event.getData();
            String operator = event.getOperator();
            switch (operator){
                case "auth.login":
                    log.info("{},{}",args.get(0),args.get(1));
                    break;
                case "car.get":
                    log.info("{}",args.get(0));
                    log.info(AuthHolder.username());
                    break;
                default:
                    break;
            }
    
        }
    }
    

    相关文章

      网友评论

        本文标题:基于guava event的事件机制

        本文链接:https://www.haomeiwen.com/subject/grqrcxtx.html