spring发布和接收定制的事件(spring事件传播)

spring发布和接收定制的事件(spring事件传播)

有事件,即有事件监听器. 有人问你spring监听器有哪些你看了下文即也知道了。   事件传播 ApplicationContext基于Observer模式(java.util包中有对应实现),提供了针对Bean的事件传 播功能。通过Application. publishEvent方法,我们可以将事件通知系统内所有的 ApplicationListener。   事件传播的一个典型应用是,当Bean中的操作发生异常(如数据库连接失败),则通过事件传播 机制通知异常监听器进行处理。在笔者的一个项目中,就曾经借助事件机制,较好的实现了当系统 异常时在监视终端上报警,同时发送报警SMS至管理员手机的功能。  

ApplicationContext容器提供了容器内部事件发布功能,是继承自JavaSE标准自定义事件类而实现的。

JavaSE标准自定义事件结构不在此详细描述,一张图很直观的描述清楚:

www.zeeklog.com  - spring发布和接收定制的事件(spring事件传播)

EventObject,为JavaSE提供的事件类型基类,任何自定义的事件都继承自该类,例如上图中右侧灰色的各个事件。Spring中提供了该接口的子类ApplicationEvent。

EventListener为JavaSE提供的事件监听者接口,任何自定义的事件监听者都实现了该接口,如上图左侧的各个事件监听者。Spring中提供了该接口的子类ApplicationListener接口。

JavaSE中未提供事件发布者这一角色类,由各个应用程序自行实现事件发布者这一角色。Spring中提供了ApplicationEventPublisher接口作为事件发布者,并且ApplicationContext实现了这个接口,担当起了事件发布者这一角色。但ApplicationContext在具体实现上有所差异,Spring提供了ApplicationEventMulticaster接口,负责管理ApplicationListener和发布ApplicationEvent。ApplicationContext会把相应的事件相关工作委派给ApplicationEventMulticaster接口实现类来做。类图如下所示:

www.zeeklog.com  - spring发布和接收定制的事件(spring事件传播)


事件发布时序图如下:


 

www.zeeklog.com  - spring发布和接收定制的事件(spring事件传播)

-------------------------------------------------------------------------------------------------

Spring中提供一些Aware相关的接口,BeanFactoryAware、 ApplicationContextAware、ResourceLoaderAware、ServletContextAware等等,其中最常用到的是ApplicationContextAware。实现ApplicationContextAware的Bean,在Bean被初始后,将会被注入ApplicationContext的实例。ApplicationContextAware提供了publishEvent()方法,实现Observer(观察者)设计模式的事件传播机,提供了针对Bean的事件传播功能。通过Application.publishEvent方法,我们可以将事件通知系统内所有的ApplicationListener。

Spring事件处理一般过程:

◆定义Event类,继承org.springframework.context.ApplicationEvent。
◆编写发布事件类Publisher,实现org.springframework.context.ApplicationContextAware接口。
◆覆盖方法setApplicationContext(ApplicationContext applicationContext)和发布方法publish(Object obj)。
◆定义时间监听类EventListener,实现ApplicationListener接口,实现方法onApplicationEvent(ApplicationEvent event)。  1.发布         1.1事件的发布者需要实现的接口             org.springframework.context.ApplicationEventPublisherAware         1.2 代码示例

import org.springframework.context.ApplicationEventPublisher;import org.springframework.context.ApplicationEventPublisherAware; /** *  * @author zq * */public class HelloWorld implements ApplicationEventPublisherAware{ private String word; private ApplicationEventPublisher tradeEventPublisher;  public void setWord(String w){  this.word = w; }  public void say(){  System.out.println("say : "+ this.word);  //construct a TradeEvent instance and publish it  TradeEvent tradeEvent = new TradeEvent(new String("tradeEvent"));  this.tradeEventPublisher.publishEvent(tradeEvent); }  @Override public void setApplicationEventPublisher(   ApplicationEventPublisher applicationEventPublisher) {  // TODO Auto-generated method stub  this.tradeEventPublisher = applicationEventPublisher; }} 2.接受事件      2.1需要实现的接口org.springframework.context.ApplicationListener       2.2代码示例

import org.springframework.context.ApplicationEvent;import org.springframework.context.ApplicationListener;import org.springframework.context.event.ContextStartedEvent; public class TradeContextListener implements ApplicationListener{  @Override public void onApplicationEvent(ApplicationEvent e) {    System.out.println(e.getClass().toString());  // TODO Auto-generated method stub  if (e instanceof ContextStartedEvent){   System.out.println("it was contextStartedEvent");  }    if (e instanceof TradeEvent){   System.out.println(e.getSource());  }   } } 3配置文件

<?xml version="1.0" encoding="utf-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans> <bean name="helloWorld" class="study.HelloWorld">  <property name="word" value="hello world"/> </bean>  <bean id="tradeContextListener" class="study.TradeContextListener"/></beans> 4.测试代码

import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext; import study.HelloWorld;public class TestHelloWorld {  /**  * @param args  */ public static void main(String[] args) {  // TODO Auto-generated method stub    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("study-context.xml");  HelloWorld bean = (HelloWorld)applicationContext.getBean("helloWorld");  bean.say(); } }    Spring中ApplicationContext的事件机制--- 内定事件) 在Spring中已经定义了五个标准事件,分别介绍如下:

1)      ContextRefreshedEvent:当ApplicationContext初始化或者刷新时触发该事件。

2)      ContextClosedEvent:当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁。

3)      RequestHandleEvent:在Web应用中,当一个http请求(request)结束触发该事件。

ContestStartedEvent:Spring2.5新增的事件,当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。

5) ContestStopedEvent:Spring2.5新增的事件,当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。

下面通过一个例子展示如何处理Spring内定的事件(例程3.8)。创建一个Java工程,添加Spring开发能力后,新建ioc.test包。在包中新建ApplicationEventListener类,实现ApplicationListener接口,在onApplicationEvent()方法中添加事件处理代码,如下:  1 package  ioc.test;
 2
 3 // Import省略
 4 public class  ApplicationEventListener implements  ApplicationListener {
 5
 6 public void  onApplicationEvent(ApplicationEvent event) {
 7
 8 // 如果是容器刷新事件
 9 if (event instanceof  ContextClosedEvent ){
 10             System.out.println(event.getClass().getSimpleName() + "  事件已发生! " );  
 11         } else if (event instanceof  ContextRefreshedEvent ){ // 如果是容器关闭事件
 12             System.out.println(event.getClass().getSimpleName() + "  事件已发生! " );  
 13         } else if (event instanceof  ContextStartedEvent ){
 14             System.out.println(event.getClass().getSimpleName() + "  事件已发生! " );
 15         } else if (event instanceof  ContextStoppedEvent){
 16             System.out.println(event.getClass().getSimpleName() + "  事件已发生! " );
 17         } else {
 18             System.out.println( " 有其它事件发生: " + event.getClass().getName());
 19         }
 20                    
 21     }
 22
 23 }
 24

在Spring配置文件中定义一个Bean,类为ApplicationEventListener,代码如下:  1 <? xml version="1.0" encoding="UTF-8" ?>
 2 < beans …………  
 3
 4    <bean id ="ApplicationEventListener"  class ="ioc.test.ApplicationEventListener" />
 5
 6 </ beans >
 7

添加含有主方法的TesMain类,在主方法中,调用容器的相应方法,触发Spring内定事件,代码如下:  1 package  ioc.test;
 2
 3 // import省略
 4 public class  TesMain {
 5
 6 public static void  main(String[] args) {
 7         AbstractApplicationContext ac = new  ClassPathXmlApplicationContext( " applicationContext.xml " );
 8        
 9
 10 //     ac.refresh(); // 触发ContextRefreshedEvent事件            
 11         ac.start(); // 触发ContextStartedEvent事件
 12         ac.stop();  // 触发ContextStoppedEvent事件        
 13         ac.close(); // 关闭容器,触发ContextClosedEvent事件
 14
 15     }
 16 }
 17

运行主类,控制台输出如下:

www.zeeklog.com  - spring发布和接收定制的事件(spring事件传播)


从例子中可以知道,要注册事件监听器,我们只需要把它配置成一个Bean即可,ApplicationContext容器会自动将其注册。

Read more

深入理解 Proxy 和 Object.defineProperty

在JavaScript中,对象是一种核心的数据结构,而对对象的操作也是开发中经常遇到的任务。在这个过程中,我们经常会使用到两个重要的特性:Proxy和Object.defineProperty。这两者都允许我们在对象上进行拦截和自定义操作,但它们在实现方式、应用场景和灵活性等方面存在一些显著的区别。本文将深入比较Proxy和Object.defineProperty,包括它们的基本概念、使用示例以及适用场景,以帮助读者更好地理解和运用这两个特性。 1. Object.defineProperty 1.1 基本概念 Object.defineProperty 是 ECMAScript 5 引入的一个方法,用于直接在对象上定义新属性或修改已有属性。它的基本语法如下: javascript 代码解读复制代码Object.defineProperty(obj, prop, descriptor); 其中,obj是目标对象,prop是要定义或修改的属性名,descriptor是一个描述符对象,用于定义属性的特性。 1.2 使用示例 javascript 代码解读复制代码//

By Ne0inhk

Proxy 和 Object.defineProperty 的区别

Proxy 和 Object.defineProperty 是 JavaScript 中两个不同的特性,它们的作用也不完全相同。 Object.defineProperty 允许你在一个对象上定义一个新属性或者修改一个已有属性。通过这个方法你可以精确地定义属性的特征,比如它是否可写、可枚举、可配置等。该方法的使用场景通常是需要在一个对象上创建一个属性,然后控制这个属性的行为。 Proxy 也可以用来代理一个对象,但是相比于 Object.defineProperty,它提供了更加强大的功能。使用 Proxy 可以截获并重定义对象的基本操作,比如访问属性、赋值、函数调用等等。在这些操作被执行之前,可以通过拦截器函数对这些操作进行拦截和修改。因此,通过 Proxy,你可以完全重写一个对象的默认行为。该方法的使用场景通常是需要对一个对象的行为进行定制化,或者需要在对象上添加额外的功能。 对比 以下是 Proxy 和 Object.defineProperty 的一些区别对比: 方面ProxyObject.defineProperty语法使用 new Proxy(target,

By Ne0inhk