在复杂的企业IT架构中 web模块主要用途其实在展现层,它接收到用户的请求后委托后端的 ejb 完成业务逻辑(将业务交由ejb处理,可方便地获得保障业务事务及分布式事务、多客户端调用等好处),然后将ejb的处理结果以可视化形式展现给用户,如此的分层架构可以方便地对ejb业务层实施可复用和分布式。
ejb通常都是jar文件,web通常是war文件,一般都是独立部署,但是,有的时候我们也希望将某些ejb和web打包的一起部署,这就是企业应用ear。
maven 支持 ear 的管理。
假设要完成的ear中包行一个ejb和一个web,名称分别为:ejb3和webdemo,两个模块独立开发完成后执行 install 安装到本地maven库,建立一个ear模块(其实就是普通的maven项目,只是设置pom打包类型<packaging>ear</packaging>),如果要开发一个ejb,那么就设置<packaging>ejb</packaging>。
名称ejb3,其pom大致为:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>eden</artifactId> <groupId>com.conquer.eden</groupId> <version>1.0</version> </parent> <modelVersion>4.0.0</modelVersion> <packaging>ejb</packaging> <artifactId>ejb3</artifactId> <dependencies> <dependency> <groupId>javax.ejb</groupId> <artifactId>ejb-api</artifactId> <version>3.0</version> <scope>provided</scope> </dependency> <!--<dependency>--> <!--<groupId>org.eclipse.persistence</groupId>--> <!--<artifactId>javax.persistence</artifactId>--> <!--<version>2.0.5</version>--> <!--<scope>provided</scope>--> <!--</dependency>--> </dependencies> <build> <finalName>${artifactId}</finalName> <plugins> <plugin> <!--<groupId>org.apache.maven.plugins</groupId>--> <artifactId>maven-ejb-plugin</artifactId> <version>2.5</version> <configuration> <ejbVersion>3.0</ejbVersion> <!--<filterDeploymentDescriptor>true</filterDeploymentDescriptor>--> <!-- this is false by default --> <generateClient>true</generateClient> <!--用下面的方式进行 客户端生成定制--> <clientIncludes> <!-- 包含 test 下面的所有文件和文件夹 --> <!--<clientInclude>test/**</clientInclude>--> <!-- 包含 com/example 下面所有的文件,PS:不含文件夹--> <!--<clientInclude>com/example/*</clientInclude>--> </clientIncludes> <clientExcludes> <!-- 不包含 com/example 下的所有文件--> <!--<clientExclude>com/example/*</clientExclude>--> <!-- this will exclude all files and directories with the name sparrow under com/jack --> <!--<clientExclude>com/jack/**/sparrow</clientExclude>--> </clientExcludes> </configuration> </plugin> </plugins> </build> </project>
以上的pom文件需要注意的点:
1.打包类型:
<packaging>ejb</packaging>
2.EJB插件
<artifactId>maven-ejb-plugin</artifactId>
3.是否生成EJB客户端jar
<generateClient>true</generateClient>
关于
<generateClient>的介绍:
<generateClient>用于生成简单版的ejb客户端,通常只包含客户端使用到的接口而不包含实现类,
他的默认排除规则是:
当然,该规则也可以定制,可以定制需要添加和排除的文件,如下:
<configuration> <clientIncludes> <!-- this will include all files and directories under com/foo/bar --> <clientInclude>com/foo/bar/**</clientInclude> <!-- this will include all files and directories under com/foo/acme --> <clientInclude>com/foo/acme/**</clientInclude> <!-- this will include all files under com/example --> <clientInclude>com/example/*</clientInclude> </clientIncludes> <clientExcludes> <!-- this will exclude all files under com/example --> <clientExclude>com/example/*</clientExclude> <!-- this will exclude all files and directories with the name sparrow under com/jack --> <clientExclude>com/jack/**/sparrow</clientExclude> </clientExcludes> </configuration>
<dependency>
<groupId>com.conquer.eden</groupId>
<artifactId>xaejb</artifactId>
<version>1.0</version>
<!--<classifier>client</classifier>-->
<type>ejb-client</type>
</dependency>
官网参考:
http://maven.apache.org/plugins/maven-ejb-plugin/
http://maven.apache.org/plugins/maven-ejb-plugin/examples/generating-ejb-client.html
ejb的java代码:
public interface TestDAOEJB { String insertData(String data) throws Exception; String insertData2(String data) throws Exception; String insertData3(String data) throws Exception; }
import javax.ejb.*; import javax.naming.Context; import javax.naming.InitialContext; import javax.sql.DataSource; import java.io.IOException; import java.sql.Connection; import java.sql.Statement; import java.util.Properties; //@Stateless //@Stateless(mappedName = "TestDAOBean") @Stateful @Remote(value = TestDAOEJB.class) public class TestDAOBean implements TestDAOEJB { private static String otherNode1; private static String otherNode2; static { try { Properties properties = new Properties(); properties.load(TestDAOBean.class.getResourceAsStream("/config.properties")); otherNode1 = properties.getProperty("otherNode1"); otherNode2 = properties.getProperty("otherNode2"); } catch (IOException e) { e.printStackTrace(); } } /** * CREATE TABLE wangpl(name VARCHAR2(200)) */ @Override @TransactionAttribute(TransactionAttributeType.REQUIRED)//这是默认值,可以省略,或修改为其它事务策略 public String insertData(String data) throws Exception { String returnString = "insertData-OK"; Connection con = null; Statement statement = null; try { DataSource dataSource = (DataSource) new InitialContext().lookup("DataSource1"); con = dataSource.getConnection(); statement = con.createStatement(); String sql = "INSERT INTO wangpl VALUES('" + data + ":insertData')"; statement.execute(sql); } finally { // close xxx } // 调用远程节点 Properties p = new Properties(); p.put(Context.INITIAL_CONTEXT_FACTORY, "com.xxx.RemoteInitialContextFactory"); p.put(Context.PROVIDER_URL, otherNode1); InitialContext ctx = new InitialContext(p); TestDAOEJB remote = (TestDAOEJB) ctx.lookup("TestDAOBeanRemote"); remote.insertData2(data + "1"); return returnString; } @Override @TransactionAttribute(TransactionAttributeType.SUPPORTS) public String insertData2(String data) throws Exception { String returnString = "insertData2-OK"; Connection con = null; Statement statement = null; try { DataSource dataSource = (DataSource) new InitialContext().lookup("DataSource1"); con = dataSource.getConnection(); statement = con.createStatement(); String sql = "INSERT INTO wangpl VALUES('" + data + ":insertData2')"; statement.execute(sql); } finally { // close xxx } // 调用远程ejb Properties p = new Properties(); p.put(Context.INITIAL_CONTEXT_FACTORY, "com.xxx.RemoteInitialContextFactory"); p.put(Context.PROVIDER_URL, otherNode2); InitialContext ctx = new InitialContext(p); TestDAOEJB remote = (TestDAOEJB) ctx.lookup("TestDAOBeanRemote"); remote.insertData3(data + "1"); if (data.equals("11")) { throw new RuntimeException("************* Runtime Exception **************"); } return returnString; } @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public String insertData3(String data) throws Exception { String returnString = "insertData3-OK"; Connection con = null; Statement statement = null; try { DataSource dataSource = (DataSource) new InitialContext().lookup("DataSource1"); con = dataSource.getConnection(); statement = con.createStatement(); String sql = "INSERT INTO wangpl VALUES('" + data + ":insertData3')"; statement.execute(sql); } finally { // close xxx } if (data.equals("211")) { throw new RuntimeException("************* Runtime Exception **************"); } return returnString; } }
其pom大致如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <parent> <artifactId>eden</artifactId> <groupId>com.conquer.eden</groupId> <version>1.0</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>webdemo</artifactId> <packaging>war</packaging> <name>webdemo</name> <build> <finalName>${artifactId}</finalName> </build> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.conquer.eden</groupId> <artifactId>ejb3</artifactId> <version>1.0</version> <!--<classifier>client</classifier>--> <type>ejb-client</type> </dependency> </dependencies> </project>以上pom,要注意的是添加ejb的client依赖,指明类型是: <type>ejb-client</type>
web层业务代码 ,可以使用 @EJB @Resource 的注解方式,或者手工: new InitialContext(xx)来访问ejb。
其pom文件为:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>eden</artifactId> <groupId>com.conquer.eden</groupId> <version>1.0</version> </parent> <modelVersion>4.0.0</modelVersion> <packaging>ear</packaging> <artifactId>ear</artifactId> <dependencies> <dependency> <groupId>com.conquer.eden</groupId> <artifactId>ejb3</artifactId> <version>1.0</version> <type>ejb</type> </dependency> <dependency> <groupId>com.conquer.eden</groupId> <artifactId>webdemo</artifactId> <version>1.0</version> <type>war</type> </dependency> </dependencies> <build> <finalName>${artifactId}</finalName> <plugins> <plugin> <artifactId>maven-ear-plugin</artifactId> <version>2.10</version> <configuration> <!--<generateModuleId>true</generateModuleId>--> <!--指定打包范围,避免无用jar混乱加入--> <!--<packagingIncludes>META-INF/**,**/acme-*.jar,**/acme-*.war</packagingIncludes>--> <!--<packagingExcludes></packagingExcludes>--> <!--打包指定目录lib--> <defaultLibBundleDir>lib/</defaultLibBundleDir> <!--将多个war的共享包提取到父级别--> <skinnyWars>true</skinnyWars> <!--<includeLibInApplicationXml>true</includeLibInApplicationXml>--> <!--jboss 定制--> <!--<jboss>--> <!--<version>5</version>--> <!--<module-order>strict</module-order>--> <!--<unauthenticated-principal>guest</unauthenticated-principal>--> <!--<loader-repository>com.foo:loader=foo-application-1.0.ear</loader-repository>--> <!--</jboss>--> <modules> <!--jarModule:用于添加第三方库,配合includeInApplicationXml,可使其像一个开发的模块--> <jarModule> <!--<groupId>com.conquer.eden</groupId>--> <!--<artifactId>ejb3</artifactId>--> <!--<bundleFileName>ejb3.jar</bundleFileName>--> <!--<includeInApplicationXml>true</includeInApplicationXml>--> <!--<bundleDir>APP-INF/lib</bundleDir> 只更改位置,名称保持不变--> <!--<uri>APP-INF/lib/anotherName-1.2.3.jar</uri> 可定制位置和名称,需要指定名称--> <!--<excluded>true</excluded>--> <!--<moduleId>ejb3-id</moduleId>--> </jarModule> <ejbModule> <groupId>com.conquer.eden</groupId> <artifactId>ejb3</artifactId> <bundleFileName>ejb3.jar</bundleFileName> </ejbModule> <webModule> <groupId>com.conquer.eden</groupId> <artifactId>webdemo</artifactId> <bundleFileName>webdemo.war</bundleFileName> <!--<moduleId>webdemo-id</moduleId>--> </webModule> </modules> <!--<security>--> <!--<security-role id="SecurityRole_1234">--> <!--<role-name>manager</role-name>--> <!--</security-role>--> <!--<security-role id="SecurityRole_5678">--> <!--<description>My cool description</description>--> <!--<role-name id="RoleName_12">teller</role-name>--> <!--</security-role>--> <!--</security>--> <!--<version>6</version>--> <!--<env-entries>--> <!--<env-entry>--> <!--<description>A complete entry.</description>--> <!--<env-entry-name>complete</env-entry-name>--> <!--<env-entry-type>java.lang.Integer</env-entry-type>--> <!--<env-entry-value>4</env-entry-value>--> <!--</env-entry>--> <!--<env-entry>--> <!--<env-entry-name>no-type</env-entry-name>--> <!--<env-entry-value>4</env-entry-value>--> <!--</env-entry>--> <!--<env-entry>--> <!--<env-entry-name>no-value</env-entry-name>--> <!--<env-entry-type>java.lang.String</env-entry-type>--> <!--</env-entry>--> <!--</env-entries>--> </configuration> </plugin> </plugins> </build> </project>
以上pom要注意的是:
1.添加的两个依赖一个是ejb,一个是war包,指明的类型分别是:
<type>ejb</type>和<type>war</type>
2.EAR的打包插件
<artifactId>maven-ear-plugin</artifactId>
3.添加的ejb和war需要分别指明:<ejbModule> 和 <webModule> 并且都可以定制打进ear的名称,通过:<bundleFileName>
执行ear模块的package目标或执行ear模块maven的ear:ear可完成 ear的打包工作。
关于 maven-ear-plugin ,官网参考:http://maven.apache.org/plugins/maven-ear-plugin/