概要
本来はJava EE環境(Java EE サーバ上)で動くCDIを、Tomcat(非Java EE サーバ)で動かしてみます。
CDIの参照実装であるWeldを使います。
シンプルな構成にしたいので、素のServletにDIするものとします。
今回作成したサンプルコードは、GitHubにアップしてあります。
https://github.com/sumeragizzz/weldservlet-examples
環境
Windows 10 Pro 64bit
Java SE 8 Update 102 64bit
Apache Tomcat 8.0.36 64bit
Weld Servlet 2.4.0.Final
準備
Maven
ビルドツールにMavenを使用します。
pom.xmlに以下の依存情報を追加します。
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.weld.servlet</groupId>
<artifactId>weld-servlet</artifactId>
<version>2.4.0.Final</version>
</dependency>
前者はHttpServletなどのServlet関連クラスをコンパイル時に参照できるようにする為。
後者は今回のテーマであるCDIの実装です。
web.xml
Sevlet 3.0からは自動的にSevletを検出してくれるので、ほぼ何も定義していません。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<display-name>Archetype Created Web Application</display-name>
</web-app>
beans.xml
CDIを有効にする為、beans.xmlを用意します。
前回の投稿にも書きましたが、0byteファイルでも有効になります。
サンプルの都合でインターセプターを定義したくらいで、有効化の為に必要な定義はありません。
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="all">
<interceptors>
<class>examples.weldservlet.interceptor.ZonedInterceptor</class>
</interceptors>
</beans>
実装
サンプルなので処理内容は特に意味の無いものになっています。
Sevletに@InjectでDIできます。
@WebServlet("/NowServlet")
public class NowServlet extends HttpServlet {
@Inject
private DateTimeFormatBean dateTimeFormatBean;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().append(dateTimeFormatBean.get());
}
}
DIしたCDI Beanに別のCDI BeanをDIできます。
public class DateTimeFormatBean {
@Inject
private NowBean nowBean;
public String get() {
return nowBean.get().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
}
}
別のCDI Beanはインターセプターを適用しました。
@ZonedInterceptorBinding
public class NowBean {
public ZonedDateTime get() {
return ZonedDateTime.now();
}
}
インターセプターの実装は下記の通り。
@Interceptor
@ZonedInterceptorBinding
public class ZonedInterceptor {
@AroundInvoke
public Object invoke(InvocationContext context) throws Exception {
ZonedDateTime result = ZonedDateTime.class.cast(context.proceed());
return result.withZoneSameInstant(ZoneId.of("America/New_York"));
}
}
@Inherited
@InterceptorBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
public @interface ZonedInterceptorBinding {
}
Tomcatにデプロイして、下記のURLにブラウザからアクサスします。
http://localhost:8080/weldservlet-examples/NowServlet
ブラウザに日時が表示されたら成功です。
2016-10-12T11:08:42.372
まとめ
pom.xmlに依存情報の追加と、beans.xmlの作成くらいなので、意外と手軽に導入できます。
ただ、実際には素のSevletを使う機会は少ないでしょう。
現実的にはJAX-RSなどとの組み合わせになるので、いずれこちらも投稿したいと思います。
参考