解释题目:为什么叫Toy企业应用,因为接下来全文将要描述的应用(home-test-all.ear)没有任何实际应用价值,之所以发布他,只是为了应用EJB相关技术;
解释企业应用:
一个企业应用是指按照JavaEE标准开发出来比较大型的企业级应用;
一般这样的应用以.ear结尾命名,可以运行在任何JavaEE容器中;
一般一个应用中包括很多模块,如业务处理EJB,Web Client war,描述XML文件等。
关键字:EJB, JMS, JPA, Oracle10g, Ant, Hibernate,Jboss ear中发布war
开发工具:Eclipse 3.6,jboss-eap-4.3,apache-ant-1.6.5,Oracle 10g
应用设计思路描述:通过两幅图来说明设计思路
在Jboss中发布完成时Jboss Deploy目录结构:
通过此图可以得到如下信息:
发布应用的J2EE容器是JBoss
该应用名叫home-test-all.ear
该应用中包括六个大模块
设计思路图:
图中有向箭头代表调运关系,中间大矩形框表示EJB容器,说明每个模块的作用和调运关系:
Http Web Client | 前台界面,指一些浏览器,本例子中设计可以通过浏览器访问我们的应用查看相关信息(查看应用运行日志记录,查看数据库操作记录) |
Entry Web War | 包括一个处理核心业务的Servlet(ControllerServlet),所有前台请求都被此Servlet受理,此Servlet处理完后将结果转发会前台 |
CommonUtil | 包括应用运行中所需的工具类,该应用中的TimerUtil就是记录一次数据库操作(一次Transaction 过程)所需的时间,将所需时间发布到我们定义的JMS Queue中,发布过程是异步处理,在线程中完成 |
Persistence Entity EJB | 定义了所有实体Bean,这些Bean分为两类,一类是User相关实体,而另一类是记录日志相关的实体,这些实体分别在处理日志的LoggerService Session Bean,UserService Session Bean,监听日志Queue的Audit Message Driven Bean运用 |
loggerService EJB | 无状态Session Bean,核心业务处理都是在这里完成的,Web Client调运它查看相关日志记录,命令行Client调运它向数据库中插入数据,它调运UserService Bean处理对User对象的增删改查,调运TimeUtil工具类记录时间日志,与数据库交互获取日志信息 |
UserService EJB | 无状态Session Bean,仅仅负责对User对象持久化维护,包括一些增删改查操作,被LoggerService Session Bean调运 |
JMS Queue | 保存日志信息的Queue,此应用中TimerUtil是他的消息发送者,Audit Message Driven Bean是他消息订阅者 |
Audit Messaging EJB | 是一个消息驱动Bean,主要功能是监听日志消失Queue,将受到消息内容提取,保存到数据库 |
Oracle 10g | 该应用中用到数据存储的数据库 |
Command line Client | java Client,用来向数据库中插入数据 |
总结设计思路:
设计的目的主要是用来测试在EJB Session Bean中通过JPA小数据库中插入数据和读取数据所需时间,插入数据包括插入单个数据,插入批量数据,读取单个和读取批量数据;
设计过程:业务核心为处理日志的loggerService EJB,通过loggerService EJB完成相关设计,设计消息Queue的目的是让日志中记录时间更加准确;
分模块说明各模块的设计
1 描述XML文件META-INF模块,如下图,该模块中包括两个XML描述文件:
application.xml应用全局描述文件,通过application.xml我们定义了home-test-all.ear中所有的模块,如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE application PUBLIC "-//Sun Microsystems, Inc.//DTD J2EE Application 1.3//EN" "http://java.sun.com/dtd/application_1_3.dtd">
<application>
<display-name>home test all</display-name>
<module>
<web>
<web-uri>home-test.war</web-uri>
<context-root>home</context-root>
</web>
</module>
<module>
<ejb>userServiceBean.jar</ejb>
</module>
<module>
<ejb>loggerServiceBean.jar</ejb>
</module>
<module>
<java>CommonUtil.jar</java>
</module>
<module>
<java>PersistUnit.jar</java>
</module>
</application>
如上定义home-test-all.ear中包括:home-test.war,userServiceBean.jar,loggerServiceBean.jar,CommonUtil.jar,PersistUnit.jar共五个模块;
注意:一个ear应用中可以包含多个war,这多个war是通过上面描述文件中<context-root>home</context-root>来定义的,context-root中定义的路径描述符与相应war应用中WEB-INF目录下jboss-web.xml中context-root定义的描述符对应
jboss-app.xml文档为该应用指定了类加载器,每个EAR应用的类加载器应该有一个唯一的名称。这里我们使用应用程序名作为类加载器的名称(其实我也不知道是神马作用,我的感觉是没有神马实质是作用,只是一个描述性的文件,这里如果定义了此文件,则在Jboss控制台可以看到相关描述),给出这里描述:
<jboss-app> <loader-repository> home-test-all:archive=home-test-all.ear </loader-repository> </jboss-app>
这里定义了 loader-repository描述信息问:home-test-all:archive=home-test-all.ear,会在Jboss JMX-console界面看到相应描述
2 Persistence Entity EJB
通过上面描述知道这里包括两类实体
User相关实体是在JPA dev: 几个问题总结 中开始描述的实例,他们关系图如下:
如上图所示:所有实体间对应关系都是单向的,User和Event,User和Friend,Event和Property,Wife和Pet,Pet和Property关系为一对多关系,User和UserCard,Friend和UserCard,Wife和UserCard,User和Wife之间的关系是一对一关系;
另一类实例类为日志记载类,包括一个实体类Audit,如下:
@Entity(name="Audit")
@Table(name="k_audit")
public class Audit implements Serializable {
private Long id;
private String content;
@Column
@Id
@GeneratedValue
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Column
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
实体persist描述文件persistence.xml, 我们知道Persistence unit 是在persistence.xml中定义的,实体类型之所以能被EntityManager控制是因为提供了Persistence unit,根据持久化规范的要求,该描述文件是必须提供的,如果不提供这一文件,则Persistence unit也将不存在,因此应用也不能够获得和使用EntityManager,下面是persistence.xml内容:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0"> <persistence-unit name="com.home.po" transaction-type="JTA"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>java:/OracleDS</jta-data-source> <properties> <property name="hibernate.hbm2ddl.auto" value="create-drop"/> <property name="hibernate.jdbc.fetch_size" value="18"/> <property name="hibernate.jdbc.batch_size" value="10"/> <!--<property name="hibernate.show_sql" value="true"/> <property name="hibernate.format_sql" value="true"/> --> </properties> </persistence-unit> </persistence>
配置文件中
persistence-unit指定Persist Pojo的路径;
provider说明我们用的JPA的实现是Hibernate;
jta-data-source说明我们关联的data-source为Oracle;
“hibernate.hbm2ddl.auto”值得容器启动时创建表,容器关闭时删除表;
"hibernate.show_sql"在容器Console口打印SQL语句;
"hibernate.format_sql"说明在容器Console显示的SQL语句是格式化的
说明:<jta-data-source>java:/OracleDS</jta-data-source> 说明在JBoss_Home\server\production\deploy目录下存在名字为oracle-ds.xml数据源描述文件定义的数据源名为OracleDS,该描述文件的模板在JBoss_Home\docs\examples\jca可以找到,将他做相应拷贝既可以运用,这里描述文件内容如下:
<?xml version="1.0" encoding="UTF-8"?> <datasources> <local-tx-datasource> <jndi-name>OracleDS</jndi-name> <connection-url>jdbc:oracle:thin:@192.168.1.105:1521:orcl</connection-url> <driver-class>oracle.jdbc.driver.OracleDriver</driver-class> <user-name>USERNAME</user-name> <password>PASSWORD</password> <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter</exception-sorter-class-name> <metadata> <type-mapping>Oracle10g</type-mapping> </metadata> </local-tx-datasource> </datasources>
3 loggerService EJB
该模块中包括一个无状态Session Bean,和相关Service接口,如下:
public interface LoggerService {
public void insertUser(User user);
public void insertUserList(List<User> users);
public List<User> getUserList();
public List<Audit> getAuditList();
}
public interface LoggerServiceLocal extends LoggerService {
}
@Stateless
@Remote(LoggerService.class)
@Local(LoggerServiceLocal.class)
public class LoggerServiceBean implements LoggerServiceLocal {
@PersistenceContext(unitName="com.home.po")
protected EntityManager em;
@EJB
protected UserServiceLocal userService;
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void insertUser(User user) {
TimerUtil timer = TimerUtil.getInstance();
timer.setTimer();
userService.insertUser(user);
timer.recordTimer("insertUser");
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void insertUserList(List<User> users) {
TimerUtil timer = TimerUtil.getInstance();
timer.setTimer();
userService.insertUserList(users);
timer.recordTimer("insertUserList, user number is " + users.size());
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public List<User> getUserList() {
TimerUtil timer = TimerUtil.getInstance();
timer.setTimer();
List<User> users = userService.getUserList();
timer.recordTimer("getUserList, user number is " + users.size());
return users;
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public List<Audit> getAuditList() {
Query query = em.createQuery("select a from Audit as a");
return query.getResultList();
}
}
如上使用标记来说明Bean属性,是EJB3规定:
@Stateless指定LoggerServiceBean 为无状态 SessionBean
@Remote指定LoggerServiceBean 是远程接口
@Local指定LoggerServiceBean 的本地接口
@PersistenceContext(unitName="com.home.po") 指定持久化的数据单元名字
@TransactionAttribute(TransactionAttributeType.REQUIRED)说明EJB容器在执行此方法时Transaction是必须的;
4 UserService EJB模块
UserService EJB同上是无状态持久类和其相关接口,如下
public interface UserService {
public void insertUser(User user);
public void insertUserList(List<User> users);
public List<User> getUserList();
public User getUserByID(Long id);
}
public interface UserServiceLocal extends UserService {
}
@Stateless
@Remote(UserService.class)
@Local(UserServiceLocal.class)
public class UserServiceBean implements UserServiceLocal {
@PersistenceContext(unitName="com.home.po")
protected EntityManager em;
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void insertUser(User user) {
em.persist(user);
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void insertUserList(List<User> users) {
for(User user : users) {
em.persist(user);
}
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public List<User> getUserList() {
Query query = em.createQuery("select u from User as u");
return query.getResultList();
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public User getUserByID(Long id) {
return em.find(User.class, id);
}
}
5 CommonUtil模块,该模块充当JMS Queue消息发送方,主要是往消息队列中发送日志消息,如下:
public class TimerUtil {
public static TimerUtil getInstance() {
return new TimerUtil();
}
private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'kk:mm:ss");
private Date start = new Date();
private boolean isSet = false;
public void setTimer() {
isSet = true;
start = new Date();
}
public void recordTimer(String key) {
long time = 0;
if(isSet) {
isSet = false;
time = new Date().getTime() - start.getTime();
}
record(key, time);
}
private void record(final String key, final long time) {
new Thread(new Runnable(){
public void run() {
Session session = null;
Connection conn = null;
try {
Context ctx = new InitialContext();
ConnectionFactory factory = (ConnectionFactory) ctx.lookup("ConnectionFactory");
conn = factory.createConnection();
Queue queue = (Queue) ctx.lookup("queue/HomeTestAuditLogQueue");
session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer sender = session.createProducer(queue);
Long t = time;
String text = dateFormat.format(new Date()) + " " + key + ", total time: " + time + " milliseconds";
TextMessage msg = session.createTextMessage(text);
sender.send(msg);
} catch (NamingException e) {
e.printStackTrace();
} catch (JMSException e) {
e.printStackTrace();
}finally {
try {
if(session != null) {
session.close();
}
if(conn != null) {
conn.close();
}
} catch (JMSException e) {
e.printStackTrace();
}
}
}}).start();
}
}
消息向JMS Queue 发布消息描述在上篇博客http://kylinsoong.iteye.com/blog/848713中可以找到,如何在JBoss中定义一个Queue,接下来将有描述
6 Audit Messaging EJB
此模块是一个Message Driven Bean,相当于一个JMS 消息订阅者,监听与一个Queue,通过上面我们知道TimerUtil是一个消息发送者,不管是消息发送者和消息订阅者都是基于某一Queue,如何定义一个Queue?这里我是通过JBoss_Home\server\production\deploy\jboss-messaging.sar目录下home-service.xml描述文件定义的,文件内容:
<?xml version="1.0" encoding="UTF-8"?> <server> <mbean code="org.jboss.jms.server.destination.QueueService" name="jboss.messaging.destination:service=Queue,name=HomeTestAuditLogQueue" xmbean-dd="xmdesc/Queue-xmbean.xml"> <depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends> <depends>jboss.messaging:service=PostOffice</depends> </mbean> </server>
如上Queue是名字为HomeTestAuditLogQueue,Jboss启动后在Jboss JNDI树上可以看到Queue HomeTestAuditLogQueue;
同样Jboss消息描述文件的模板可以在JBoss_Home\docs\examples\jms下可以找到,只需做少量修改,便可以使用,使用时只需将修改完的文件拷贝到JBoss_Home\server\production\deploy\jboss-messaging.sar既可以,JBoss启动时自动创建描述文件中定义的Queue;
此处Message Driven Bean的内容:
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "acknowledgeMode"
, propertyValue = "Auto-acknowledge"),
@ActivationConfigProperty(propertyName = "destination"
, propertyValue = "queue/HomeTestAuditLogQueue"),
@ActivationConfigProperty(propertyName = "destinationType"
, propertyValue = "javax.jms.Queue") })
public class AuditLoggerMsgBean implements MessageListener {
@PersistenceContext(unitName="com.home.po")
protected EntityManager em;
public void onMessage(Message msg) {
try {
if(msg instanceof TextMessage) {
System.out.println(((TextMessage) msg).getText());
Audit audit = new Audit();
audit.setContent(((TextMessage) msg).getText());
em.persist(audit);
} else {
Audit audit = new Audit();
audit.setContent("Error msg Type passed," + msg.getClass());
em.persist(audit);
}
} catch (JMSException e) {
Audit audit = new Audit();
audit.setContent(e.getMessage());
em.persist(audit);
}
}
}
7 Entry Web War模块
如下图描述了Web模块结构:
Web模块的名字为home-test.war,前台界面仅有一个index.jsp,WEB-INF文件下是Web模块的描述文件
WEB-INF内容如下:
jboss-web.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 2.3V2//EN" "http://www.jboss.org/j2ee/dtd/jboss-web_3_2.dtd"> <jboss-web> <context-root>home</context-root> </jboss-web>
此处定义是context-root与JBoss_Home\server\production\deploy\home-test-all.ear\META-INF下application.xml文件中Web模块定义的context-root相对应
web.xml为Web描述文件如下:
<web-app > <servlet> <servlet-name>ControllerServlet</servlet-name> <display-name>Controller Servlet</display-name> <servlet-class>com.home.servlet.ControllerServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>ControllerServlet</servlet-name> <url-pattern>/controller</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>/index.jsp</welcome-file> </welcome-file-list> </web-app>
如上Web模块中只有一个Servlet,名字为:com.home.servlet.ControllerServlet,默认欢迎页面为:index.jsp
ControllerServlet内容:
public class ControllerServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
handlerRequest(req, resp);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
handlerRequest(req, resp);
}
private void handlerRequest(HttpServletRequest req, HttpServletResponse resp) throws IOException {
Properties properties = new Properties();
LoggerService service = null;
try {
Context ctx = new InitialContext(properties);
service = (LoggerService) ctx.lookup("home-test-all/LoggerServiceBean/remote");
} catch (NamingException e) {
e.printStackTrace();
}
String action = req.getParameter("action");
if(action.compareTo("user") == 0) {
List<User> users = service.getUserList();
req.getSession().getServletContext().setAttribute("action", "user");
req.getSession().getServletContext().setAttribute("value", users);
} else if(action.compareTo("audit") == 0) {
List<Audit> audits = service.getAuditList();
req.getSession().getServletContext().setAttribute("action", "audit");
req.getSession().getServletContext().setAttribute("value", audits);
}
resp.sendRedirect("index.jsp");
}
}
index.jsp内容:
<%@ page language="java" import="java.util.*, com.home.po.*" pageEncoding="ISO-8859-1"%>
<%
String action = (String) request.getSession().getServletContext().getAttribute("action");
Object obj = request.getSession().getServletContext().getAttribute("value");
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Home-Test</title>
<link rel="SHORTCUT ICON" href="favicon.ico">
</head>
<body>
<h2>
<form method="post" action="controller">
<input type="hidden" name="action" value="user">
<input type="submit" name="submit" value="View All User">
</form>
</h2>
<h2>
<form method="post" action="controller">
<input type="hidden" name="action" value="audit">
<input type="submit" name="submit" value="View All Audit">
</form>
</h2>
<hr>
<%
if(action != null && action.equals("user")) {
List<User> users = (List<User>) obj;
for(User u : users) {
%>
<p><%=u.getId() + " " + u.getName() + " " + u.getWife().getName() + " " + u.getCreatedDate().getTime() %></p>
<%
}
}
if(action != null && action.equals("audit")) {
List<Audit> audits = (List<Audit>) obj;
for(Audit a : audits) {
%>
<p><%=a.getContent() %></p>
<%
}
}
%>
</body>
</html>
结果分析:
部署成功后在JMX-console控制页面http://localhost:8080/jmx-console/JMX Agent View可以看到我们home-test-all.ear应用的描述:
此处显示是在JBoss_Home\server\production\deploy\home-test-all.ear\META-INF下的jboss-app.xml中定义的
同样在JMX Agent View的jboss.jca模块可以看到Oracle数据源相关描述
此处显示是在JBoss_Home\server\production\deploy\下的oracle-ds.xml中定义的
查看JNDI View树:http://localhost:8080/jmx-console/HtmlAdaptor,在JMX MBean Operation Result list()中可以看到我们应用定义的War,Queue,EJB等
home-test-all.ear描述如下:
在Global JNDI Namespace可以看到Queue和EJB相关描述:
加粗红线指出我们定义的Queue
Session Bean树如下:
结果测试:
通过Command Line向数据库中插入1个User,并取出,插入100个User,然后取出所有User,再插入1000个User,后取出,完成后我们到前台看数据库操作日志:
点击后可以看到如下界面:
点击View All Audit Button可以看到如下信息:
2010-12-25T13:23:16 insertUser, total time: 250 milliseconds
2010-12-25T13:23:16 getUserList, user number is 1, total time: 781 milliseconds
2010-12-25T13:24:08 insertUserList, user number is 1000, total time: 20468 milliseconds
2010-12-25T13:24:24 getUserList, user number is 1101, total time: 2719 milliseconds
2010-12-25T13:23:36 insertUserList, user number is 100, total time: 2953 milliseconds
2010-12-25T13:23:38 getUserList, user number is 101, total time: 360 milliseconds
点击View All User,可以看到如下信息:
6491 Kylin Soong Bitch Soong Sat Dec 25 00:00:00 CST 2010
6514 Kylin Soong Bitch Soong Sat Dec 25 00:00:00 CST 2010
……
补充1:全部工程已经上传,运行下面build.xml可以将应用部署到Jboss上,build.xml内容:
<?xml version="1.0"?> <project name="com.home.ear" default="compile" basedir=".."> <property environment="env" /> <property name="app.dir" value="${basedir}\com.home.ear" /> <property name="src.dir" value="${app.dir}\src" /> <property name="build.dir" value="${app.dir}\build" /> <property name="deploy.resource" value="${app.dir}\resource" /> <property name="build.classes.dir" value="${build.dir}\classes" /> <property name="jboss.home" value="${env.JBOSS_HOME}" /> <property name="jboss.server.config" value="${jboss.home}\server\production\deploy" /> <path id="build.classpath"> <fileset dir="${app.dir}\jars"> <include name="*.jar" /> </fileset> </path> <target name="clean"> <delete dir="${build.dir}" /> <delete file="${deploy.resource}\CommonUtil.jar" /> <delete file="${deploy.resource}\userServiceBean.jar" /> <delete file="${deploy.resource}\PersistUnit.jar" /> <delete file="${deploy.resource}\loggerServiceBean.jar" /> <delete file="${deploy.resource}\homeTestWeb.jar" /> </target> <target name="prepare" depends="clean"> <mkdir dir="${build.dir}" /> <mkdir dir="${build.classes.dir}" /> </target> <target name="compile" depends="prepare" description="compile"> <javac srcdir="${src.dir}" destdir="${build.classes.dir}" debug="on" deprecation="on" optimize="off" includes="com/**"> <classpath refid="build.classpath" /> </javac> </target> <target name="ejbjar" depends="compile" description="generate all jar"> <jar jarfile="${deploy.resource}\userServiceBean.jar"> <fileset dir="${build.classes.dir}"> <include name="com/home/user/session/*.class" /> </fileset> </jar> <jar jarfile="${deploy.resource}\loggerServiceBean.jar"> <fileset dir="${build.classes.dir}"> <include name="com/home/logger/session/*.class" /> <include name="com/home/audit/*.class" /> </fileset> </jar> <jar jarfile="${deploy.resource}\homeTestWeb.jar"> <fileset dir="${build.classes.dir}"> <include name="com/home/servlet/*.class" /> </fileset> </jar> <jar jarfile="${deploy.resource}\PersistUnit.jar"> <fileset dir="${build.classes.dir}"> <include name="com/home/po/*.class" /> </fileset> <metainf dir="${deploy.resource}\META-INF"> <include name="persistence.xml" /> </metainf> </jar> <jar jarfile="${deploy.resource}\CommonUtil.jar"> <fileset dir="${build.classes.dir}"> <include name="com/home/util/*.class" /> </fileset> </jar> </target> <target name="deploy" depends="ejbjar"> <mkdir dir="${jboss.server.config}\home-test-all.ear" /> <mkdir dir="${jboss.server.config}\home-test-all.ear\META-INF" /> <mkdir dir="${jboss.server.config}\home-test-all.ear\home-test.war" /> <mkdir dir="${jboss.server.config}\home-test-all.ear\home-test.war\WEB-INF" /> <mkdir dir="${jboss.server.config}\home-test-all.ear\home-test.war\WEB-INF\lib" /> <copy file="${deploy.resource}\jboss-web.xml" todir="${jboss.server.config}\home-test-all.ear\home-test.war\WEB-INF" /> <copy file="${deploy.resource}\web.xml" todir="${jboss.server.config}\home-test-all.ear\home-test.war\WEB-INF" /> <copy file="${deploy.resource}\homeTestWeb.jar" todir="${jboss.server.config}\home-test-all.ear\home-test.war\WEB-INF\lib" /> <copy file="${deploy.resource}\web\index.jsp" todir="${jboss.server.config}\home-test-all.ear\home-test.war" /> <copy file="${deploy.resource}\application.xml" todir="${jboss.server.config}\home-test-all.ear\META-INF" /> <copy file="${deploy.resource}\jboss-app.xml" todir="${jboss.server.config}\home-test-all.ear\META-INF" /> <copy file="${deploy.resource}\PersistUnit.jar" todir="${jboss.server.config}\home-test-all.ear" /> <copy file="${deploy.resource}\userServiceBean.jar" todir="${jboss.server.config}\home-test-all.ear" /> <copy file="${deploy.resource}\CommonUtil.jar" todir="${jboss.server.config}\home-test-all.ear" /> <copy file="${deploy.resource}\loggerServiceBean.jar" todir="${jboss.server.config}\home-test-all.ear" /> </target> <target name="undeploy" > <delete dir="${jboss.server.config}\home-test-all.ear" /> </target> </project>
概括上述脚步Target作用:
path 说明Ant Build过程依赖jar的位置 clean 删除已经存在的旧的Build结果,包括目录和文件 prepare 创建存放编译结果的文件夹,依赖于clean,即创建之前删除已经存在的文件夹 compile 编译应用中所有的java类,将编译结果存放在prepare创建的文件夹中,依赖于prepare ejbjar 将上述编译的class文件和相关资源文件打包,将打包结果存放在项目的resource目录,依赖于compile deploy
将相关jar包和描述文件部署到JBoss_Home\server\production\deploy中,主要包括两类操作:
在JBoss_Home\server\production\deploy下创建所需目录;
将ejbjar中创建的jar包和相关描述文件拷贝到JBoss中
undeploy 删除已经部署在JBoss中的应用补充2:如何使用Eclipse远程调试部署在JBoss上的远程代码,可分两步,如下:
1 修改JBoss 启动脚本run.bat,添加如下一行脚本,实际就是设定了一个JAVA_OPTS变量,该变量包括说明Debug方式,运程Debug网络几乎协议为TCP,TCP远程连接端口8787,启动server选择Yes,挂起Server选择No
set JAVA_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n %JAVA_OPTS%
上面描述的脚步已经包括在启动脚本run.bat中,只是被注释了而已,默认挂起Server选项suspend=y,实际操作中我们只需将脚本注释去掉,将默认挂起Server选项设定为suspend=n,设定完成启动JBoss,启动过程会看到如下描述信息:
2 Eclipse Debug 设定(以调试上述应用中AuditMessageBean为例说明):
在Eclipse导航栏选择run→Debug Configuration→Remote Java Application→New,给远程调试命名,修改相关端口如下:
设定完成给AuditLoggerMsgBean中onMessage方法设定断点后运行Debug,然后用Command line Client向数据库中发送一条信息,我们会看到Eclipse执行停止到断点处,如下:
--------------------------------------------------------------------------------------------------------------
到此结束,问题还有很多,此博客太长,现在结束