首页 > 代码库 > JBOSS EAP 6 系列四 EJB实现——调用(贯穿始终的模块)

JBOSS EAP 6 系列四 EJB实现——调用(贯穿始终的模块)

    本文主要介绍在JBOSS EAP 6.2(或者JBOSS AS7)中模块是如何贯穿EJB实现的始终。延续上一博文《认识模块的使用》的话题继续聊JBOSS做为模块申明式容器的这一特性在EJB实现中的完全贯彻。


 Session bean

        JBOSS EAP(AS7)中默认的EJB是3.1版本遵循JSR318规范。EJB从3.0开始已经全面引入Annotation的概念,3.0以前的EJB需要在XML文件里面对Bean所做的配置都能通过标签的方式在代码中实现。同时,之前为了工厂模式而做的双接口Home和Remote已经被一个业务接口所取代。由于Entity Bean的概念已经从EJB中拿出放到了JPA规范中,所以这里只介绍Session Bean最基本的Annotation方式的实现,为后文提供知识基础。

      Session Bean由两部分组成:一个业务接口和一个具体实现业务的JAVA类。

       业务接口是一个普通的Java接口Interface。
可以被声明为@Local或者@Remote,区别就是标明这个EJB的可见度。
@Local标明这是一个只在同一个容器范围内的应用可见的Session bean
@Remote只要能与这台主机通讯的地方都可以调用这个Session bean。

<span style="font-size:18px;">public interface AssessContentBean extends BaseBean<AssessContent> {
	public List<AssessContent> queryContentByTemplateId(String templateId);
	
	public boolean deleteAll(Object[] ids);
}</span>


       实现类
是一个普通的JAVA类

在类名的上方使用@Stateless或者@Stateful来指明这个Session Bean是否有状态。


@Stateless或者@Stateful标签中可以带上name属性来指明这个无状态Bean的JNDI名称,如果不指明的话实现类的名称就是JNDI名称。

        需要注意的一点变化是:与EJB3.0不同的是EJB3.1的JNDI有很大变化,原本在EJB3.0的时候@Stateless(name=”StudentAssessResultBeanImpl”),在客户端可以使用initContext.lookup(“StudentAssessResultBeanImpl”)查到这个bean。


但是EJB3.1的JNDI规范是

java:global[/<app-name>]/<module-name>/<bean-name>[!<fully-quali?fied-interface-name>]

其中WAR包名称app-name,JAR包名称module-name,自定义Bean名称bean-name,接口的全地址名称fully-quali?fied-interface-name。


所以如上申明的@Stateless(name=””)在新的EJB3.1 JNDI中仅只是<bean-name>部分,想要调用这个EJB还需要组合出全部的名称来,具体的JNDI名称在后面的博文中做介绍。


直接上一个最简单的无状态Bean的实例:

<span style="font-size:18px;">@Stateless(name="StudentAssessResultBeanImpl")
@Remote(StudentAssessResultBean.class)
@TransactionManagement(TransactionManagementType.CONTAINER)
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class StudentAssessResultBeanImpl extends BaseBeanImpl<StudentAssessResult> implements StudentAssessResultBean {
	
	@EJB(beanName = "StudentAssessResultEao")
	private StudentAssessResultEao studentAssessResultEao;

	@Override
	public BaseEao getBaseEao() {
		// TODO Auto-generated method stub23
		return this.studentAssessResultEao;
	}


}</span>


这就是一个最最简单的EJB的实现,对于之前的JBOSS AS到此就可以运行了,但是JBOSS EAP 6.2(或者JBOSS AS7)还需要对EJB做配置,具体配制方法在下一个小节中做介绍。


【EJB学习内容小扩展】

下面列举一些常用的标签,学习完它们大部分的应用都够了。

@Stateless
@Remote
@Local
@LocalBean
@EJB
@Resource
@Inject
@Stateful
@Init
@PostConstruct
@PreDestroy
@PrePassivate
@PostActivate
@Remove

至于EJB复杂实现技术就不做介绍了,要深入了解的可以下载EJB 3.1规范JSR318。

以上介绍的都是服务端EJB的代码,Client端在下一篇博文《让人又爱又恨的EJB3.1 JNDI》介绍JNDI的时候会有更深入的介绍。

2. 贯穿始终的模块

回到模块的话题,模块的具体配置方法请参看《Oracle数据源的配置—认识模块的使用》中第2部分介绍。本节使用一个生产中的实例来说明模块在EJB实现的整个过程中是如何贯穿始终的。


回顾一下本系列第一篇文章《新特性》中所介绍的"模块申明式容器"这一特性:
JBOSS EAP不再有lib的概念,一切都是module。无论是系统调用的lib,用户编制的lib,或者应用程序引用到的第三方lib都以模块的方式构建起来,并在使用的地方申明具体使用了哪个模块。


<span style="font-size:18px;">@Stateless(name="StudentAssessResultBeanImpl")
@Remote(StudentAssessResultBean.class)
@TransactionManagement(TransactionManagementType.CONTAINER)
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class StudentAssessResultBeanImpl extends BaseBeanImpl<StudentAssessResult> implements StudentAssessResultBean {
	
	@EJB(beanName = "StudentAssessResultEao")
	private StudentAssessResultEao studentAssessResultEao;

	@Override
	public BaseEao getBaseEao() {
		// TODO Auto-generated method stub23
		return this.studentAssessResultEao;
	}


}</span>


有了上一节的铺垫,以上的这段删节的代码中基本显现了整个组件的结构,这是产品中的一个记录日志的组件,包括3个部分:
  • LogManager是EJB的具体实现,以上这段代码就是从LogManager中截取出来的。
  • logManagerCommon是EJB存放接口、放置与日志调用和存储有关的公共方法和变量的地方。LogManger需要依赖这个Project
  • commonClass用来放置项目全局范围内的各种资源。LogManger和LogManangerCommon需要依赖这个Project,同时这个Project也要依赖一些第三方包。


接下来我们来介绍这些部分在JBOSS EAP 6.2中的配置方式:
logManagerCommon和commonClass是做为用户创建的lib使用的,都需要被配置为JBOSS的module。


commonClass被打成jar包,放置在jboss-eap-6.1\modules\com\xx\ngoss\xxx\commonClass\main中,并配置module.xml文件如下,

<span style="font-size:18px;"><span style="font-size:18px;"><?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="com.xx.ngoss.xxx.commonClass">
  <dependencies>
    <module name="javax.api"/>
    <module name="javax.transaction.api"/>
    <module name="org.jboss.remote-naming"/>
    <module name="org.jython"/>
  </dependencies>
  <resources>
    <resource-root path="CommonClass.jar"/>
  </resources>
</module></span></span>

其中<module>标签中的name属性将这个模块命名为com.xx.ngoss.xxx.commonClass,同时在<dependencies>标签中指明了commonClass这个模块所依赖的其他模块:
  • commonClass依赖了JBOSS容器中的javax.api模块,这是一组与命名服务相关的javax包,在系统模块jboss-eap-6.1\modules\system\layers\base\javax\api\main中被配置为javax.api模块。
  • commonClass依赖了JBOSS容器中的javax.transaction.api模块,对应的是jboss-transaction-api_1.1_spec-1.0.1.Final-redhat-2.jar位于jboss-eap-6.1\modules\system\layers\base\javax\transaction\api\main目录中的一个jar包,被容器默认的配置为javax.transaction.api模块。
  • commonClass依赖了JBOSS容器中的org.jboss.remote-naming模块,对应的是jboss-remote-naming-1.0.6.Final-redhat-2.jar位于\jboss-eap-6.1\modules\system\layers\base\org\jboss\remote-naming\main目录中的一个jar包,被容器默认的配置为org.jboss.remote-naming模块。
  • commonClass还依赖了一个第三方包jython.jar,需要引入并配置成为一个新的JBOSS模块。我们把它放置在jboss-eap-6.1\modules\org\jython\main下,对应的module.xml中配置模块名称为org.jython。


<span style="font-size:18px;"><span style="font-size:18px;"><?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="org.jython">
    <dependencies>
        <module name="javax.api"/>
    </dependencies>
		<resources>
			<resource-root path="jython.jar"/>
		</resources>
</module></span></span>

       LogManger是实现EJB业务的地方,最终部署的时候会被放置到jboss-eap-6.1\standalone\deployments中部署。与之前的JBOSS AS不同之处在于:JBOSS EAP 6.1(AS7)中一个EJB项目对JBOSS模块的依赖需要指明在MANIFAST.MF文件中。LogManager/src/META-INF/MANIFEST.MF文件如下配置:


Manifest-Version: 1.0
Dependencies: com.xx.ngoss.xxx.commonClass, com.xx.ngoss.xxx.logManagerCommon, org.jboss.log4j.logmanager
Class-Path: 


这样就指明了EJB Project对JBOSS EAP 6.1中配置好的模块com.xx.ngoss.xxx.commonClass,com.xx.ngoss.xxx.logManagerCommon和org.jboss.log4j.logmanager的依赖。才完成整个EJB在JBOSS中的配置工作。剥离业务实现,这个日志组件的配置包括以下三步:

  • 将第三方包配置为模块
  • 将自己构建的包配置为模块,设置好模块所依赖的系统模块或者第三方包的模块
  • 在EJB Project的MANIFEST.MF中指明项目对JBOSS模块的依赖

系统自带包,第三方包,自定义包全都变为模块,模块与组建之间需要指明依赖关系,同时EJB项目也需要指明依赖关系到JBOSS EAP中的组件上。JBOSS EAP 6.1中组件的概念可谓是深入骨髓。

总结 

 

       本文首先介绍了最简单的EJB 3.1的实现,随后引入一个实例类说明JBOSS模块是如何配置到EJB项目、用户制作的lib、第三方的lib、系统lib之间来清楚的指明依赖关系的。这种设计为JBOSS容器优化带来了可行性。也在JBOSS EAP 6.1的启动与重启速度中得到了充分的证明。


       但从开发人员的角度出发,虽然开发环境中JBOSS的起降性能有很大提升,但是这种所有lib都需要配置为module的方式没有原来直接仍到lib中的方式容易实现,由于module可能被配置在$JBOSS_EAP$/modules目录下的任何一级目录下,有的或许系统里面已经有了,有的需要引入,引入到什么位置,都由开发人员自行决定。这样的自由度一方面给开发人员带来了额外的工作量,另一方面如果多个开发人员一起开发,不同的模块引入相同的包到了不同级别的目录下,从而引发冲突。


总结

       综上所述,模块申明式容器这一新特性,从性能的角度来看值得欣赏,但对于开发人员来说是利弊参半,我们慢慢的深入体会吧。


JBOSS EAP 6 系列四 EJB实现——调用(贯穿始终的模块)