文档库 最新最全的文档下载
当前位置:文档库 › Vert.X学习笔记

Vert.X学习笔记

Vert.X学习笔记
Vert.X学习笔记

1.基本概念

Verticle:Vert.x的代码执行包,它可以用JS、Ruby等多语言来编写,在同一个Vert.x实例中可以同时执行多个Verticl e,一个应用可能由多个Verticle组成,他们被部署到不同的网络节点上,彼此之间通过在Vert.x的事件总线(event bus)上交换信息来通信。对于具体的verticle可以直接从命令行启动,但是通常会将它打包成modules。

Module:Vert.X是由一个或多个的Module组合而成,一个模块由多个Verticle来组成,

Event Loops:即事件循环,是由Vert.x启动的事件处理线程,也是Vert.x项目对外开放的入口,Vert.x由此接收请求事件。一个Vert.x有一个或多个事件循环线程组成,线程最大数量为主机有效的CPU核数。

Event Loop Vertical:事件的业务处理线程,存在于Event Loop中,用于处理非阻塞短任务。

Worker Vertical : 事件的业务处理线程,用于处理长任务阻塞任务。

Event Bus:它是Vert.X的核心,在集群中容器之间的通信,各个Verticle之间的通讯都是经过Event Bus来实现的,后期会推出一篇专门关于这个的文章,敬请等待。

Shared Data:它是Vert.X提供的一个简单共享Map和Set,用来解决各个Verticle之间的数据共享。

通常Tomcat会在100个并发长请求(这个请求要求做很多事长任务)下堵塞,而Vertx将长任务委托给另外一个线程来执行,从而不会堵塞当前线程,与NodeJS的原理非常类似,如下图:

事件循环的线程和长任务工作线程之间是通过事件总线EventBus通讯的,这个事件总线是一个JVM之中,Vert.x以非阻塞IO 的思想来实现高性能,非阻塞IO的实现,基于Event Loop Vertical和Worker Vertical的分离,在Vert.x中,Event Loop用于接收,并将短业务操作交由其内部的Vertical来处理,该模块是非阻塞的,这样可以保证请求的处理效率;阻塞任务通过Vert.x 的事件机制脱离当前线程,转移到Worker Vertical中执行,并执行结果返回给Event Loop Vertical。这一过程完成的核心是Event Bus,Event Bus中注册了所有的事件,通过事件匹配完成事件转移和结果返回,从而将整个流程衔接起来。如下图:

多层之间也可以通过EventBus通讯实现调用:

多个客户端或服务器端。Vert.x启动时,会将Worker Vertical的事件处理函数加载到Event Bus,当一个HTTP请求发送到Vert.x 构建的应用时,Event Loop首先接收到请求,并对请求做分析、包装,然后将事件交给Event Bus来处理,Event Bus为此次请求事件添加一个事件ID,然后根据注册的Worker Vertical事件寻找已经注册的监听函数,若未找到则会抛弃该事件,若找到则会对处理类进行实例化,并同时使用事件ID在Event Bus中注册一个返回结果处理事件,该事件为Event Vertical类型。下一步由Worker Vertical实例执行事件处理函数,事件处理函数中通常包含业务处理、数据库操作等。Worker Vertical实例处理结束后,将返回结果和事件信息返回给Event Bus,Event Bus找到在其中注册的Event Vertical实例,然后将返回数据交给该实例处理,Event Vertical实例进一步处理数据并将结果返回给浏览器。如下图:

2.Vert.x-Web

Vert.x-Web是vert.x的web构建模块。你可以使用它构建现代的可扩展的web应用程序。Vert.x提供了一些相当底层的方式处理HTTP请求,但是对于大多数的应用程序这些也就够用了。Vert.x-Web基于Vert.x-Core为更容易的构建真正的web应用程序提供了丰富的功能。

关于一些Vert.x的关键特征:

路由(基于方法、路径等)、正则表达式模式匹配的路径、从路径提取参数、内容协商、请求主体处理、身体大小限制、Cookie 解析和处理、多表单上传、多文件上传、子路由器支持、会话支持——本地和集群、交叉起源资源共享支持、错误页面处理程序、基本身份验证、基于重定向的身份验证、授权处理程序、JWT基于授权、用户/角色/权限授权、标识处理、服务器端呈现的模板支持(包括支持以下模板引擎的:Handlebars、Jade、MVEL、Thymeleaf)、响应时间处理程序、静态文件服务,包括缓存逻辑和目录清单。请求超时的支持、SockJS支持、事件总线桥

大多数的Vert.x的特性被实现为处理事件(Handler),这样你就可以自己实现它。随着时间的推移我们将加入更多特性。

这里有一个使用Vert.x核心API编写的《hello world》的web服务器:

HttpServer server = vertx.createHttpServer();

server.requestHandler(request -> {

// This handler gets called for each request that arrives on the server

HttpServerResponse response = request.response();

response.putHeader("content-type", "text/plain");

// Write to the response and end it

response.end("Hello World!");

});

server.listen(8080);

Router 是Vert.x的核心概念之一。它的一个对象可以维护零个或多个路径,处理请求和调用下一个处理程序:

HttpServer server = vertx.createHttpServer();

Router router = Router.router(vertx);

router.route(―/‖).handler(routingContext -> {

// This handler will be called for every request

HttpServerResponse response = routingContext.response();

response.putHeader("content-type", "text/plain");

// Write to the response and end it

response.end("Hello World from Vert.x-Web!");

});

Route route1 = router.route("/some/path/").handler(routingContext -> {

HttpServerResponse response = routingContext.response();

// enable chunked responses because we will be adding data as

// we execute over other handlers. This is only required once and

// only if several handlers do output.

response.setChunked(true);

response.write("route1\n");

// Call the next matching route after a 5 second delay

routingContext.vertx().setTimer(5000, tid -> routingContext.next());

});

Route route2 = router.route("/some/path/").handler(routingContext -> {

HttpServerResponse response = routingContext.response();

response.write("route2\n");

// Call the next matching route after a 5 second delay

routingContext.vertx().setTimer(5000, tid -> routingContext.next());

Route route3 = router.route("/some/path/").handler(routingContext -> {

// This handler will be called for the following request paths:

// `/some/path`

// `/some/path/`

// `/some/path//`

//

//but not:

// `/some/path/subdir`

HttpServerResponse response = routingContext.response();

response.write("route3");

// Now end the response

routingContext.response().end();

});

Route route = router.route().path("/some/path/*");

route.handler(routingContext -> {

// This handler will be called for any path that starts with

// `/some/path/`, e.g.

// `/some/path`

// `/some/path/`

// `/some/path/subdir`

// `/some/path/subdir/blah.html`

//

// but not:

// `/some/bath`

});

//如果post请求的地址是:/catalogue/products/tools/drill123/ 然后Route会匹配为:productType的值为tools和productID 的值为drill123.

Route route = router.route(HttpMethod.POST, "/catalogue/products/:productype/:productid/");

route.handler(routingContext -> {

String productType = routingContext.request().getParam("producttype");

String productID = routingContext.request().getParam("productid");

// Do something with them...

});

server.requestHandler(router::accept).listen(8080);

使用阻塞处理程序

可以为一个路径(route)添加一个blockingHandler。比如这样:

router.route().blockingHandler(routingContext -> {

// Do something that might take some time synchronously

service.doSomethingThatBlocks();

// Now call the next handler

routingContext.next();

3. Vert.x中EventBus中的使用

event bus 是vert.x的神经系统。

每一个vert.x的实例都有一个单一的event bus 实例。它是使用vertx.eventBus()方法获得的。

event bus 允许程序中的不同语言编写的模块进行通信,不论他们是相同的vert.x实例,还是不同的vert.x实例。

它甚至可以桥接浏览器中运行的Javascript通信。

event bus可以在分布式系统中的多个服务器节点之间进行点对点通信和多个浏览器。

event bus支持发布/订阅模式,点对点模式,和请求/响应模式。

event bus的API是非常容易的,它主要包括注册消息处理事件,取消处理事件,发送和发布消息。

EVENT BUS 的API让我们跳进event bus的API。

获得event bus 的对象

你可以通过如下代码获得event bus的单一对象:

EventBus eb = vertx.eventBus();

注册处理事件

使用下面这个简单方法注册一个消费处理程序:

EventBus eb = vertx.eventBus();

eb.consumer(―https://www.wendangku.net/doc/a01042962.html,.sport‖, message -> {

System.out.println(―I have received a message: ‖ + message.body());

});

当一个消息到达你的处理事件是。你的事件将被激活,并处理这个消息。

consumer()方法返回一个MessageConsumer的对象实例。这个对象随后用于注销处理程序,或者用处理程序作为流。然而您也可以使用consumer()返回MessageConsumer没有处理程序,然后单独设置处理程序。例如:

EventBus eb = vertx.eventBus();

MessageConsumer consumer = eb.consumer(―https://www.wendangku.net/doc/a01042962.html,.sport‖);consumer.handler(message -> { System.out.printl n(―I have received a message: ‖ + message.body());

});

当在集群事件总线上注册一个处理程序时,它可以花一些时间登记到集群的所有节点上。

如果你希望在注册完成时得到通知的话,你可以在MessageConsumer上注册一个注册完成的处理程序:

https://www.wendangku.net/doc/a01042962.html,pletionHandler(res -> {

if (res.succeeded()) {

System.out.println(―The handler registration has reached all nodes‖);

} else {

System.out.println(―Registration failed!‖);

}

});

注销处理事件

去除处理事件,叫做注销。

如果你是集群事件总线,如果你想当这个过程完成时通知注销,你可以使用下面的方法:

consumer.unregister(res -> {

if (res.succeeded()) {

System.out.println(―The handler un-registration has reached all nodes‖);

} else {

System.out.println(―Un-registration failed!‖);

}

});

发布消息

发布消息非常简单,只需要把它发布到指定地址即可:

eventBus.publish(―https://www.wendangku.net/doc/a01042962.html,.sport‖, ―Yay! Someone kicked a ball‖);

这一消息将被交付所有订阅https://www.wendangku.net/doc/a01042962.html,.sport地址处理。

发送消息

发送消息将导致只有一个注册地址的处理程序接收到消息(多个注册地址也只有一个能收到)。这就是点对点模式,选择处理程序的方法采用非严格循环方式。

你可用用send()方法发送一条消息。

eventBus.send(―https://www.wendangku.net/doc/a01042962.html,.sport‖, ―Yay! Someone kicked a ball‖);

未解决的指令包括在-include::override/eventbus_headers.adoc[] ==== The Message object

你的消息处理程序收到的是一个Message。

消息的body对应着是应该发送还是应该发布。

消息的headers是可用的。

回复消息

有时你发送消息后希望得到接收到消息的人的回复。这就需要你使用请求-响应模式。

要做到这一点,在消息发送的时候,你可以指定一个回复事件。

当你接收到消息的时候,你可以通过调用reply()方法来应答。

当这一切发生的时候它会导致一个答复发送回发送方,发送方收到应答消息再做处理。

接收方:

MessageConsumer consumer = eventBus.consumer(“https://www.wendangku.net/doc/a01042962.html,.sport”);

consumer.handler(message -> {

System.out.println(“I have received a message: ”+ message.body());

message.reply(“how interesting!”);

});

发送方:

eventBus.send(“https://www.wendangku.net/doc/a01042962.html,.sport”, “Yay! Someone kicked a ball across a patch of grass”, ar -> { if (ar.succeeded()) {

System.out.println("Received reply: " + ar.result().body());

}

});

对应答也可以做应答。这样你就可以在两个不同的程序中创建一个包含多个回合的对话。

发送超时

当你发送消息时和指定应答事件时你可以通过DeliveryOptions指定超时时间。

如果应答事件不少于超时时间,这个应答事件将失败。

默认的超时时间是30S。

发送失败

消息发送失败的其他原因,包括:

没有可用的事件去发送消息

接收者已经明确使用失败:失败的消息

在所有情况下,应答事件将回复特定的失败。

未解决的指令包含在 –include::override/eventbus.adoc[]==== Clustered Event Bus

event bus 不仅仅存在于一个单一的Vert.x实例中,在一个集群中不同的Vert.x实例也可以形成一个单一的,分布的事件总线。

集群编程

如果你创建一个Vert.x实例用于集群编程,你需要的得到一个关于集群事件总线配置

VertxOptions options = new VertxOptions();

Vertx.clusteredVertx(options, res -> {

if (res.succeeded()) {

Vertx vertx = res.result();

EventBus eventBus = vertx.eventBus();

System.out.println(“We now have a clustered event bus: ”+ eventBus);

} else {

System.out.println(“Failed: ”+ res.cause());

}

});

你应该确保在你的类路径中实现了一个ClusterManager,例如默认的:HazelcastClusterManager。

使用命令集群

你可以使用命令行运行集群:vertx run my-verticle.js -cluster

Automatic clean-up in verticles

4.Vert.x的微服务verticle

而Vert.x的verticle本身就是很好的一种服务定义,你可以把verticle看成一个service,也可以把verticle看成一个actor。

这样你的视角会切到Actor模型里。本文我们将讨论如何基于Vert.x实现远程调用。

Vert.x EventBus两宗罪

但Vert.x的EventBus有两点不太好的地方,导致不能原生支持面向接口的服务调用。

EventBus是Vert.x的核心,因为它的存在可以使得系统模块化解耦成为可能,同时也可以将业务水平扩展。我们只需要定义EventBus地址然后传入Json对象就可以,所有的事情都很流畅。但是这里有一点不太好的地方,默认传输协议走Json,而Json 本身不太好定义数据类型。

如果了解Vert.x历史的同学肯定知道为什么EventBus一定要使用Json作为主要的传输对象——为了兼容其他JVM上的弱语言。可是现实情况中80%的项目都是基于Java跑的,根本就没有考虑去兼容其他JVM上的语言。这就造成了一种尴尬,大家都传Json对象,然后在Handler里先做一次转换,将Json对象转换成POJO,之后再做业务上的逻辑。这里明显在Handler里做了很多与业务无关的事情,服务定位与对象转换,这些本质上应该是框架层面去解决的。

不能隐试的将Json对象转成POJO这是EventBus的一宗罪。(Vert.x3可以直接接受POJO,但是针对一个address,只能接收一种POJO格式。)另外当我们使用EventBus的时候不能很方便的确定方法逻辑,简单的讲我只能EventBus。send()后面跟地址参数以及JSON对象,而这并不适合描述业务,这是EventBus的二宗罪。

举个例子,有一个业务逻辑,对用户的账户进行存款与取款这两个操作,如果用Java接口来描述就很Easy。

Java代码

interface Account {

void saveMemory(int total);

void withdrawMemory(int total);

}

如果换成EventBus你会发现没办法定义行为的名称(Java的方法),只能通过eb.send("address",json)来调用目标接口。这里的json也许得包含method的描述。这样会显得很啰嗦,关键是对IDE不友好,重构起来不方便,严重影响团队开发流畅度。

5.Vertx-RPC介绍

介于上面的原因,我们开发了一个简单的RPC框架,它简单的封装了EventBus,使之可以包装成Java的接口。这样客户端与服务端之间调用就像本地接口一样。vertx-rpc其实做的非常简单,他只依赖protostuff,作为数据传输的协议,当然也可以使用JSON 协议。接着只需要定义好接口,然后在服务端实现接口,而客户端只依赖接口,单独将项目打包成jar暴露给出来就可以使用了。我们继续上面的例子,根据接口我们会把项目分成两个Maven模块。SPI,SPI-impl,在parent的pom.xml定义好即可。下面我们先在impl的项目里启动好service并通过EventBus暴露服务。

Java代码

Vertx vertx = Vertx.vertx();

String address = "serviceAddress";

RPCServerOptions rpcServerOptions = new RPCServerOptions(vertx).setBusAddress(address).addService(new MyServiceImpl()); new VertxRPCServer(rpcServerOptions);

以上四行代码就已经成功的定义了服务,是这里要注意new MyServiceimpl()必须实现spi项目里的MyService接口。下面我们来看调用方,怎么调用服务。

Java代码

Vertx vertx = Vertx.vertx();

String address = "serviceAddress";

RPCClientOptions rpcClientOptions = new

RPCClientOptions(vertx).setBusAddress(address).setServiceClass(MyService.class);

MyService myService = new VertxRPCClient<>(rpcClientOptions).bindService();

这里本质上是两行代码,一行定义了rpcClient的配置通过RPCClientOptions,另外一行直接绑定服务,通过VertxRPCClient。bindService()。最后得到了接口MyService。下面你就可以在客户端直接调用服务端的接口了,一切又回到了以前的面向接口编程。

这里有个完整的项目例子。我们把项目里的SPI定义接口,里面除了接口,还包含接口用到的对象以及异常。以后所有的操作都是面向这个SPI来做,service-impl就实现了其接口,outer-invoker其实是外部的service依赖接口来调用service-impl。这便是完全面向接口编程。

vertx-rpc除了包装EventBus使之可以通过Java标准方法调用外,还可以通过注解来定义每一个方法的超时时间。

Java代码

@RequestProp(timeout = 1, timeUnit = TimeUnit.SECONDS, retry = 2)

void hello(String what, Handler> handler);

这里就对hello方法定义了超时时间,以及超时重试次数,非常方便用于幂等的方法。上面的方法第二个参数是Vert。x的handler 回调,这里也可以使用RxJava或者Java8的CompletableFuture。

Java代码

Observable hello(String what)

//或者

CompletableFuture hello(String what)

具体可以参考项目例子。

6. JWT 介绍及其原理

JWT是Auth0提出的通过对JSON进行加密签名来实现授权验证的方案,编码之后的JWT看起来是这样的一串字符:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.T JVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

由 . 分为三段,通过解码可以得到:

// 1. Headers // 包括类别(typ)、加密算法(alg);{ "alg": "HS256", "typ": "JWT" } // 2. Claims // 包括需要传递的用户信息;{ "sub": "1234567890", "name": "John Doe", "admin": true } // 3. Signature // 根据alg算法与私有秘钥进行加密得到的签名字串;// 这一段是最重要的敏感信息,只能在服务端解密;

HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), SECREATE_KEY )

在使用过程中,服务端通过用户登录验证之后,将Header+Claim信息加密后得到第三段签名,然后将签名返回给客户端,在后续请求中,服务端只需要对用户请求中包含的JWT进行解码,即可验证是否可以授权用户获取相应信息,其原理如下图所示:为了保存用户授权信息,仍然需要通过Cookie或类似的机制进行本地保存。因此JWT是用来取代服务端的Session而非客户端Cookie的方案,当然对于客户端本地存储

7. RxJava介绍及其原理

RxJava最核心的两个东西是Observables(被观察者,事件源)和Subscribers(观察者)。Observables发出一系列事件,Subscribers 处理这些事件。这里的事件可以是任何你感兴趣的东西(触摸事件,web接口调用返回的数据。。。).一个Observable可以发出零个或者多个事件,知道结束或者出错。每发出一个事件,就会调用它的Subscriber的onNext方法,最后调用Subscriber.onNext()或者Subscriber.onError()结束。

1.Observable和Subscriber可以做任何事情

Observable可以是一个数据库查询,Subscriber用来显示查询结果;Observable可以是屏幕上的点击事件,Subscriber用来响应点击事件;Observable可以是一个网络请求,Subscriber用来显示请求结果。

2.Observable和Subscriber是独立于中间的变换过程的。

在Observable和Subscriber中间可以增减任何数量的map。整个系统是高度可组合的,操作数据是一个很简单的过程。

创建一个Observable对象很简单,直接调用Observable.create即可

Observable myObservable = Observable.create(

new Observable.OnSubscribe() {

@Override

public void call(Subscriber sub) {

sub.onNext("Helo, world!");

sub.onCompleted();

}

} );

这里定义的Observable对象仅仅发出一个Hello World字符串,然后就结束了。接着我们创建一个Subscriber来处理Observable 对象发出的字符串。

Subscriber mySubscriber = new Subscriber() {

@Override

public void onNext(String s) { System.out.println(s); }

@Override

public void onCompleted() { }

@Override

public void onError(Throwable e) { }

};

myObservable.subscribe(mySubscriber);

这里subscriber仅仅就是打印observable发出的字符串。通过subscribe函数就可以将我们定义的myObservable对象和mySubscriber对象关联起来,这样就完成了subscriber对observable的订阅。

上面的代码最终可以写成这样

Observable.just("Hello, world!")

.subscribe(new Action1() {

@Override

public void call(String s) {

System.out.println(s);

}

});

使用java8的lambda可以使代码更简洁

Observable.just("Hello, world!").subscribe(s -> System.out.println(s));

操作符(Operators)

Observable.just("Hello, world!")

.map(s -> s + " -Dan")

.subscribe(s -> System.out.println(s));

Observable.just("Hello, world!")

.map(new Func1() {

@Override

public Integer call(String s) {

return s.hashCode();

}

}).subscribe(i -> System.out.println(Integer.toString(i)));

query("Hello, world!")

.flatMap(urls -> Observable.from(urls))

.flatMap(url -> getTitle(url))

.filter(title -> title != null)

.take(5)

.doOnNext(title -> saveTitle(title))

.subscribe(title -> System.out.println(title));

错误处理

Observable.just("Hello, world!")

.map(s -> potentialException(s))

.map(s -> anotherPotentialException(s))// 2.操作符不需要处理异常

.subscribe(new Subscriber() {

@Override

public void onNext(String s) { System.out.println(s); }

@Override// 3.你能够知道什么时候订阅者已经接收了全部的数据。

public void onCompleted() { System.out.println("Completed!"); }

@Override// 1.只要有异常发生onError()一定会被调用

public void onError(Throwable e) { System.out.println("Ouch!"); }

});

RxJava的另外一个好处就是它处理unsubscribing的时候,会停止整个调用链

subscription.unsubscribe();

8.Reactive Streams开源项目

Reactive Streams目标是管制流数据在跨越异步边界进行流数据交换,可以认为是将元素传递到另一个线程或线程池,同时确保在接收端不是被迫缓冲任意数量的数据。换句话说,抗压是该模型重要组成部分,设置协调线程之间的队列大小是有限制的,如果不同异步模型之间的通信是同步的将削弱异步的好处。因此必须采取谨慎措施,强制完全无阻塞的反应流能在系统的各个方面异步实施1. 处理潜在的无边界限制的元素2.顺序3.在组件之间异步传递元素4.使用强制性的非堵塞的抗压。

RS由以下部分组成:

SPI:定义了不同实现组件之间的交互层和互操作性

API:定义Reactive Streams用户使用的类型

9. JCA (J2EE 连接器架构,Java Connector Architecture)是对J2EE标准集的重要补充

J2EE中找到相关的规范与实现了这些规范的工具,比如:

* WebService下面有基于XML的JAX-WS规范,以及基于REST的JAX-RS规范。实现了这些规范的开源项目有:Apache CXF,RESTEasy、jersey等

* 数据库有JPA规范,相关的开源工具当然是大名鼎鼎的Hibernate、mybatis等。

* 消息中间件有JMS规范,实现了这一规范的开源工具包括HornetQ,Apache ActiveMQ等等。

* 事务管理

*jCA的全称是J2EE Connector Architecture,它定义了一个连接J2EE平台和Enterprise Information Systems(EIS: A是一个Web 项目,用Servlet开发的;B是一个FTP服务器,上面有些文件;C是一个数据库,里面有点数据。那么,A,B,C都叫EIS)的标准架构,使得各个EIS能够接入到Application Server当中。

什么是J2EE Application Server?

J2EE Application Server就是支持各种(最好是所有)J2EE技术的应用服务器。比如开源的JBoss AS,或者是WebSphere,这些都是J2EE Application Server。因为它们支持各种J2EE的标准和框架。比如你做了个和数据库有关的项目,是基于JPA接口规范做的,那么你既可以把它部署在JBoss AS里面,用Hibernate支持跑起来你的项目,也可以部署在WebSphere服务器里面,使用另一套解决方案。因此,这些实现了J2EE各个规范的服务器,就叫做J2EE Application Server。那么Tomcat算不算J2EE Application Server 呢?严格来讲,Tomcat不能算是J2EE Application Server,它只能说是一个Servlet容器,虽然Servlet标准也是J2EE世界中的一员。Tomcat支持的J2EE组件太少了,它不包含对J2EE的事务标准JTA的支持,也不支持JMS,不支持JPA(没有Hibernate这样的组件),不支持EJB,不支持各种WebSerivce。。。当然,你可以在Tomcat的基础上打造一个准J2EE Application Server。比如,你可以在自己的项目里面加上Hibernate,加上ActiveMQ,加上WebService,加上OpenEJB。。。

JCA定义了三个Contract:

* Connection management (连接管理)

* Transaction management (事务管理)

* Security (安全规范)

案例:

在本文中我们要用到的EIS是一个Servlet的服务,运行在一个JBoss AS服务器上(实际上运行在哪里无所谓,是什么也不重要。因为JCA标准中,并没有对EIS的形式或内容做要求。可以是文件,数据库,FTP服务,或像本文要用到的这个HTTP Servlet服务)。

这个项目的功能是列出自己电脑上的目录。我们将这个项目命名为:

* services-1.0.0.war

然后我们要使用另一台JBoss AS服务器做为Application Server,在这上面开发一个ResourceAdapter,用RAR的形式部署,将EIS 接进来。将这个项目命名为:

* listfiles-0.1.rar

最后,我们要在Application Server上面开发一个Web应用,使用这个ResourceAdapter为我们接入的EIS资源,提供给最终用户进行使用。这个项目名为:

* listfiles-0.1.war

示例的整体架构图如下:

接下来是实施过程:

10.Metrics是一个给JAVA服务的各项指标提供度量工具的包,用于检测jvm 上后端服务的运行状况

Metrics提供了一组通用的模块库用于支持比如Guice,Jetty,Log4j,Apache HttpClient,EhCache,Logback,Spring等,也提供对比如Ganglia和Graphite等后端的报告。

core包主要提供如下核心功能:

●Metrics Registries类似一个metrics容器,维护一个Map,可以是一个服务一个实例。

●支持五种metric类型:Gauges、Counters、Meters、Histograms和Timers。

●可以将metrics值通过JMX、Console,CSV文件和SLF4J loggers发布出来,它还可以将度量数据发送给Ganglia和Graphite

以提供图形化的监控。Ganglia工作原理:Ganglia包括如下几个程序,他们之间通过XDR(xml的压缩格式)或者XML格式传递监控数据,达到监控效果。集群内的节点,通过运行gmond收集发布节点状态信息,然后gmetad周期性的轮询gmond收集到的信息,然后存入rrd数据库,通过web服务器可以对其进行查询展示。

11. jsonp

JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题,利用