JavaOne2015 - Java EE
2015/11/14 上妻 宜人 (あげつま のりと)
• APサーバサポート、Javaトラブルシューティング
• ブログ 見習いプログラミング日記
• twitter: @n_agetsu
上妻 宜人 (あげつま のりと)
• Java EE 8 のアップデート
• Early Draft Review1: Servlet4.0, JMS2.1
• ドラフト未リリース: JAX-RS2.1, JPA2.2
• Java EE 周辺の話
• WildFly Swarm
本日の内容
Java EE 8 はまだ検討中。
この先の内容は、今後大きく変わる
可能性があります。
Servlet4.0
現在のステータス: Early Draft Review
JSR-368 https://jcp.org/en/jsr/detail?id=368
Servlet 4.0
サーブレットコンテナもHTTP/2通信に対応
• 2015年5月 RFC 7540で公開。SPDYが原型。
• 多重化 / バイナリフレーム / ヘッダ圧縮
• ヘッダの意味合い (GET/POST/200 OK など) は基本的に踏襲
client server
client server
client server
並行リクエストは、複数TCP接続が必要
ブラウザ実装によっては同時接続数『6』 1TCP接続で多重化
TCPコネクション_1
TCPコネクション_2..
Servlet 4.0
HTTP/2 ストリームによる多重化
Connection : 1つのTCPコネクション
Stream : 1つのリクエスト & レスポンスの組
Stream id=1
Stream id=1 .. N:
http://chimera.labs.oreilly.com/books/1230000000545/ch12.html#HTTP2_STREAMS_MESSAGES_FRAMES
Request
Stream: 1
:method: GET ...
Frame : HTTP2.0通信の最小単位
Stream: 1
:status:200
HEADERS frame
Stream: 1
response data
DATA frame
Response
Servlet 4.0
HTTP/2 ストリームによる多重化のServlet影響
• APIのユーザ視点では影響はあまりない
• 1リクエスト => 1レスポンス の法則が崩れなければ、
doGet, doPostメソッドの現状の仕組みがそのまま使える
• HttpServletRequest/HttpServletResponse へのメソッド追加
• int getStreamId()
• ストリームIDを知りたい機会は少ないと思う
Servlet 4.0
HTTP/2 サーバプッシュ
client server
.html
.js
.png
.css
• SSE/WebSocketとは用途が異なる
• 関連リソースをサーバプッシュ
• 例えばhtmlの要求がきたら
• 関連のjs, png, css もプッシュする
• 従来はインラインイメージを適用
• 1リクエスト => 1レスポンスが崩れる
• 今までのHttpServletResponseは
1レスポンスが前提
Servlet 4.0
HTTP/2 サーバプッシュのServlet影響
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
PushBuilder builder = request.getPushBuilder();
builder.setPath(“/style.css”);
builder.push();
res.setContentType(“text/html”);
PrintWriter out = res.getPrintWriter();
out.println(“<html>”);
out.println(“<head>”)
out.println(“<link rel=”stylesheet” type=”text/css” href=“style.css”>”);
…
}
Servlet4.0 まとめ
• HTTP/2 対応
– サーブレットコンテナがHTTP/2に対応
– ストリームID取得, サーバプッシュ向けAPIの追加
• 本日は未紹介
– (検討中) Java9 Flow対応によるリクエスト処理
JAX-RS2.1
現在のステータス: ドラフト未リリース
JSR-370 https://jcp.org/en/jsr/detail?id=370
JAX-RS2.1
主なテーマ
• 非同期クライアントAPIの改善
• ノンブロッキング I/O
• Server-Sent Event
– Jersey実装と同じ
JAX-RS2.1
非同期クライアントAPIの改善
• 並列で依存関係のあるWebAPIを呼び出したい
• Jerseyには既に実装がある
• RxJava Observable, Java 8 CompletableFuture 対応
出張手配
サービス
新幹線予約
ホテル予約大阪1泊2日で!
手配完了
料金請求
1. 予約を並列実行
2. 予約が終わったら
請求サービスに投げる
JAX-RS2.1
非同期クライアント: rx()によるCompletationState取得
// Aの問い合わせ (非同期)
WebTarget targetA = Client.newClient().target(...);
CompletionStage<User> a = target1.request().resolveTemplate(“id”, 1)
.rx().get(User.class);
// Bの問い合わせ (非同期)
CompletionState<Product> b = targetB.request().resolveTemplate(“id”, 1)
.rx().get(Product.class);
// AとBの結果を組み合わせて、Cに問い合わせ (非同期)
CompletionState<String> c = a.thenCombine(b, (user, product) ->
targetC.request()
.resolveTemplate(“user”,user)
.resolveTemplate(“prod”,product).rx().get(...)));
// 最終的な結果の取得
c.join();
a
b
c 最終的な結果
JAX-RS2.1
非同期クライアント: rx()によるCompletationState取得
// Aの問い合わせ (非同期)
WebTarget targetA = Client.newClient().target(...);
CompletionStage<User> a = target1.request().resolveTemplate(“id”, 1)
.rx().get(User.class);
// Bの問い合わせ (非同期)
CompletionState<Product> b = targetB.request().resolveTemplate(“id”, 1)
.rx().get(Product.class);
// AとBの結果を組み合わせて、Cに問い合わせ (非同期)
CompletionState<String> c = a.thenCombine(b, (user, product) ->
targetC.request()
.resolveTemplate(“user”,user)
.resolveTemplate(“prod”,product).rx().get(...)));
// 最終的な結果の取得
c.join();
a
b
c 最終的な結果
JAX-RS2.1
非同期クライアント: アノテーションによる依存性制御
class DeclarativeRxHandler {
@FinalResult
public String getC(
@PartialResult(“A”) String a, @PartialResult(“B”) String b) {
return a;
}
@PartialResult(“A”)
public CompletableFuture<String> getA() {...}
@PartialResult(“B”)
public CompletableFuture<String> getB() {...}
}
A
B
C 最終的な結果
JAX-RS2.1
ノンブロッキング I/O - 背景
• 不安定/遅いネットワークからファイルアップロード
• CPUは別スレッドに割当てられても、メモリは1MB消費し続ける
@Path(“/upload”)
public class FileUploadResource {
@POST @Consumes(MediaType.MULTIPART_FORM_DATA)
public void upload(@FormDataParam(“file”) InputStream input, ...) {
byte[] buf = new byte[1024];
int readed;
try {
while ((readed = input.read(buf)) != -1) {
// write file ...
} catch (IOException e) {...}
}
データが来るまでブロック
(64bitJVM)
@POST @Consumes(MediaType.APPLICATION_OCTET_STREAM)
public void upload(@QueryParam(“path”) String path,
@Context request, @Suspend AsyncResponse response) {
FileOutputStream out = new FileOutputStream(tmpdir);
byte[] buf = new byte[1024];
request.entity(input -> {
try {
if (input.isFinished()) {
// データ読み込み完了
out.close();
response.resume(“Upload Completed”);
} else {
final int n = input.read(buffer);
out.write(buffer, 0, n);
}
} catch (IOException e) {...}
}
}
JAX-RS2.1
ノンブロッキング I/O - JavaOneで紹介されていたアイディア
@POST @Consumes(MediaType.APPLICATION_OCTET_STREAM)
public void upload(@QueryParam(“path”) String path,
@Context request, @Suspend AsyncResponse response) {
FileOutputStream out = new FileOutputStream(tmpdir);
byte[] buf = new byte[1024];
request.entity(input -> {
try {
if (input.isFinished()) {
// データ読み込み完了
out.close();
response.resume(“Upload Completed”);
} else {
final int n = input.read(buffer);
out.write(buffer, 0, n);
}
} catch (IOException e) {...}
}
}
ブロックしない
読込可能データの発生毎に
繰り返しコールバックされる?
JAX-RS2.1
ノンブロッキング I/O - JavaOneで紹介されていたアイディア
JAX-RS2.1
ノンブロッキング I/O - まだまだ検討中
• 本当に必要? 色々と議論がある
• ユーザレベルでNIOを意識しなくても良いのでは など?
– MessageBodyReader, MessageBodyWriterの実装内に隠蔽
(JAX-RSランタイムの中の json read/write 時に利用)
– Servlet コンテナのコネクタ実装としてのNIOで十分では?
JMS2.1
現在のステータス: Early Draft Review
JSR-368 https://jcp.org/en/jsr/detail?id=368
JMS2.0
Java EE 7 - JMS2.0のMDBを振り返る
@MessageDriven(
activationConfig = {
@ActivationConfigProperty(
propertyName="destinationType", propertyValue="javax.jms.Queue"),
@ActivationConfigProperty(
propertyName="destination", propertyValue="java:/queue/myQueue")
})
public class SampleMDB implements MessageListener {
@Override
public void onMessage(Message message) {
try {
TextMessage textMessage = (TextMessage) message;
System.out.println(textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
@MessageDriven(
activationConfig = {
@ActivationConfigProperty(
propertyName="destinationType", propertyValue="javax.jms.Queue"),
@ActivationConfigProperty(
propertyName="destination", propertyValue="java:/queue/myQueue")
})
public class SampleMDB implements MessageListener {
@Override
public void onMessage(Message message) {
try {
TextMessage textMessage = (TextMessage) message;
System.out.println(textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
JMS2.0
Java EE 7 - JMS2.0のMDBを振り返る
何のリスナ (Queue or Topic)を
文字列で指定する必要がある
@MessageDriven(
activationConfig = {
@ActivationConfigProperty(
propertyName="destinationType", propertyValue="javax.jms.Queue"),
@ActivationConfigProperty(
propertyName="destination", propertyValue="java:/queue/myQueue")
})
public class SampleMDB implements MessageListener {
@Override
public void onMessage(Message message) {
try {
TextMessage textMessage = (TextMessage) message;
System.out.println(textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
JMS2.0
Java EE 7 - JMS2.0のMDBを振り返る
インタフェースの実装、
Messageのキャストが必要
JMS2.1
JMS2.1の主な機能追加
• MDBからMessageListenerの実装を不要とする
• タイプセーフ
• キャストの不要化
• 1クラスで複数コールバックメソッドを実装
JMS2.1
JMS2.1ドラフト: @JMSQueueListener
@MessageDriven
public class SampleMDB {
@JMSQueueListener (destionationLookup = “java:/queue/myQueue”)
public void printMessage(TextMessage text) {
try {
System.out.println(text.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
@MessageDriven
public class SampleMDB {
@JMSQueueListener (destionationLookup = “java:/queue/myQueue”)
public void printQueue1Msg(TextMessage text) {
….
}
@JMSQueueListener (destionationLookup = “java:/queue/myQueue2”)
public void printQueue2Msg(TextMessage text) {
….
}
}
JMS2.1
JMS2.1ドラフト: 1クラスに複数コールバック定義
• MDB停止中のトピック書き込みは検知できない
• JMS2.0では
@ActivationConfigProperty(
propertyName="subscriptionDurability“, propertyValue="NonDurable")
@MessageDriven
public class SampleMDB {
@JMSNonDurableTopicListener(destinationLookup=“java:/topic/myTopic”)
public void printMessage(TextMessage text) {
….
}
}
JMS2.1
JMS2.1ドラフト: トピック向け非永続化サブスクライバ
@MessageDriven
public class SampleMDB {
@JMSDurableTopicListener (
destinationLookup=“java:/topic/myTopic”, cliendId=“someid”,
subscriptionName=“somename”)
public void printMessage(TextMessage text) {
….
}
}
• 全永続化サブスクライバの受信までメッセージ削除されない
• JMS2.0では
@ActivationConfigProperty(
propertyName="subscriptionDurability“, propertyValue="Durable")
@ActivationConfigProperty(propertyName=“clientid”, propertyValue=“someid”)
@ActivationConfigProperty(propertyName="subscriptionName", propertyValue=“somename")
JMS2.1
JMS2.1ドラフト: トピック向け永続化サブスクライバ
JMS2.1 まとめ
• 今のところはMDBのシンプル化が主な内容
• CDI管理Beanによるメッセージ受信は検討中
(Early Draft Review1には含まれていない)
JPA2.2
現在のステータス: ドラフト未リリース
JSRなし (状況はJIRA参照https://java.net/jira/browse/JPA_SPEC)
JPA2.2
検討中の主な項目
• Java SE 8対応
• Date and Time API への対応
• @NamedQueryのRepeatableアノテーション対応
• スクロール機能の標準化
• 例: org.hibernate.ScrollableResults
JPA2.2
スクロール機能の標準化 - getStreamResult()
Query q = em.createQuery(“select e from Employee e”);
// OutOfMemoryError ??
List<Employee> employees = q.getResultList();
// 少ないJavaヒープメモリで動作
int total = q.getStreamResult().collect(
Collectors.summingInt(Employee::getSalary));
Java EE 8 スケジュール
Java EE 8 & GlassFish5リリースは2017上半期予定
• 2015 Q4 Early Draft
• 2016 Q1 Public Review
• 2016 Q4 Proposed Final Draft
• 2017年上半期 Final 予定
Java EE 周辺の話
Spring Boot風 Java EE “WildFly Swarm”
WildFly Swarm
Java EE で java -jar myapp.jar 起動
• Spring Boot風のJava EE
• 2015/5 に1.0.0.Alpha1リリース
– まだ実験的: (最新) 2015/10/25 1.0.0.Alpha5
• APサーバの事前インストールが不要になる
• java -jar myapp.jar で手軽に起動
なぜ WildFly Swarm
Spring Bootとは少し背景が違う
• Spring Bootの背景 (集約)
• 機能が豊富で、pom.xml の組み合わせ方法が難しい
=> 推奨組み合わせを作って、簡単に使えるようにした
• WildFly Swarmの背景 (分解)
• Java EE をフルセットで使う人は少ない
=> アプリで利用する機能だけ一式jarにまとめて軽量化
Hello World!
1. 利用したい機能をpom.xmlに記述
<dependencies>
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>wildfly-swarm-jaxrs-weld</artifactId>
<version>${version.wildfly-swarm}</version>
</dependency>
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>wildfly-swarm-jpa</artifactId>
<version>${version.wildfly-swarm}</version>
</dependency>
</dependencies>
JAX-RS & CDI
JPA
組み込みH2の起動
データソースExampleDS追加
Hello World!
2. uber jar を作成する wildfly-swarm-plugin
<plugin>
<groupId>org.wildfly.swarm</groupId>
<artifactId>wildfly-swarm-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>package</goal>
</goals>
</execution>
</executions>
</plugin>
• Mavenプラグインによりmvn packageで実行可能jarを生成
Hello World!
3. 通常と変わりなくコードを書く
@Path("/")
public class EmployeeResource {
@Inject
EntityManager em;
@GET
@Produces("application/json")
public List<Employee> get() {
return em.createNamedQuery("Employee.findAll", Employee.class)
.getResultList();
}
}
Hello World!
4. アプリケーションの起動
• デフォルト設定利用時はmainメソッド不要
• mvn package; java -jar target/xxx-swarm.jar
– 必要なモジュールのみjarにまとめられる
– JAX-RS+CDI+JPAアプリで94MB(WildFly全体約127M)。まだ大きい。
• サンプルコードが豊富
– https://github.com/wildfly-swarm/wildfly-swarm-examples
Hello World!
カスタム設定はmainメソッドに実装
public static void main(String[] args) throws Exception {
Container container = new Container();
/ /H2向けJDBCドライバの登録と、データソースの生成
container.fraction(new DatasourcesFraction()
.jdbcDriver("h2", (d) -> {
d.driverDatasourceClassName("org.h2.Driver");
d.xaDatasourceClass("org.h2.jdbcx.JdbcDataSource");
d.driverModuleName("com.h2database.h2");
})
.dataSource("MyDS", (ds) -> {
ds.driverName("h2");
ds.connectionUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;... ");
ds.userName("sa");
ds.password("sa");
})
);
....
Hello World!
カスタム設定はmainメソッドに実装
public static void main(String[] args) throws Exception {
Container container = new Container();
/ /H2向けJDBCドライバの登録と、データソースの生成
container.fraction(new DatasourcesFraction()
.jdbcDriver("h2", (d) -> {
d.driverDatasourceClassName("org.h2.Driver");
d.xaDatasourceClass("org.h2.jdbcx.JdbcDataSource");
d.driverModuleName("com.h2database.h2");
})
.dataSource("MyDS", (ds) -> {
ds.driverName("h2");
ds.connectionUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;... ");
ds.userName("sa");
ds.password("sa");
})
);
....
デフォルト設定を調べるには
Fraction: WildFlyのサブシステムのようなもの
• Swarmのソースより、xxxFraction.java クラスの中を確認
– デフォルト値はWildFlyの設定値 (standalone.xml) とほぼ同じ
public class JPAFraction extends JPA<JPAFraction> implements Fraction {
...
@Override
public void initialize(Container.InitContext initContext) {
if (!inhibitDefaultDatasource) {
final DatasourcesFraction datasources = new DatasourcesFraction()
.jdbcDriver(new JDBCDriver("h2")
.driverName("h2")
.driverDatasourceClassName("org.h2.driver")
.....
主なFraction
Java EE 以外からも機能を取り込み
• Java EE : JAX-RS, JSF, JPA, CDI, Transaction, JMS ...
• logstash
• サーバログをlogstashサーバ(TCP)に送る機能
• java -Dswarm.logstash.hostname -Dswarm.logstash.port
• Netflix OSS(Ribbon, Hystrix), Jolokia (JMX REST-API)
• 一覧はSwarmユーザガイド参照
https://wildfly-swarm.gitbooks.io/wildfly-swarm-users-guide/
SwarmによるJava EEの分解を見て
Java EE にもマイナーアップデートが欲しい
• Spring Frameworkは着実に進化
– 4.0 (2013/12) => 4.1 (2014/9) => 4.2 (2015/7)
• Java EE は標準化に時間が掛かる
– Java EE 7 (2013年) => Java EE 8 (2017年予定)
– 実装サーバは仕様がFinalになってから1年ぐらい後
– 例えば JCache + MVC + Java 8 RepetableAnnotation 対応で
Java EE 7.1 など
まとめ
まとめ
• Java EE 8 は2017年リリース予定
– HTTP/2対応、非同期、APIのシンプル化
– 徐々にではあるが、検討が進み始めている
• Java EE 周辺
– WildFly Swarmの進化に期待

JavaOne2015報告会 Java EE アップデート #j1jp

  • 1.
    JavaOne2015 - JavaEE 2015/11/14 上妻 宜人 (あげつま のりと)
  • 2.
    • APサーバサポート、Javaトラブルシューティング • ブログ見習いプログラミング日記 • twitter: @n_agetsu 上妻 宜人 (あげつま のりと)
  • 3.
    • Java EE8 のアップデート • Early Draft Review1: Servlet4.0, JMS2.1 • ドラフト未リリース: JAX-RS2.1, JPA2.2 • Java EE 周辺の話 • WildFly Swarm 本日の内容
  • 4.
    Java EE 8はまだ検討中。 この先の内容は、今後大きく変わる 可能性があります。
  • 5.
    Servlet4.0 現在のステータス: Early DraftReview JSR-368 https://jcp.org/en/jsr/detail?id=368
  • 6.
    Servlet 4.0 サーブレットコンテナもHTTP/2通信に対応 • 2015年5月RFC 7540で公開。SPDYが原型。 • 多重化 / バイナリフレーム / ヘッダ圧縮 • ヘッダの意味合い (GET/POST/200 OK など) は基本的に踏襲 client server client server client server 並行リクエストは、複数TCP接続が必要 ブラウザ実装によっては同時接続数『6』 1TCP接続で多重化 TCPコネクション_1 TCPコネクション_2..
  • 7.
    Servlet 4.0 HTTP/2 ストリームによる多重化 Connection: 1つのTCPコネクション Stream : 1つのリクエスト & レスポンスの組 Stream id=1 Stream id=1 .. N: http://chimera.labs.oreilly.com/books/1230000000545/ch12.html#HTTP2_STREAMS_MESSAGES_FRAMES Request Stream: 1 :method: GET ... Frame : HTTP2.0通信の最小単位 Stream: 1 :status:200 HEADERS frame Stream: 1 response data DATA frame Response
  • 8.
    Servlet 4.0 HTTP/2 ストリームによる多重化のServlet影響 •APIのユーザ視点では影響はあまりない • 1リクエスト => 1レスポンス の法則が崩れなければ、 doGet, doPostメソッドの現状の仕組みがそのまま使える • HttpServletRequest/HttpServletResponse へのメソッド追加 • int getStreamId() • ストリームIDを知りたい機会は少ないと思う
  • 9.
    Servlet 4.0 HTTP/2 サーバプッシュ clientserver .html .js .png .css • SSE/WebSocketとは用途が異なる • 関連リソースをサーバプッシュ • 例えばhtmlの要求がきたら • 関連のjs, png, css もプッシュする • 従来はインラインイメージを適用 • 1リクエスト => 1レスポンスが崩れる • 今までのHttpServletResponseは 1レスポンスが前提
  • 10.
    Servlet 4.0 HTTP/2 サーバプッシュのServlet影響 publicvoid doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { PushBuilder builder = request.getPushBuilder(); builder.setPath(“/style.css”); builder.push(); res.setContentType(“text/html”); PrintWriter out = res.getPrintWriter(); out.println(“<html>”); out.println(“<head>”) out.println(“<link rel=”stylesheet” type=”text/css” href=“style.css”>”); … }
  • 11.
    Servlet4.0 まとめ • HTTP/2対応 – サーブレットコンテナがHTTP/2に対応 – ストリームID取得, サーバプッシュ向けAPIの追加 • 本日は未紹介 – (検討中) Java9 Flow対応によるリクエスト処理
  • 12.
  • 13.
  • 14.
    JAX-RS2.1 非同期クライアントAPIの改善 • 並列で依存関係のあるWebAPIを呼び出したい • Jerseyには既に実装がある •RxJava Observable, Java 8 CompletableFuture 対応 出張手配 サービス 新幹線予約 ホテル予約大阪1泊2日で! 手配完了 料金請求 1. 予約を並列実行 2. 予約が終わったら 請求サービスに投げる
  • 15.
    JAX-RS2.1 非同期クライアント: rx()によるCompletationState取得 // Aの問い合わせ(非同期) WebTarget targetA = Client.newClient().target(...); CompletionStage<User> a = target1.request().resolveTemplate(“id”, 1) .rx().get(User.class); // Bの問い合わせ (非同期) CompletionState<Product> b = targetB.request().resolveTemplate(“id”, 1) .rx().get(Product.class); // AとBの結果を組み合わせて、Cに問い合わせ (非同期) CompletionState<String> c = a.thenCombine(b, (user, product) -> targetC.request() .resolveTemplate(“user”,user) .resolveTemplate(“prod”,product).rx().get(...))); // 最終的な結果の取得 c.join(); a b c 最終的な結果
  • 16.
    JAX-RS2.1 非同期クライアント: rx()によるCompletationState取得 // Aの問い合わせ(非同期) WebTarget targetA = Client.newClient().target(...); CompletionStage<User> a = target1.request().resolveTemplate(“id”, 1) .rx().get(User.class); // Bの問い合わせ (非同期) CompletionState<Product> b = targetB.request().resolveTemplate(“id”, 1) .rx().get(Product.class); // AとBの結果を組み合わせて、Cに問い合わせ (非同期) CompletionState<String> c = a.thenCombine(b, (user, product) -> targetC.request() .resolveTemplate(“user”,user) .resolveTemplate(“prod”,product).rx().get(...))); // 最終的な結果の取得 c.join(); a b c 最終的な結果
  • 17.
    JAX-RS2.1 非同期クライアント: アノテーションによる依存性制御 class DeclarativeRxHandler{ @FinalResult public String getC( @PartialResult(“A”) String a, @PartialResult(“B”) String b) { return a; } @PartialResult(“A”) public CompletableFuture<String> getA() {...} @PartialResult(“B”) public CompletableFuture<String> getB() {...} } A B C 最終的な結果
  • 18.
    JAX-RS2.1 ノンブロッキング I/O -背景 • 不安定/遅いネットワークからファイルアップロード • CPUは別スレッドに割当てられても、メモリは1MB消費し続ける @Path(“/upload”) public class FileUploadResource { @POST @Consumes(MediaType.MULTIPART_FORM_DATA) public void upload(@FormDataParam(“file”) InputStream input, ...) { byte[] buf = new byte[1024]; int readed; try { while ((readed = input.read(buf)) != -1) { // write file ... } catch (IOException e) {...} } データが来るまでブロック (64bitJVM)
  • 19.
    @POST @Consumes(MediaType.APPLICATION_OCTET_STREAM) public voidupload(@QueryParam(“path”) String path, @Context request, @Suspend AsyncResponse response) { FileOutputStream out = new FileOutputStream(tmpdir); byte[] buf = new byte[1024]; request.entity(input -> { try { if (input.isFinished()) { // データ読み込み完了 out.close(); response.resume(“Upload Completed”); } else { final int n = input.read(buffer); out.write(buffer, 0, n); } } catch (IOException e) {...} } } JAX-RS2.1 ノンブロッキング I/O - JavaOneで紹介されていたアイディア
  • 20.
    @POST @Consumes(MediaType.APPLICATION_OCTET_STREAM) public voidupload(@QueryParam(“path”) String path, @Context request, @Suspend AsyncResponse response) { FileOutputStream out = new FileOutputStream(tmpdir); byte[] buf = new byte[1024]; request.entity(input -> { try { if (input.isFinished()) { // データ読み込み完了 out.close(); response.resume(“Upload Completed”); } else { final int n = input.read(buffer); out.write(buffer, 0, n); } } catch (IOException e) {...} } } ブロックしない 読込可能データの発生毎に 繰り返しコールバックされる? JAX-RS2.1 ノンブロッキング I/O - JavaOneで紹介されていたアイディア
  • 21.
    JAX-RS2.1 ノンブロッキング I/O -まだまだ検討中 • 本当に必要? 色々と議論がある • ユーザレベルでNIOを意識しなくても良いのでは など? – MessageBodyReader, MessageBodyWriterの実装内に隠蔽 (JAX-RSランタイムの中の json read/write 時に利用) – Servlet コンテナのコネクタ実装としてのNIOで十分では?
  • 22.
    JMS2.1 現在のステータス: Early DraftReview JSR-368 https://jcp.org/en/jsr/detail?id=368
  • 23.
    JMS2.0 Java EE 7- JMS2.0のMDBを振り返る @MessageDriven( activationConfig = { @ActivationConfigProperty( propertyName="destinationType", propertyValue="javax.jms.Queue"), @ActivationConfigProperty( propertyName="destination", propertyValue="java:/queue/myQueue") }) public class SampleMDB implements MessageListener { @Override public void onMessage(Message message) { try { TextMessage textMessage = (TextMessage) message; System.out.println(textMessage.getText()); } catch (JMSException e) { e.printStackTrace(); } } }
  • 24.
    @MessageDriven( activationConfig = { @ActivationConfigProperty( propertyName="destinationType",propertyValue="javax.jms.Queue"), @ActivationConfigProperty( propertyName="destination", propertyValue="java:/queue/myQueue") }) public class SampleMDB implements MessageListener { @Override public void onMessage(Message message) { try { TextMessage textMessage = (TextMessage) message; System.out.println(textMessage.getText()); } catch (JMSException e) { e.printStackTrace(); } } } JMS2.0 Java EE 7 - JMS2.0のMDBを振り返る 何のリスナ (Queue or Topic)を 文字列で指定する必要がある
  • 25.
    @MessageDriven( activationConfig = { @ActivationConfigProperty( propertyName="destinationType",propertyValue="javax.jms.Queue"), @ActivationConfigProperty( propertyName="destination", propertyValue="java:/queue/myQueue") }) public class SampleMDB implements MessageListener { @Override public void onMessage(Message message) { try { TextMessage textMessage = (TextMessage) message; System.out.println(textMessage.getText()); } catch (JMSException e) { e.printStackTrace(); } } } JMS2.0 Java EE 7 - JMS2.0のMDBを振り返る インタフェースの実装、 Messageのキャストが必要
  • 26.
    JMS2.1 JMS2.1の主な機能追加 • MDBからMessageListenerの実装を不要とする • タイプセーフ •キャストの不要化 • 1クラスで複数コールバックメソッドを実装
  • 27.
    JMS2.1 JMS2.1ドラフト: @JMSQueueListener @MessageDriven public classSampleMDB { @JMSQueueListener (destionationLookup = “java:/queue/myQueue”) public void printMessage(TextMessage text) { try { System.out.println(text.getText()); } catch (JMSException e) { e.printStackTrace(); } } }
  • 28.
    @MessageDriven public class SampleMDB{ @JMSQueueListener (destionationLookup = “java:/queue/myQueue”) public void printQueue1Msg(TextMessage text) { …. } @JMSQueueListener (destionationLookup = “java:/queue/myQueue2”) public void printQueue2Msg(TextMessage text) { …. } } JMS2.1 JMS2.1ドラフト: 1クラスに複数コールバック定義
  • 29.
    • MDB停止中のトピック書き込みは検知できない • JMS2.0では @ActivationConfigProperty( propertyName="subscriptionDurability“,propertyValue="NonDurable") @MessageDriven public class SampleMDB { @JMSNonDurableTopicListener(destinationLookup=“java:/topic/myTopic”) public void printMessage(TextMessage text) { …. } } JMS2.1 JMS2.1ドラフト: トピック向け非永続化サブスクライバ
  • 30.
    @MessageDriven public class SampleMDB{ @JMSDurableTopicListener ( destinationLookup=“java:/topic/myTopic”, cliendId=“someid”, subscriptionName=“somename”) public void printMessage(TextMessage text) { …. } } • 全永続化サブスクライバの受信までメッセージ削除されない • JMS2.0では @ActivationConfigProperty( propertyName="subscriptionDurability“, propertyValue="Durable") @ActivationConfigProperty(propertyName=“clientid”, propertyValue=“someid”) @ActivationConfigProperty(propertyName="subscriptionName", propertyValue=“somename") JMS2.1 JMS2.1ドラフト: トピック向け永続化サブスクライバ
  • 31.
    JMS2.1 まとめ • 今のところはMDBのシンプル化が主な内容 •CDI管理Beanによるメッセージ受信は検討中 (Early Draft Review1には含まれていない)
  • 32.
  • 33.
    JPA2.2 検討中の主な項目 • Java SE8対応 • Date and Time API への対応 • @NamedQueryのRepeatableアノテーション対応 • スクロール機能の標準化 • 例: org.hibernate.ScrollableResults
  • 34.
    JPA2.2 スクロール機能の標準化 - getStreamResult() Queryq = em.createQuery(“select e from Employee e”); // OutOfMemoryError ?? List<Employee> employees = q.getResultList(); // 少ないJavaヒープメモリで動作 int total = q.getStreamResult().collect( Collectors.summingInt(Employee::getSalary));
  • 35.
    Java EE 8スケジュール Java EE 8 & GlassFish5リリースは2017上半期予定 • 2015 Q4 Early Draft • 2016 Q1 Public Review • 2016 Q4 Proposed Final Draft • 2017年上半期 Final 予定
  • 36.
    Java EE 周辺の話 SpringBoot風 Java EE “WildFly Swarm”
  • 37.
    WildFly Swarm Java EEで java -jar myapp.jar 起動 • Spring Boot風のJava EE • 2015/5 に1.0.0.Alpha1リリース – まだ実験的: (最新) 2015/10/25 1.0.0.Alpha5 • APサーバの事前インストールが不要になる • java -jar myapp.jar で手軽に起動
  • 38.
    なぜ WildFly Swarm SpringBootとは少し背景が違う • Spring Bootの背景 (集約) • 機能が豊富で、pom.xml の組み合わせ方法が難しい => 推奨組み合わせを作って、簡単に使えるようにした • WildFly Swarmの背景 (分解) • Java EE をフルセットで使う人は少ない => アプリで利用する機能だけ一式jarにまとめて軽量化
  • 39.
  • 40.
    Hello World! 2. uberjar を作成する wildfly-swarm-plugin <plugin> <groupId>org.wildfly.swarm</groupId> <artifactId>wildfly-swarm-plugin</artifactId> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> • Mavenプラグインによりmvn packageで実行可能jarを生成
  • 41.
    Hello World! 3. 通常と変わりなくコードを書く @Path("/") publicclass EmployeeResource { @Inject EntityManager em; @GET @Produces("application/json") public List<Employee> get() { return em.createNamedQuery("Employee.findAll", Employee.class) .getResultList(); } }
  • 42.
    Hello World! 4. アプリケーションの起動 •デフォルト設定利用時はmainメソッド不要 • mvn package; java -jar target/xxx-swarm.jar – 必要なモジュールのみjarにまとめられる – JAX-RS+CDI+JPAアプリで94MB(WildFly全体約127M)。まだ大きい。 • サンプルコードが豊富 – https://github.com/wildfly-swarm/wildfly-swarm-examples
  • 43.
    Hello World! カスタム設定はmainメソッドに実装 public staticvoid main(String[] args) throws Exception { Container container = new Container(); / /H2向けJDBCドライバの登録と、データソースの生成 container.fraction(new DatasourcesFraction() .jdbcDriver("h2", (d) -> { d.driverDatasourceClassName("org.h2.Driver"); d.xaDatasourceClass("org.h2.jdbcx.JdbcDataSource"); d.driverModuleName("com.h2database.h2"); }) .dataSource("MyDS", (ds) -> { ds.driverName("h2"); ds.connectionUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;... "); ds.userName("sa"); ds.password("sa"); }) ); ....
  • 44.
    Hello World! カスタム設定はmainメソッドに実装 public staticvoid main(String[] args) throws Exception { Container container = new Container(); / /H2向けJDBCドライバの登録と、データソースの生成 container.fraction(new DatasourcesFraction() .jdbcDriver("h2", (d) -> { d.driverDatasourceClassName("org.h2.Driver"); d.xaDatasourceClass("org.h2.jdbcx.JdbcDataSource"); d.driverModuleName("com.h2database.h2"); }) .dataSource("MyDS", (ds) -> { ds.driverName("h2"); ds.connectionUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;... "); ds.userName("sa"); ds.password("sa"); }) ); ....
  • 45.
    デフォルト設定を調べるには Fraction: WildFlyのサブシステムのようなもの • Swarmのソースより、xxxFraction.javaクラスの中を確認 – デフォルト値はWildFlyの設定値 (standalone.xml) とほぼ同じ public class JPAFraction extends JPA<JPAFraction> implements Fraction { ... @Override public void initialize(Container.InitContext initContext) { if (!inhibitDefaultDatasource) { final DatasourcesFraction datasources = new DatasourcesFraction() .jdbcDriver(new JDBCDriver("h2") .driverName("h2") .driverDatasourceClassName("org.h2.driver") .....
  • 46.
    主なFraction Java EE 以外からも機能を取り込み •Java EE : JAX-RS, JSF, JPA, CDI, Transaction, JMS ... • logstash • サーバログをlogstashサーバ(TCP)に送る機能 • java -Dswarm.logstash.hostname -Dswarm.logstash.port • Netflix OSS(Ribbon, Hystrix), Jolokia (JMX REST-API) • 一覧はSwarmユーザガイド参照 https://wildfly-swarm.gitbooks.io/wildfly-swarm-users-guide/
  • 47.
    SwarmによるJava EEの分解を見て Java EEにもマイナーアップデートが欲しい • Spring Frameworkは着実に進化 – 4.0 (2013/12) => 4.1 (2014/9) => 4.2 (2015/7) • Java EE は標準化に時間が掛かる – Java EE 7 (2013年) => Java EE 8 (2017年予定) – 実装サーバは仕様がFinalになってから1年ぐらい後 – 例えば JCache + MVC + Java 8 RepetableAnnotation 対応で Java EE 7.1 など
  • 48.
  • 49.
    まとめ • Java EE8 は2017年リリース予定 – HTTP/2対応、非同期、APIのシンプル化 – 徐々にではあるが、検討が進み始めている • Java EE 周辺 – WildFly Swarmの進化に期待