记录学习的脚步 以备不时之需
主要涉及到有状态会话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 真的要赞一下 很好用