美文网首页程序员
如何实现Application event,观察者模式

如何实现Application event,观察者模式

作者: 杭宇_8ba6 | 来源:发表于2019-03-13 14:41 被阅读0次

    spring 事件为bean 与 bean之间传递消息。一个bean处理完了希望其余一个接着处理.这时我们就需要其余的一个bean监听当前bean所发送的事件.

    spring事件使用步骤如下:

    1.先自定义事件:你的事件需要继承 ApplicationEvent

    2.定义事件监听器: 需要实现 ApplicationListener

    3.使用容器对事件进行发布

    • 首先定义一个事件
    /**
     * @Title:
     * @Auther: hangyu
     * @Date: 2019/3/13
     * @Description
     * @Version:1.0
     */
    public class TestEvent extends ApplicationEvent {
    
        private String name;
    
        private String msg;
    
        public TestEvent(Object source){
            super(source);
        }
    
        public TestEvent(Object source, String name, String msg) {
            super(source);
            this.name = name;
            this.msg = msg;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    }
    
    • 其次定义事件监听
    /**
     * @Title:
     * @Auther: hangyu
     * @Date: 2019/3/13
     * @Description
     * @Version:1.0
     */
    @Component
    public class TestEventListener implements ApplicationListener<TestEvent> {
    
        @Async
        @Override
        public void onApplicationEvent(TestEvent testEvent) {
            System.out.println("姓名:"+testEvent.getName()+"得到消息:"+testEvent.getMsg());
        }
    }
    
    • 使用容器发布事件
    
    /**
     * @Title:
     * @Auther: hangyu
     * @Date: 2019/3/13
     * @Description
     * @Version:1.0
     */
    @Component
    public class TestEventPublisher {
    
        @Autowired
        private ApplicationContext applicationContext;
    
        public void pushlish(String name, String msg){
            applicationContext.publishEvent(new TestEvent(this, name,msg));
        }
    }
    
    • 测试事件是否能够生效
    /**
     * @Title:
     * @Auther: hangyu
     * @Date: 2019/3/13
     * @Description
     * @Version:1.0
     */
    @Configuration
    @ComponentScan("cn.*.event")
    public class EventConfig {
    }
    
    
    
    /**
     * @Title:
     * @Auther: hangyu
     * @Date: 2019/3/13
     * @Description
     * @Version:1.0
     */
    public class TestMain {
    
        private static AnnotationConfigApplicationContext context;
    
        public static void main(String[] args) {
            start();
        }
    
        private static void start() {
            if (context == null) {
                 context=new AnnotationConfigApplicationContext(EventConfig.class);
            }
            context.getBean(TestEventPublisher.class).pushlish("hangyu","申请退款!");
        }
    }
    
    输出打印结果

    最后有一个思考:ApplicationEvent事件执行部分和起一个TaskExecutor去执行 有啥区别吗?反正都是异步。

    可以这样实现;

     @Autowired
     private AsyncExecutor asyncExecutor;
    
    Executor executor = asyncExecutor.getAsyncExecutor();
    executor.execute(
               //具体业务
    });
    
    
    @Configuration
    @EnableAsync
    public class AsyncExecutor implements AsyncConfigurer {
    
    // 日志
    static final Logger logger = LoggerFactory.getLogger(AsyncExecutor.class);
    
    public Executor getAsyncExecutor() {
    
    ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    
    taskExecutor.setCorePoolSize(5);
    
    taskExecutor.setMaxPoolSize(10);
    
    taskExecutor.setQueueCapacity(20000);
    
    taskExecutor.setKeepAliveSeconds(120);
    
    taskExecutor.setAllowCoreThreadTimeOut(true);
    
    taskExecutor.initialize();
    
    return taskExecutor;
    }
    }
    

    还可以这样实现;

        <!-- 异步线程池 -->
        <bean id="taskExecutor"
              class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
            <!-- 核心线程数 -->
            <property name="corePoolSize" value="3" />
            <!-- 最大线程数 -->
            <property name="maxPoolSize" value="10" />
            <!-- 队列最大长度 >=mainExecutor.maxSize -->
            <property name="queueCapacity" value="25" />
            <!-- 线程池维护线程所允许的空闲时间 -->
            <property name="keepAliveSeconds" value="300" />
            <!-- 线程池对拒绝任务(无线程可用)的处理策略 ThreadPoolExecutor.CallerRunsPolicy策略 ,调用者的线程会执行该任务,如果执行器已关闭,则丢弃.  -->
            <property name="rejectedExecutionHandler">
                <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
            </property>
        </bean>
    
     @Resource
     private TaskExecutor taskExecutor;
    
     taskExecutor.execute(new Runnable() {
                @Override
                public void run() {
                  //具体业务
                }
    }
    
    这就是注解方式和直接引用方式,本质是一样的

    我的思考:ApplicationEvent是观察者设计模式,这种设计模式使得主题和观察者之间的耦合度降低,松耦合是面向对象设计中很重要的一个原则,最终也是使用@Async来实现异步。而TaskExecutor则是启动一个线程池任务异步执行任务,两者效果一样,但原理不同。

    通过我的思考,又带来一个疑问:那观察者模式是不是就是我们MQ中的发布订阅模式呢?只不过观察者模式是进程内的,而MQ是跨进程的?就这唯一的区别吗?

    经过一些资料的查阅:大多数地方观察者模式约等于发布订阅模式,但是观察者模式是由具体目标调度的,而发布/订阅模式是统一由调度中心调的,所以观察者模式的订阅者与发布者之间是存在依赖的,而发布/订阅模式则不会。
    所以说观察者模式是小米加步枪,发布订阅模式是95式自动步枪,是它的进化版!

    相关文章

      网友评论

        本文标题:如何实现Application event,观察者模式

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