Tomcat…+Strus2+JPA(EclipseLink)をWildfly10+Struts2(ここはそのまま…)+CDI+EJB+JPA(Hibernate)でEEになったのになぜか色々動かなくなった件について上手に書けたら公開します。。
— Ryoichi Obara (@ryoichi_obara) June 16, 2016
上手に書けたら…と言いつつ上手に書けてはいないのですが、将来追記するかも。
放置な理由はテザリング回線が帯域制限で6月後半はほとんど書けなかったわけです。
46時間近くも動画流しっぱなしにしてたらそりゃ帯域制限かかりますわな。
言い訳多いですが本題へ。
before
Tomcat8 + Struts2 + JPA 2.0 (EclipseLink 入れた)
after
Wildfly 10 + Struts2 + CDI 1.2 (Weld 2.2) + EJB 3.2 + JPA 2.1 (標準Hibernate)
と、Struts2以外はWildfly10標準そのままなのです。
マイグレ理由
・社内展開が見込まれたのでEE環境へ移行してCDI,EJBの恩恵を受けまくりたい
ちなみにJSFにしなかった理由は
・展開時のスタディコストの軽減 (ゼロにはならないけど)
・JSFは結局Prime Facesがデファクトで必須になる感あったり
って感じの理由で戦略的に選択しなかったつもり。MVC 1.0カモン!
悩んだこと
よくわからない(って言っちゃいけない)けど2,3日ぐらい消費してしまった。
@EJBや@InjectできずNullPointerException
@PersistenceUnitも注入されない…
相談できる相手も居なかったのでここだけの話 地獄でした。
WELDのエラーとStackOverflowとにらめっこ。
ひととおりの答えでは全然解決しない。
でも全然Injectできない…
そもそもServletとCDIはビジネス層では関係ないでしょ…JSF必須なの?とか思ったり、でもWildfly起動時のログではちゃんとCDIに登録されている模様だし。
Injectできない…ツラい!悪循環。
やったこと
まずはTomcatで動いていたソースをそのまま移行。
Maven pom.xmlの整理。
ここでTomcat時代にはお手製で組み込んでいたJTA/JPAをprovidedにしたり
JPAをEclipseLink⇒Hibernate(Wildfly標準)に変更したり
EEのdependencyを組み込んで
<scope>provided</scope>を入れたりします。
そしてソースコードで
・対象クラスに@Statelessを付与、EJB内ではEntityManagerを@Inject
・ActionクラスからはEJBクラスのnewを@Inejctに書き換え
だが動かない。
ビジネスロジックInjectできない。。。
Webとビジネスロジックは別のMavenサブモジュールに配置していたので
試しに同じサブモジュールに配置してもこれまたダメ…
CDI 1.1以降本当は必要ないbeans.xmlも
ParentMavenProject/WebProject/src/main/webapp/WEB-INF/beans.xml
に配置してみたりしてもダメ。
(ちなみにsrc/main/resources/META-INF/beans.xmlでも良かったがjboss-deployment-structure.xmlやweb.xmlがあるのでwebapp/WEB-INF配下にした。)
<?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="annotated">
</beans>
<!-- http://n-agetsuma.hatenablog.com/entry/2013/08/18/130358 より引用 -->
でも
YYYY-MM-DD HH:MM:SS,SSS INFO [org.jboss.as.ejb3.deployment] (MSC service thread 1-3) WFLYEJB0473: JNDI bindings for session bean named '【EJBサービス名】' in deployment unit 'deployment "【アプリ名】.war"' are as follows:
java:global/【アプリ名】/【EJBサービス名】!【パッケージ名】.【EJBサービス名】
java:app/【アプリ名】/【EJBサービス名】!【パッケージ名】.【EJBサービス名】
java:module/【EJBサービス名】!【パッケージ名】.【EJBサービス名】
java:global/【アプリ名】/【EJBサービス名】
java:app/【アプリ名】/【EJBサービス名】
java:module/【EJBサービス名】
な感じなのでWFLYEJB0473でCDIには登録されている模様。
試しにWildfly 8.2.1.Final も入れて動かしてみるも同じ。。
でも新規でmaven-archetypeよりWildfly-CDI-JPA入りのものを落としてくるとそれは動く。。
もぅ…
ちなみに使ったのは
br.com.address.archetypes:struts2-archetype:1.5
Descriptionが
an archetype web 3.0 + struts2 (bootstrap + jquery) + JPA 2.1 with struts2 login system
といった所、かなり安心感ありますw
Struts2 CDI Pluginなるものを発見
既にEE環境なのになぜpluginでCDIを入れなければいけないのかという葛藤は置いてとけないけどぐっとこらえて‥
でも動かず...
そしてまだまだ色々やってるうちに動くように
ごめんなさいごめんなさい。
よくよく振り返ると
に記載があるように
スコープとしては暗黙的に@Dependentとみなされますが、明示的にスコープアノテーションが付与されていないため、インジェクション対象とならない為です。
bean-discovery-mode="annotated"の場合@Dependentだけだとダメよと。
今回は
public class Action {
@EJB
EJBService service;
}
@Stateless
public class EJBService {
@Inject
private EntityManager em;
}
@Named
@Dependent
public class EntityManagerProducer {
@PersistenceContext(unitName="hogehoge")
@Produces
private EntityManager em;
}
だったのですがここらへんが一番アヤシイ感じではあります。
反省点としてはどこだったんだろう…と。。
同じ悩みの方は、多分もうドハマリ中だと思うので
新規でMaven archetype (br.com.address.archetypes:struts2-archetype:1.5)から
現在の実装に寄せていくと動くようになると思います。(勝手…)