CDI services--Event(事件)
Cdi中的event事件,是整个CDI的精华所在之一.其有点类似设计模式中的观察者模式.但也有不同的地方.如下3点:
- 不仅是生产者(producers)从观察者(observers)解耦.观察者也从生产者解耦.
- 观察者可以指定“选择器”的组合来缩小的事件通知
- 观察者可以立即通知,或者可以指定交付的事件应该推迟到当前事务的结束。
即用一种维护生产者和观察者之间的分离代码的方式,来产生和订阅(即观察)在应用程序中发生的事件。使用 javax.enterprise.event.Event 类创建事件,并使用 CDI 的 @Observes 标注订阅处理事件。
1. Event payload(事件的有效载入)
事件对象只不过是一个具体的Java类的实例。
一个事件可指定限定符,观察者可以区别于其他相同类型的事件。
限定符的功能很像主题选择器, 允许限定符决定观察器将观察哪些事件。
使用@ qualifier定义的一个例子:
|
1
2
3
4
|
@Qualifier@Target({METHOD, FIELD, PARAMETER, TYPE})@Retention(RUNTIME)public @interface Updated {} |
另外,事件的创建和订阅是类型安全的.
2. Event observers(event的观察者)
一个观察者的处理方式是在方法中,加入一个参数注解@Observes.如下所示:
|
1
2
|
public void onAnyDocumentEvent(@Observes Document document){ ... } |
带注解的参数称为事件参数。事件的参数类型是观察到的事件类型。事件参数还可以指定限定符。如下:
|
1
|
public void afterDocumentUpdate(@Observes @Updated Document document) { ... } |
当然也可以有其他参数
|
1
|
public void afterDocumentUpdate(@Observes @Updated Document document, User user) { ... } |
3. Event producers(event生产者)
Event producers的fire事件是使用参数化Event interface的实例.如下,通过@Inject注入该接口的一个实例.
|
1
|
@Inject @Any Event<Document> documentEvent; |
而事件生产者通过调用fire()方法,并传递"事件对象"从而激活事件处理.
|
1
|
documentEvent.fire(document); |
通过事件对象的参数值,容器调用所有观察者的方法,如果任何观察者方法抛出一个异常,容器会停止调用观察者方法,异常将会由fire()方法抛出。
Qualifiers 在事件中应用方式有两种:
在event的注入点(Injection point)通过注解
|
1
|
@Inject @Updated Event<Document> documentUpdatedEvent; |
在观察者的处理方法中,通过事件对Qualifiers的选择.
|
1
|
public void afterDocumentUpdate(@Observes @Updated Document document) { ... } |
注解注入的缺点是,我们不能动态地指定限定符。
CDI也考虑到了这一点.
4.AnnotationLiteral动态注入对应事件
|
1
|
documentEvent.select(new AnnotationLiteral<Updated>(){}).fire(document); |
documentEvent注入点不用再使用限定符 @Updated. 这样可以在程序中判断后进行分支处理.
|
1
2
3
4
5
|
if(num==1){documentEvent.select(new AnnotationLiteral<Updated>(){}).fire(document);}else{documentEvent.select(new AnnotationLiteral<Other>(){}).fire(document);} |
事件可以有多个事件限定符,通过select()方法可以使用任意的注解组合在事件注入点和限定符实例上.
5.Conditional observer methods
默认情况下,在当前上下文如果没有一个观察者的实例,容器将为事件实例化观察者.
但我们希望传递给观察者的实例是已经存在于上下文中的观察者.
指定一个有条件的观察者的方式是在@Observes注释上添加receive = IF_EXISTS
|
1
|
public void refreshOnDocumentUpdate(@Observes(receive = IF_EXISTS) @Updated Document d) { ... } |
Note
A bean with scope @Dependent cannot be a conditional observer, since it would never be called!
6.Event qualifiers with members
|
1
2
3
4
5
6
7
|
@Qualifier@Target({METHOD, FIELD, PARAMETER, TYPE})@Retention(RUNTIME)public @interface Role { RoleType value();} |
可以通过注解的value值传递信息给observer.
|
1
|
public void adminLoggedIn(@Observes @Role(ADMIN) LoggedIn event) { ... } |
在事件注入点的使用
|
1
|
@Inject @Role(ADMIN) Event<LoggedIn> loggedInEvent; |
在AnnotationLiteral方式中的使用:
先定义一个AnnotationLiteral的抽象类
|
1
|
abstract class RoleBinding extends AnnotationLiteral<Role> implements Role {} |
通过select()方法的使用代码
|
1
2
3
|
documentEvent.select( new RoleBinding() {public void value() { return user.getRole(); }} ).fire(document); |
7.Multiple event qualifiers
qualifiers 是可以多重组合的.如下代码:
|
1
2
3
|
@Inject @Blog Event<Document> blogEvent;...if (document.isBlog()) blogEvent.select(new AnnotationLiteral<Updated>(){}).fire(document); |
下面所有这些观察方法将得到通知。
|
1
2
3
4
5
6
7
|
public void afterBlogUpdate(@Observes @Updated @Blog Document document) { ... }public void afterDocumentUpdate(@Observes @Updated Document document) { ... }public void onAnyBlogEvent(@Observes @Blog Document document) { ... }public void onAnyDocumentEvent(@Observes Document document) { ... }}} |
然而,如果还有一个观察者的方法:
|
1
|
public void afterPersonalBlogUpdate(@Observes @Updated @Personal @Blog Document document) { ... } |
它不会通知,因为@Personal并未包含在事件发生处.
8.事务性处理的transactional observers
事务处理的observers 在事务完成之前或之后的阶段才会收到事件通知.
例如,下面的观察方法需要在应用程序上下文中刷新一个查询的结果集,但是只有在 Category 更新成功才会执行:
|
1
|
public void refreshCategoryTree(@Observes(during = AFTER_SUCCESS) CategoryUpdateEvent event) { ... } |
一共有五种transactional observers:
IN_PROGRESS --- observers被立即通知 (default)
AFTER_SUCCESS --- 在事务成功完成后,observers会被通知.
AFTER_FAILURE --- 在事务完成失败后,observers会被通知.
AFTER_COMPLETION --- observers在交易完成后的阶段被调用
BEFORE_COMPLETION --- observers在交易完成前阶段被调用
在一个有状态的对象模型(stateful object model)中,Transactional observers是非常重要的.因为那些状态经常是长事务的.
想象一下,我们已经在application scope范围缓存一个JPA查询,
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
import javax.ejb.Singleton;import javax.enterprise.inject.Produces;@ApplicationScoped @Singletonpublic class Catalog { @PersistenceContext EntityManager em; List<Product> products; @Produces @Catalog List<Product> getCatalog() { if (products==null) { products = em.createQuery("select p from Product p where p.deleted = false").getResultList(); } return products; }} |
如果一个产品被创建或删除,我们需要重新整理产品目录,这个时候我们必须要等到这个更新的事务成功完成后.
创建和删除产品的Bean可以引发事件,例如:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
import javax.enterprise.event.Event;@Statelesspublic class ProductManager { @PersistenceContext EntityManager em; @Inject @Any Event<Product> productEvent; public void delete(Product product) { em.delete(product); productEvent.select(new AnnotationLiteral<Deleted>(){}).fire(product); } public void persist(Product product) { em.persist(product); productEvent.select(new AnnotationLiteral<Created>(){}).fire(product); } ...} |
在事务完成后,对产品目录用观察者的方法进行更新/删除
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import javax.ejb.Singleton;@ApplicationScoped @Singletonpublic class Catalog { ... void addProduct(@Observes(during = AFTER_SUCCESS) @Created Product product) { products.add(product); } void removeProduct(@Observes(during = AFTER_SUCCESS) @Deleted Product product) { products.remove(product); }} |
DEMO
概述流程:
A: event 主体
首先是2个事件. 1.run,跑 事件 2.walk,走 事件
页面触发这2个事件.首先在后台定义@Qualifier,对应每个事件. 在CDI中所有的对象和生产者都是限定类型的.所以需要指定具体的@Qualifier.而这里事件就2个,所以如下:
run.java
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.Target;import javax.inject.Qualifier;@Qualifier@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })@Retention(RUNTIME)@Documentedpublic @interface Run {} |
walk.java
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.Target;import javax.inject.Qualifier;import static java.lang.annotation.RetentionPolicy.RUNTIME;@Qualifier@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })@Retention(RUNTIME)@Documentedpublic @interface Walk {} |
定义好后,我们需要定义具体的事件处理的主题.也就是运动.不管是跑还是走,都是运动的一种.所以定义运动事件主体.
其实主要是因为在这里是自己想的一个CDI EVENT的场景,
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
import java.util.Date;public class ExerciseEvent { private String type; //walk or run private Long howfar; private Date datetime; public String getType() { return type; } public void setType(String type) { this.type = type; } public Long getHowfar() { return howfar; } public void setHowfar(Long howfar) { this.howfar = howfar; } public Date getDatetime() { return datetime; } public void setDatetime(Date datetime) { this.datetime = datetime; } @Override public String toString() { return "在"+this.datetime+",你"+this.type+"--"+(this.howfar.toString()); }} |
不忙处理页面,这个时候,我们应该对走还是跑做具体的处理.
分析一下,cdi的event处理,主要是2个,一个ob一个producer.现在,我们已经定义好了event.那么接着就是先处理observer.
CDI services--Event(事件)的更多相关文章
- CDI(Weld)高级<4> Event(事件) (转)
目录[-] 1. Event payload(事件的有效载入) 2. Event observers(event的观察者) 3. Event producers(event生产者) 4.Annotat ...
- CDI Services *Decoretions *Intercepters * Scope * EL\(Sp EL) *Eventmodel
1.Decorators装饰器综述 拦截器是一种强大的方法在应用程序捕捉运行方法和解耦.拦截器可以拦截任何java类型的调用. 这使得拦截器适合解决事务管理,安全性,以及日记记录. 本质上说,拦截 ...
- [.NET] C# 知识回顾 - Event 事件
C# 知识回顾 - Event 事件 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/6060297.html 序 昨天,通过<C# 知识回顾 - ...
- Event事件
妙味课堂-Event事件 1.焦点:当一个元素有焦点的时候,那么他就可以接受用户的输入(不是所有元素都能接受焦点) 给元素设置焦点的方式: 1.点击 2.tab 3.js 2.(例子:输入框提示文字) ...
- JS学习笔记9之event事件及其他事件
-->鼠标事件-->event事件对象-->默认事件-->键盘事件(keyCode)-->拖拽效果 一.鼠标事件 onclick ---------------鼠标点击事 ...
- JS(event事件)
常用的event事件: 属性 此事件发生在何时... onabort 图像的加载被中断. onblur 元素失去焦点. onchange 域的内容被改变. onclick 当用户点击某个对象时调用的事 ...
- event事件学习小节
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Javascript 事件对象(二)event事件
Event事件: <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" ...
- js event 事件兼容浏览器 ie不需要 event参数 firefox 需要
js event 事件兼容浏览器 ie不需要 event参数 firefox 需要 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 ...
随机推荐
- bool值的底层应用场景
这里我们的if 或者while,还有and,or,not 等都是在内部调用一个对象的bool方法,然后返回True或者是False, a = [0, ] # a = [] # print(bool(a ...
- web服务-3、epoll高效率实现并发服务器
知识点: 之前写的四种方法实现并发服务效率都还是低,早期的服务器采用的是select和poll方式,select这种方式的特点是轮询所有套接字去一个个看有没有事件发生,但是装套接字的列表长度是有限制的 ...
- 【JavaScrpt】JS之数组去重
var arr = [] var peoples = [ {id:1,name:'wang'}, {id:2,name:'zhang'}, {id:2,name:'zhang'}, ] for(let ...
- KaliLinuxNetHunter教程实施刷机解锁Bootloader
KaliLinuxNetHunter教程实施刷机解锁Bootloader 当用户将前面的工作都准备完成后,即可开始刷机.其中,整个刷机过程分为三个步骤,分别是解锁Bootloader.刷入第三方Rec ...
- open
open服务指的是封装的订单流接口,给外部第三方提供使用.(当然也可以区别的名字,我司这么叫而已,并且是用Java写的,谁晓得为什么不选择PHP来写)通过open api合作方就可以通过调用接口直接下 ...
- 获取验证码倒计时60s
倒计时函数: function time(btns) { if (wait == 0) { btns.css("background-color","#F84C02&qu ...
- SQLyog 最新版本12.5-64bit 完美破解,亲测可用!
声明:本文只是提供一个网络上找到的针对12.5版本的注册码使用方式做一个说明,不建议企业用户破解,有条件的还是希望大家购买原版.当然个人学习用的但又不想购买原版的,这里只是提供个途径,请勿用做商业用途 ...
- dup(dup2/dup3)
readme man~ NAME dup, dup2, dup3 - duplicate a file descriptor SYNOPSIS #include <unistd.h> in ...
- HTML入门6
这篇将简单会编写网页整体网站架构,通过HTML来表示网站结构. 标题<header>,通常顶部有个大标题或图标,是网站的主要常见信息,存在于每个网页 导航<nav>,通常包含菜 ...
- MySQL数据库下载安装和DataGrip的下载安装和破解
一: 数据库下载 地址:官网https://dev.mysql.com/downloads/file/?id=482771;如果参数id失效,就选择之前的版本,5.7就可以,太新的没人用,老的很稳定. ...