在Spring中发布自定义事件

在Java中,事件机制的实现包括三个基本组件,事件、事件发布者和事件监听者。在Spring中,事件机制的实现也同样包括这三个基本组件,但 Spring框架对这些组件实现了高层封装和抽象,使得事件的发布过程非常的简单,而且降低了组件之间的耦合性。但事情总没有完美的,事件组件和 Spring框架之间的耦合则不可避免。不管怎样,Spring还是帮助我们简单而优雅的实现了事件机制。下面就来看看如何在Spring中实现自定义事 件的发布和监听。
 

   假设这样一个场景:新学期开了一门新课,学生要通过注册取得上课的资格,课程不可能接受太多的学生,当注册人数达到一定数量后,就不再允许注册这门课程了(我们这门新课只接受7个学生,先到先得哦在Spring中发布自定义事件)。
    先实现和事件没关系的组件——课程,代码如下:
public class Course {
    public static final int MAX_CAPACITY = 7;
    private int capacity = 0;
    public Course() {}
    public int getCapacity() {
        return capacity;
    }
    public void addNewStudent() {
        this.capacity++;
    }
}
    接着实现事件的三个基本组件,首先事件是事件机制的核心,先实现它。这里实现了两个事件RegisteredEvent和 CourseFullEvent,分别表示注册成功事件和课程已满事件。在Spring中,所有事件都继承自抽象类ApplicationEvent。我 们不需要这两个事件做什么,所以它们的代码很简单。
public class RegisteredEvent extends ApplicationEvent {
    public RegisteredEvent(Object arg0) {
        super(arg0);
    }
}
public class CourseFullEvent extends ApplicationEvent {
    public CourseFullEvent(Object arg0) {
        super(arg0);
    }
}
    第二个组件是事件发布者,也就是课程注册服务。在Spring中发布事件当然要通过容器来发布,这样容器内的监听器组件才会知道事件发生了。 BeanFactory容器没有发布事件的功能,所以就要用特性更为丰富的ApplicationContext。而容器中的Java对象要想知道它所在 的容器,就一定要实现ApplicationContextAware接口,因此这个对象就难免要和Spring框架建立联系了,为了实现发布事件的功 能,与框架的耦合在所难免。
public interface StudentService {
    void register(Course course, Student student);
}
public class StudentServiceImpl implements StudentService,
        ApplicationContextAware {
    private ApplicationContext context;
    public void setApplicationContext(ApplicationContext arg0)
            throws BeansException {
        this.context = arg0;
    }
    public void register(Course course, Student student) {
        int capacity = course.getCapacity();
        if (++capacity > Course.MAX_CAPACITY) {
            System.out.println("该课程已经人满,注册失败");
            context.publishEvent(new CourseFullEvent(this));
        } else {
            course.addNewStudent();
            student.setStudentId(course.getCapacity());
            System.out.println("恭喜您,注册成功");
            context.publishEvent(new RegisteredEvent(this));
        }
    }
}
Spring容器会自动地通过set方法把自己注入到实现了ApplicationContextAware接口的对象中,这样 StudentService的实现就可以通过所在的容器发布任何事件了,很简单,调用容器的publishEvent方法并传入所要发布的事件就行了。
    最后要实现的组件就是监听者了,也就是Student,它实现了ApplicationListener接口,并把自己注册到Spring容器中。当事件 发生时,容器会通知它里面的监听者,Student收到事件通知,在onApplicationEvent方法中,判断事件类型,并对事件做出响应。 Student的代码如下:
public class Student implements ApplicationListener {
    private int studentId;

    public Student() {}

    public void onApplicationEvent(ApplicationEvent arg0) {
        if (arg0 instanceof RegisteredEvent) {
            System.out.println("太好了,我注册的学号是" + this.studentId);
        } else if (arg0 instanceof CourseFullEvent) {
            System.out.println("来晚了,我没注册上");
        }
    }

    public void setStudentId(int studentId) {
        this.studentId = studentId;
    }
}
    当然,别忘了Spring的配置文件:
<beans>
    <bean id="student" class="com.Student" />

    <bean id="course" class="com.Course" />

    <bean id="studentService"
        class="com.StudentServiceImpl" />
</beans>
    最后,写个小应用运行一下,看看效果如何:
public class SpecialBeanApp {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext(
                "applicationContext.xml");

        // 开一门课
        Course course = (Course) ctx.getBean("course");

        // 开启注册课程的服务
        StudentService service = (StudentService) ctx.getBean("studentService");

        // 注册10个学生
        for (int i = 0; i < 10; i++) {
            Student student = (Student) ctx.getBean("student");
            service.register(course, student);
        }
    }
}
    最后再说明一点,Spring的事件机制是同步的,也就是阻塞式的,所以,对事件的处理要尽量简单快捷,否则会极大的影响应用程序的性能。我们期待着Spring2.0的后续版本能实现异步的事件机制。

转载于:https://www.cnblogs.com/kinbos/archive/2013/02/27/2934650.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值