49
JavaOne2015 - Java EE 2015/11/14 上上 上上 ( 上上上上 上上上 )

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

Embed Size (px)

Citation preview

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

JavaOne2015 - Java EE2015/11/14 上妻 宜人 ( あげつま のりと )

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

• AP サーバサポート、 Java トラブルシューティング• ブログ 見習いプログラミング日記• twitter: @n_agetsu

上妻 宜人 ( あげつま のりと )

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

• Java EE 8 のアップデート• Early Draft Review1: Servlet4.0, JMS2.1

• ドラフト未リリース : JAX-RS2.1, JPA2.2

• Java EE 周辺の話• WildFly Swarm

本日の内容

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

Java EE 8 はまだ検討中。この先の内容は、今後大きく変わる可能性があります。

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

Servlet4.0現在のステータス : Early Draft Review

JSR-368 https://jcp.org/en/jsr/detail?id=368

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

Servlet 4.0サーブレットコンテナも HTTP/2 通信に対応• 2015 年 5 月 RFC 7540 で公開。 SPDY が原型。• 多重化 / バイナリフレーム / ヘッダ圧縮• ヘッダの意味合い (GET/POST/200 OK など ) は基本的に踏

襲client serverclient server

client server

並行リクエストは、複数 TCP 接続が必要ブラウザ実装によっては同時接続数『 6 』 1TCP 接続で多重化

TCP コネクション _1

TCP コネクション_2..

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

Servlet 4.0HTTP/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 frameStream: 1

response data

DATA frameResponse

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

Servlet 4.0HTTP/2 ストリームによる多重化の Servlet 影響• API のユーザ視点では影響はあまりない• 1 リクエスト => 1 レスポンス の法則が崩れなければ、

doGet, doPost メソッドの現状の仕組みがそのまま使える• HttpServletRequest/HttpServletResponse へのメソッド追加• int getStreamId()

• ストリーム ID を知りたい機会は少ないと思う

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

Servlet 4.0HTTP/2 サーバプッシュclient server

.html

.js

.png

.css

• SSE/WebSocket とは用途が異なる• 関連リソースをサーバプッシュ• 例えば html の要求がきたら• 関連の js, png, css もプッシュす

る• 従来はインラインイメージを適

用• 1 リクエスト => 1 レスポンスが崩

れる• 今までの HttpServletResponse は

1 レスポンスが前提

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

Servlet 4.0HTTP/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\”>”); …}

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

Servlet4.0 まとめ• HTTP/2 対応– サーブレットコンテナが HTTP/2 に対応– ストリーム ID 取得 , サーバプッシュ向け API の追加

• 本日は未紹介– ( 検討中 ) Java9 Flow 対応によるリクエスト処理

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

JAX-RS2.1現在のステータス : ドラフト未リリースJSR-370 https://jcp.org/en/jsr/detail?id=370

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

JAX-RS2.1主なテーマ• 非同期クライアント API の改善• ノンブロッキング I/O

• Server-Sent Event

– Jersey 実装と同じ

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

JAX-RS2.1非同期クライアント API の改善• 並列で依存関係のある WebAPI を呼び出したい• Jersey には既に実装がある• RxJava Observable, Java 8 CompletableFuture 対応

出張手配サービス

新幹線予約ホテル予約大阪 1 泊 2 日で!

手配完了料金請求

1. 予約を並列実行

2. 予約が終わったら請求サービスに投げる

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

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

bc 最終的な結果

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

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

bc 最終的な結果

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

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

BC 最終的な結果

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

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)

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

@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 で紹介されていたアイディア

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

@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 で紹介されていたアイディア

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

JAX-RS2.1ノンブロッキング I/O - まだまだ検討中• 本当に必要? 色々と議論がある• ユーザレベルで NIO を意識しなくても良いのでは など?

– MessageBodyReader, MessageBodyWriter の実装内に隠蔽(JAX-RS ランタイムの中の json read/write 時に利用 )

– Servlet コンテナのコネクタ実装としての NIO で十分では?

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

JMS2.1現在のステータス : Early Draft Review

JSR-368 https://jcp.org/en/jsr/detail?id=368

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

JMS2.0Java 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(); } }}

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

@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.0Java EE 7 - JMS2.0 の MDB を振り返る何のリスナ (Queue or Topic) を文字列で指定する必要がある

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

@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.0Java EE 7 - JMS2.0 の MDB を振り返る

インタフェースの実装、Message のキャストが必要

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

JMS2.1JMS2.1 の主な機能追加• MDB から MessageListener の実装を不要とする• タイプセーフ• キャストの不要化

• 1 クラスで複数コールバックメソッドを実装

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

JMS2.1JMS2.1 ドラフト : @JMSQueueListener

@MessageDrivenpublic class SampleMDB { @JMSQueueListener (destionationLookup = “java:/queue/myQueue”) public void printMessage(TextMessage text) { try { System.out.println(text.getText()); } catch (JMSException e) { e.printStackTrace(); } }}

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

@MessageDrivenpublic class SampleMDB { @JMSQueueListener (destionationLookup = “java:/queue/myQueue”) public void printQueue1Msg(TextMessage text) { …. }

@JMSQueueListener (destionationLookup = “java:/queue/myQueue2”) public void printQueue2Msg(TextMessage text) { …. }}

JMS2.1JMS2.1 ドラフト : 1 クラスに複数コールバック定義

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

• MDB停止中のトピック書き込みは検知できない• JMS2.0 では

@ActivationConfigProperty( propertyName="subscriptionDurability“, propertyValue="NonDurable")

@MessageDrivenpublic class SampleMDB { @JMSNonDurableTopicListener(destinationLookup=“java:/topic/myTopic”) public void printMessage(TextMessage text) { …. }}

JMS2.1JMS2.1 ドラフト : トピック向け非永続化サブスクライバ

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

@MessageDrivenpublic 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.1JMS2.1 ドラフト : トピック向け永続化サブスクライバ

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

JMS2.1 まとめ• 今のところは MDB のシンプル化が主な内容• CDI管理 Bean によるメッセージ受信は検討中

(Early Draft Review1 には含まれていない )

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

JPA2.2現在のステータス : ドラフト未リリース

JSR なし ( 状況は JIRA参照 https://java.net/jira/browse/JPA_SPEC)

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

JPA2.2検討中の主な項目• Java SE 8 対応• Date and Time API への対応• @NamedQuery の Repeatable アノテーション対応

• スクロール機能の標準化• 例 : org.hibernate.ScrollableResults

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

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));

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

Java EE 8 スケジュールJava EE 8 & GlassFish5 リリースは 2017 上半期予定• 2015 Q4 Early Draft

• 2016 Q1 Public Review

• 2016 Q4 Proposed Final Draft

• 2017 年上半期 Final 予定

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

Java EE 周辺の話 Spring Boot風 Java EE “WildFly Swarm”

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

WildFly SwarmJava 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 で手軽に起動

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

なぜ WildFly Swarm Spring Boot とは少し背景が違う• Spring Boot の背景 (集約 )• 機能が豊富で、 pom.xml の組み合わせ方法が難しい => 推奨組み合わせを作って、簡単に使えるようにした

• WildFly Swarm の背景 (分解 )• Java EE をフルセットで使う人は少ない => アプリで利用する機能だけ一式 jar にまとめて軽量化

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

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 追加

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

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 を生成

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

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(); }}

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

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

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

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"); }) ); ....

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

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"); }) ); ....

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

デフォルト設定を調べるには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") .....

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

主な FractionJava 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/

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

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 など

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

まとめ

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

まとめ• Java EE 8 は 2017 年リリース予定– HTTP/2 対応、非同期、 API のシンプル化– 徐々にではあるが、検討が進み始めている

• Java EE 周辺– WildFly Swarm の進化に期待