记录学习的脚步 以备不时之需
主要涉及到有状态会话Bean与无状态会话Bean ,本地接口与远程接口,依赖注入EJB服务与数据源
理论方面知识简单提一下吧 毕竟我也说的不是特别精辟
会话Bean一般用于处理业务层操作,有状态Bean与无状态Bean的区别在于是否记录用户的状态信息 ,有状态Bean记录用户的状态信息,采用(写回(不使用时,将Bean的状态写入硬盘)-激活(需要使用时,从硬盘中恢复其状态信息)机制进行控制),而无状态Bean采用实力池方式控制,类似于数据库连接池
本地接口与远程接口的区别在于,想要使用本地接口,本地接口与想要使用的业务类代码必须处于一个JVM中,例如部署在一个jboss容器中,本地接口的出现是为了减少远程接口的网络开销、协议解析开销之类的,总之就是加快速度
依赖注入--都很熟悉了 不解释了
好吧 用一个HelloWorld展现吧
从一个无状态HelloWorld类开始吧
package com.undergrowth.hello.impl; import java.sql.Connection; import java.sql.ResultSet; import java.sql.sqlException; import java.sql.Statement; import javax.annotation.Resource; import javax.ejb.EJB; import javax.ejb.Local; import javax.ejb.Remote; import javax.ejb.Stateless; import javax.sql.DataSource; import com.undergrowth.hello.HelloWorldLocal; import com.undergrowth.hello.HelloWorldRemote; import com.undergrowth.hello.Other; /** * Session Bean implementation class HelloWorld */ @Stateless @Remote(HelloWorldRemote.class) @Local({HelloWorldLocal.class}) public class HelloWorld implements HelloWorldRemote,HelloWorldLocal { //依赖注入其他EJB服务 @EJB(beanName="OtherBean") Other other; //注入数据源 @Resource(mappedName="java:/myDataSource") DataSource dataSource; /** * Default constructor. */ public HelloWorld() { } /** * EJB测试方法 */ @Override public String sayHello(String what) { // TODO Auto-generated method stub //通过数据源 获取信息 String name=connDb(Integer.valueOf(what)); return "你好,"+what+",我是EJB HELLO WORLD!!"+"\n"+other.sayOther(what)+"\n"+"我知道你叫"+name; } /** * 本该单独分开写的 * 简单处理 就在这写了 * @param id * @return */ private String connDb(int id) { String str=null; Connection conn = null; try { conn = dataSource.getConnection(); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT st.name from student st WHERE st.id="+id); if (rs.next()) str = rs.getString(1); rs.close(); stmt.close(); } catch (sqlException e) { e.printStackTrace(); }finally{ try { if(null!=conn && !conn.isClosed()) conn.close(); } catch (sqlException e) { e.printStackTrace(); } } return str; } }
看到他有两个实现接口,一个本地,一个远程
远程接口
package com.undergrowth.hello; import javax.ejb.Local; import javax.ejb.Remote; /** * 远程接口 * HelloWorld Remote interface */ public interface HelloWorldRemote { public String sayHello(String what); }本地接口
package com.undergrowth.hello; /** * 本地接口 * @author Administrator * */ public interface HelloWorldLocal { public String sayHello(String what); }
哦 还有一个依赖注入的EJB服务 使用@EJB注解
Other接口
package com.undergrowth.hello; /** * 测试接口 * @author Administrator * */ public interface Other { public String sayOther(String what); }
有状态的Bean
package com.undergrowth.hello.impl; import javax.ejb.Stateless; import com.undergrowth.hello.Other; /** * 测试@EJB 依赖注入 使用其他EJB服务 * Other不写Remote或者Local的话 默认为本地接口 * @author Administrator * */ @Stateless public class OtherBean implements Other { @Override public String sayOther(String what) { // TODO Auto-generated method stub return what+",我是other"; } }
好吧 到目前为止 准备了三个接口 一个远程 两个本地
还有两个会话Bean,一个有状态 ,一个没有状态
哦 对了 还有使用了@Resource 注入了jboss数据源 得去配置一下
在
jboss\jboss-as-7.1.1.Final\standalone\configuration下的standalone.xml中 在
<subsystem xmlns="urn:jboss:domain:datasources:1.0"> <datasources>元素下添加数据源 修改后如下
<datasources> <datasource jndi-name="java:jboss/datasources/ExampleDS" pool-name="ExampleDS" enabled="true" use-java-context="true"> <connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1</connection-url> <driver>h2</driver> <security> <user-name>sa</user-name> <password>sa</password> </security> </datasource> <datasource jta="true" jndi-name="java:/myDataSource" pool-name="OraclesqlDS" enabled="true" use-java-context="true" use-ccm="true"> <connection-url>jdbc:oracle:thin:@localhost:1521:orcl</connection-url> <driver>oracle</driver> <transaction-isolation>TRANSACTION_READ_COMMITTED</transaction-isolation> <pool> <min-pool-size>10</min-pool-size> <max-pool-size>100</max-pool-size> <prefill>true</prefill> <use-strict-min>false</use-strict-min> <flush-strategy>FailingConnectionOnly</flush-strategy> </pool> <security> <user-name>u1</user-name> <password>u1</password> </security> </datasource> <drivers> <driver name="h2" module="com.h2database.h2"> <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class> </driver> <driver name="oracle" module="com.oracle.ojdbc6"> <xa-datasource-class>oracle.jdbc.xa.client.OracleXADataSource</xa-datasource-class> </driver> </drivers> </datasources>
因为jboss7的模块化管理 详情可参考 http://vase.iteye.com/blog/1299425
哦 现在剩下的就是将上面的会话Bean打包 发布到JBOSs中 好的 来个ant的build.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- ================================================ --> <!-- Sample buildfile for jar components --> <!-- --> <!-- ================================================ --> <project name="HelloWorld" basedir="."> <!-- 定义属性 --> <property name="src.dir" value="${basedir}\src" /> <property environment="env" /> <property name="jboss.home" value="${env.JBOSS_HOME}"/> <property name="jboss.server.home" value="standalone" /> <property name="dep" value="deployments" /> <property name="build.dir" value="${basedir}\build" /> <path id="build.classpath"> <fileset dir="${basedir}\lib"> <include name="*.jar" /> </fileset> <pathelement location="${build.dir}" /> </path> <!-- - - - - - - - - - - - - - --> <!-- target: init --> <!-- - - - - - - - - - - - - - --> <target name="init"> <delete dir="${build.dir}"></delete> <mkdir dir="${build.dir}"></mkdir> </target> <!-- ========================= --> <!-- target: compile --> <!-- ========================= --> <target name="compile" depends="init" description="--> compile this component" > <javac srcdir="${src.dir}" destdir="${build.dir}" includes="com/**"> <classpath refid="build.classpath" /> </javac> </target> <!-- 打包 --> <target name="ejbjar" depends="compile" description="打包ejb"> <jar jarfile="${basedir}\${ant.project.name}.jar"> <fileset dir="${build.dir}"> <include name="**/*.class"></include> </fileset> <Metainf dir="${src.dir}\Meta-INF"></Metainf> </jar> </target> <!-- 部署 --> <target name="delopy" depends="ejbjar" description="部署ejb"> <copy file="${basedir}\${ant.project.name}.jar" todir="${jboss.home}\${jboss.server.home}\${dep}\" /> </target> <!-- 卸载ejb --> <target name="undeploy" description="卸载ejb"> <delete file="${jboss.home}\${jboss.server.home}\${dep}\${ant.project.name}.jar"></delete> </target> <!-- 打包接口 --> <target name="package_inter" depends="compile" description="打包接口"> <jar jarfile="${basedir}\${ant.project.name}Interface.jar"> <fileset dir="${build.dir}"> <exclude name="**/impl/*.class"></exclude> </fileset> </jar> </target> </project>
运行ant的deploy 之后 在jboss看到部署信息
23:52:03,775 INFO [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-2) JNDI bindings for session bean named OtherBean in deployment unit deployment "HelloWorld.jar" are as follows: java:global/HelloWorld/OtherBean!com.undergrowth.hello.Other java:app/HelloWorld/OtherBean!com.undergrowth.hello.Other java:module/OtherBean!com.undergrowth.hello.Other java:global/HelloWorld/OtherBean java:app/HelloWorld/OtherBean java:module/OtherBean
23:52:03,792 INFO [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-2) JNDI bindings for session bean named HelloWorld in deployment unit deployment "HelloWorld.jar" are as follows: java:global/HelloWorld/HelloWorld!com.undergrowth.hello.HelloWorldRemote java:app/HelloWorld/HelloWorld!com.undergrowth.hello.HelloWorldRemote java:module/HelloWorld!com.undergrowth.hello.HelloWorldRemote java:jboss/exported/HelloWorld/HelloWorld!com.undergrowth.hello.HelloWorldRemote java:global/HelloWorld/HelloWorld!com.undergrowth.hello.HelloWorldLocal java:app/HelloWorld/HelloWorld!com.undergrowth.hello.HelloWorldLocal java:module/HelloWorld!com.undergrowth.hello.HelloWorldLocal
看到HelloWorld既有远程接口又有本地接口 而Other只有本地接口
好了 服务已经在JBOSS的JNDI中了 现在使用客户端进行调用
运行 ant 的package_inter 打包接口
将打包好的接口 拷贝到 客户端测试项目 HelloWorldWeb 中 在index.jsp中 加入一段代码
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ page import="javax.naming.*,com.undergrowth.hello.*,com.undergrowth.ejb3.client.*" %> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title> <Meta http-equiv="pragma" content="no-cache"> <Meta http-equiv="cache-control" content="no-cache"> <Meta http-equiv="expires" content="0"> <Meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <Meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <% try { //本地接口的使用 需要本地接口与EJB应用在一个JVM里面 本地接口才能找到对应部署的EJB应用 HelloWorldLocal helloWorld=HelloWorldClient.lookupRemoteHelloWorldBean(); out.println(helloWorld.sayHello("1"));; } catch (NamingException e) { // TODO Auto-generated catch block e.printStackTrace(); } %> </body> </html>
这里调用本地接口 因为测试客户端与服务在一个JBOSS中
JBOSS7的查找JNDI的方法 与之前的版本稍微不一样 如下
public static HelloWorldLocal lookupRemoteHelloWorldBean() throws NamingException { final Hashtable jndiProperties = new Hashtable(); jndiProperties.put(Context.URL_PKG_PREFIXES,"org.jboss.ejb.client.naming"); final Context context = new InitialContext(jndiProperties); // The app name is the application name of the deployed EJBs. This is typically the ear name // without the .ear suffix. However,the application name could be overridden in the application.xml of the // EJB deployment on the server. // Since we haven't deployed the application as a .ear,the app name for us will be an empty string final String appName = ""; // This is the module name of the deployed EJBs on the server. This is typically the jar name of the // EJB deployment,without the .jar suffix,but can be overridden via the ejb-jar.xml // In this example,we have deployed the EJBs in a jboss-as-ejb-remote-app.jar,so the module name is // jboss-as-ejb-remote-app final String moduleName = "HelloWorld"; // AS7 allows each deployment to have an (optional) distinct name. We haven't specified a distinct name for // our EJB deployment,so this is an empty string final String distinctName = ""; // The EJB name which by default is the simple class name of the bean implementation class final String beanName = "HelloWorld"; // the remote view fully qualified class name // final String viewClassName = HelloWorldRemote.class.getName(); final String viewClassName = HelloWorldLocal.class.getName(); // let's do the lookup return (HelloWorldLocal) context.lookup("ejb:" + appName + "/" + moduleName + "/" + distinctName + "/" + beanName + "!" + viewClassName); }
哦 还有一个 jboss客户端访问jboss服务器的参数文件 文件名为:jboss-ejb-client.properties 放在src目录下即可
endpoint.name=client-endpoint remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false remote.connections=default remote.connection.default.host= localhost remote.connection.default.port = 4447 remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false remote.connection.default.username=qq remote.connection.default.password=q
参考文档 :jboss官方参考手册 https://docs.jboss.org/author/display/AS71/EJB+invocations+from+a+remote+client+using+JNDI
发布测试客户端 访问index.jsp 输出如下
你好,1,我是EJB HELLO WORLD!! 1,我是other 我知道你叫Eason
即可看到 这里获取JBOSS的JNDI树中发布的服务获取到会话Bean 并转给本地接口 本地接口 进行调用相应的服务 完成功能
对于JBOSS 真的要赞一下 很好用