解释题目:为什么叫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内容如下:
<?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相关描述:
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执行停止到断点处,如下:
--------------------------------------------------------------------------------------------------------------
到此结束,问题还有很多,此博客太长,现在结束