之前一直用JavaEE的服务器软件,CDI,JPA都是默认支持的,配置方面很简单。最近在学习axon和axon-cdi(CDI api 1.1),想使用轻量一点的应用服务器,选择了tomcat,配置方面总是有些问题,不过终于可以跑了,记录一下。
然后在WEB-INF/下增加beans.xml文件,在WEB-INF/web.xml中增加weld监听器,使这个web应用可以使用weld的CDI:
这样在普通的java类中就可以使用基本的CDI了。到这里都很简单。
按说,到这一步,部署后就可以直接使用strtus2的CDI了,但是实际上遇到了一个情况,就是启动tomcat时strtus2通过jndi查找BeanManager失败了。通过查找jboss上的文档,可以用如下方式配置:
以上内容,name="BeanManager"的是beanManager的jndi配置(还有个数据源的配置,下面也用的着),然后在应用的web.xml中增加资源配置:
有了以上配置,struts2就可以通过java:comp/env/BeanManager找到CDI的BeanManager了。同样,以上也包含了mysql的数据源的资源配置,同上面的context.xml中的内容相对应。
@PersistenceContext和@PersistenceUnit这两种注解都没有效果,只能手动初始化entitymanager:EntityManagerFactory factory = Persistence.createEntityManagerFactory("addresses");
1.首先,使用基本的tomcat 7,而不是TomEE,TomeEE不支持cdi-api 1.1
2.使用weld作为cdi的实现,它可以在j2se下运行,所以可以整合到tomcat中去。
3.用到了struts2,也需要一点配置才能使用cdi模块
maven工程,
首先,在pom.xml中增加cdi和weld的依赖:
<dependency>
<groupId>org.jboss.weld.servlet</groupId>
<artifactId>weld-servlet-core</artifactId>
<version>2.3.3.Final</version>
</dependency>
然后在WEB-INF/下增加beans.xml文件,在WEB-INF/web.xml中增加weld监听器,使这个web应用可以使用weld的CDI:
<listener>
<listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
</listener>
这样在普通的java类中就可以使用基本的CDI了。到这里都很简单。
第二步,配置struts2的cdi支持。增加struts2的cdi支持,增加依赖:
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-cdi-plugin</artifactId>
<version>2.3.20</version>
</dependency>
在web.xml中增加strtus2的filter配置:
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
<init-param>
<param-name>loggerFactory</param-name>
<param-value>
com.opensymphony.xwork2.util.logging.commons.CommonsLoggerFactory
</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
按说,到这一步,部署后就可以直接使用strtus2的CDI了,但是实际上遇到了一个情况,就是启动tomcat时strtus2通过jndi查找BeanManager失败了。通过查找jboss上的文档,可以用如下方式配置:
1.在web根目录下的META-INF中,建立一个context.xml文件,文件配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<!-- disables storage of sessions across restarts -->
<!-- <Manager pathname=""/> -->
<Resource name="BeanManager"
auth="Container"
type="javax.enterprise.inject.spi.BeanManager"
factory="org.jboss.weld.resources.ManagerObjectFactory"/>
<Resource name="jdbc/axon" auth="Container" type="javax.sql.DataSource"
maxActive="20" maxIdel="10" maxWait="1000" username="root"
password="1234" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/axon?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8">
</Resource>
<!-- enable injection into Servlet -->
<!-- <Listener className="org.jboss.weld.environment.tomcat.WeldLifecycleListener"/> -->
<!--
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>META-INF/context.xml</WatchedResource>
-->
</Context>
以上内容,name="BeanManager"的是beanManager的jndi配置(还有个数据源的配置,下面也用的着),然后在应用的web.xml中增加资源配置:
<resource-env-ref>
<description>Object factory for the CDI Bean Manager</description>
<resource-env-ref-name>BeanManager</resource-env-ref-name>
<resource-env-ref-type>
javax.enterprise.inject.spi.BeanManager
</resource-env-ref-type>
</resource-env-ref>
<resource-ref>
<description>MySQL DBCP</description>
<res-ref-name>jdbc/axon</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
有了以上配置,struts2就可以通过java:comp/env/BeanManager找到CDI的BeanManager了。同样,以上也包含了mysql的数据源的资源配置,同上面的context.xml中的内容相对应。
下面就是配置JPA了,META-INF/persistence.xml如下(不是webroot下的META-INF,是类路径下的,如在源代码的src/下):
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
<persistence-unit name="addresses" transaction-type="RESOURCE_LOCAL">
<non-jta-data-source>java:comp/env/jdbc/axon</non-jta-data-source>
<class>com.ngworld.dddproj.domain.model.query.AddressEntry</class>
<class>com.ngworld.dddproj.domain.model.query.ContactEntry</class>
<class>com.ngworld.dddproj.domain.model.command.ClaimedContactName</class>
<class>org.axonframework.eventstore.jpa.DomainEventEntry</class>
<class>org.axonframework.eventstore.jpa.SnapshotEventEntry</class>
<properties>
<property name="hibernate.archive.autodetection" value="class"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
<property name="hibernate.hbm2ddl.auto" value="validate" />
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>
</persistence>
注意,tomcat不是EE容器,只能使用transaction-type只能是RESOURCE_LOCAL,而且不能使用jta-data-source,而是non-jta-data-source。
,在pom.xml中增加hibernate和其jpa实现的依赖:、
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.1.0.Final</version>
</dependency>
这样文件方面就配置完成了,需要编写JPA中EntityManager的producer了:
package com.ngworld.dddproj.axonintegration;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Default;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnit;
@ApplicationScoped
public class EntityManagerProducer {
//@PersistenceContext//(unitName = "addresses")//non EE server use it
//private EntityManager entityManager;
//@PersistenceUnit(unitName="addresses") //EE server use this
//private EntityManagerFactory entityManagerFactory;
private static final EntityManagerFactory factory = Persistence.createEntityManagerFactory("addresses");
@Produces
@Default
@RequestScoped
public EntityManager create()
{
return factory.createEntityManager();
//return entityManager;
//return this.entityManagerFactory.createEntityManager();
}
public void dispose(@Disposes @Default EntityManager entityManager)
{
if (entityManager.isOpen())
{
entityManager.close();
}
}
}
@PersistenceContext和@PersistenceUnit这两种注解都没有效果,只能手动初始化entitymanager:EntityManagerFactory factory = Persistence.createEntityManagerFactory("addresses");
这样基本上就完成了,在使用entitymanager的地方,直接使用@Inject就可以了。