Upload
norito-agetsuma
View
11.648
Download
5
Embed Size (px)
Citation preview
JavaOne2015 - Java EE2015/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 serverclient server
client server
並行リクエストは、複数 TCP 接続が必要ブラウザ実装によっては同時接続数『 6 』 1TCP 接続で多重化
TCP コネクション _1
TCP コネクション_2..
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
Servlet 4.0HTTP/2 ストリームによる多重化の Servlet 影響• API のユーザ視点では影響はあまりない• 1 リクエスト => 1 レスポンス の法則が崩れなければ、
doGet, doPost メソッドの現状の仕組みがそのまま使える• HttpServletRequest/HttpServletResponse へのメソッド追加• int getStreamId()
• ストリーム ID を知りたい機会は少ないと思う
Servlet 4.0HTTP/2 サーバプッシュclient server
.html
.js
.png
.css
• SSE/WebSocket とは用途が異なる• 関連リソースをサーバプッシュ• 例えば html の要求がきたら• 関連の js, png, css もプッシュす
る• 従来はインラインイメージを適
用• 1 リクエスト => 1 レスポンスが崩
れる• 今までの HttpServletResponse は
1 レスポンスが前提
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\”>”); …}
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
bc 最終的な結果
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 最終的な結果
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 最終的な結果
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.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(); } }}
@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) を文字列で指定する必要がある
@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 のキャストが必要
JMS2.1JMS2.1 の主な機能追加• MDB から MessageListener の実装を不要とする• タイプセーフ• キャストの不要化
• 1 クラスで複数コールバックメソッドを実装
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(); } }}
@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 クラスに複数コールバック定義
• MDB停止中のトピック書き込みは検知できない• JMS2.0 では
@ActivationConfigProperty( propertyName="subscriptionDurability“, propertyValue="NonDurable")
@MessageDrivenpublic class SampleMDB { @JMSNonDurableTopicListener(destinationLookup=“java:/topic/myTopic”) public void printMessage(TextMessage text) { …. }}
JMS2.1JMS2.1 ドラフト : トピック向け非永続化サブスクライバ
@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 ドラフト : トピック向け永続化サブスクライバ
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 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 で手軽に起動
なぜ 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") .....
主な 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/
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 の進化に期待