EJB2和EJB3在架构上的不同点


Posted in 面试题 onSeptember 29, 2014
EJB编程模型的简化

首先,EJB3简化的一个主要表现是:在EJB3中,一个EJB不再象EJB2中需要两个接口一个Bean实现类,虽然我们以前使用JBuilder这样可视化开发工具自动生成了EJB2的这三个类,好像不觉得复杂,但是当EJB个数增加时,就显得累赘了。

简化后的EJB3的sessionBean依靠annotations元注释来定义SessionBean的类型,也就是说,EJB2中的SessionBean类型区分在EJB3继续继承,只不过书写代码的方式不同而已,例如下代码使用@Stateless表示一个无状态Bean。

package example;@Statelesspublic class TestSessionBean implements TestSessionLocal{public void xxxx(){System.out.println(“hello”);}}

上述Session Bean中没有了EJB2中ejbCreate等多余方法,这样TestSessionBean很象一个普通JavaBeans了。是不是简单?先别急,我们需要接着看看这个TestSessionBean是如何调用?

在EJB2中,一个EJB对象的调用需要经过两个步骤:JNDI寻找和工厂创建,如下例:

Context ctx = new InitialContext();TestSessionLocalHome home = (TestSessionLocalHome)ctx.lookup(“java:comp/env/ejb/TestSession”);TestSessionLocal bean = home.create();bean.xxxx();//真正目的 对象使用

JPA替代实体Bean

如果说EJB3与EJB2变化最大的部分,就是持久层使用Java Persistence API 替代了EJB2的实体Bean,这样,我们通过Evans DDD建模得到的Domain Model类可以直接持久化保存到数据库,不像EJB2中还需要在Model类和实体Bean中进行一次转换。

EJB3引入EntityManager进行需要持久实体的查询及其新增修改;EntityManager非常类似JDBCTemp/HibernateTemplate等持久化模板。

JPA和JDO以及Hibernate等O/R mapping框架都是非常相似的。

虽然在JPA中,我们都可以使用Annotation来替代配置,实现很多过去需要专门配置文件才能实现功能,不再一定需要 每个服务器不同的cmp映射文件,增强了移植性,但是EJB3还是需要 一个叫persistence.xml配置文件,在这个配置中进行数据库JNDI配置;当然,还有一些和具体服务器有关的配置属性,如果使用JBoss,JBoss的JPA底层使用Hibernate实现,因此在persistence.xml要进行有关Hibernate属性配置:

java:/TestDS

拦截器概念

EJB3.0引入了类似AOP中的拦截器概念(注意,AOP不只等于拦截器,所以不能认为EJB3就是完全AOP了),JBoss使用JBossAOP来实现拦截器功能,自己定义的拦截器方法可以拦截任何一个业务方法或生命周期事件回调;拦截方法可以在bean中定义或专门的拦截器类。

@Stateless@Interceptors( { NullChecker.class, ArgumentsChecker.class })public class StatelessSessionBean implements StatelessSession {// This business method is called after// the above two interceptor’s @AroundInvoke// methods are invoked. Hence it is guaranteed// that the argument to this method is not null// and it starts with a letterpublic String initUpperCase(String val) {String first = val.substring(0, 1);return first.toUpperCase() + val.substring(1);}}

NullChecker和ArgumentsChecker是StatelessSessionBean两个拦截器,在拦截器NullChecker中,必须指定的拦截方法为@AroundInvoke。

public class NullChecker {@AroundInvokepublic Object checkIfNull(InvocationContext ctx)throws Exception {Method method = ctx.getMethod();if (method.getName().equals(“initUpperCase”)) {String param = (String) (ctx.getParameters()[0]);}………}// Proceed to the next interceptorreturn ctx.proceed();}}

总结

总之,从上面EJB2和EJB3的总结上看,EJB3.0在EJB2基础上,引入了更多概念,最大变化就是Annotation替代了配置文件,对于一些配置文件厌恶者来说,是一个好事;但是在实战中,在一些依赖注射不能照顾到地方,我们还必须和更加复杂的JNDI名称打交道,这恐怕是EJB3的一个不是很完美的地方。

关于EJB3中可测试性的优点被很多人津津乐道,将EJB脱离容器测试,虽然可以进行微观的单元测试,但是脱离容器就是脱离特定完整的业务场景,所以,基于容器的(也就是基于完整的业务场景)单点跟踪调试才是最重要的,这些必须依赖开发工具的发展,目前已经在Eclipse3.2以后版本+WPT(或JBossIDE/Lomboz)中实现,这个功能适合大部分J2EE/JavaEE程序。

所以,个人对脱离容器的测试要求并不以为然,而这个曾经是Martin Fowler定义POJO的主要内容,因为在过去容器概念刚刚出现时,很多人都有容器恐惧症,以为容器都是不透明的,我们的业务对象放入进去,就失去了控制,这些都是落后设计观念导致,其实,Java语言本身提供的可跟踪性和介入性是非常强大,目前性能跟踪工具Profiler可以在容器运行时,跟踪到容器中某个具体类占据CPU多少,占用多少内存资源,那么一个单点调试岂是一个个所谓容器可以阻挡的?容器是Java语言的特点,ClassLoader决定了Java就是一个容器性的语言,关键这个容器是必须透明的。

其实上述代码最后一句才是我们真正目的,但是为了这个目的,必须经过前面冗长的代码创建,而在EJB3中,为创建型模式的Ioc模式(或称依赖注射)取代了home.create这样简单工厂创建模式,以一种更加松耦合和简洁的方式解决了对象创建问题,可以让我们精力更集中在对象的使用上了。

下面是annotations+Ioc/DI的EJB3调用代码:

@EJB //注意这里后面是空白private TestSessionLocal testbean; //使用接口声明public void invoke(){testbean.xxxx(); //直接使用}

上述EJB3调用代码中,@EJB后面是空白,这其实使用了TestSessionLocal的缺省JNDI名称,一直到这里,我们一直满足于EJB3的简化,但是如果研究@EJB语法后,会发现其完整写法如下:

@EJB(name = “ejb/shopping-cart”,//被调用者Cart实现类的ejb-reference名称beanName = “cart1”, //被调用者的名称 beanNamebeanInterface = ShoppingCart.class, //接口名称description = “The shopping cart for this application”)private Cart myCart;

上述完整@EJB写法适用于同一个接口有多个实现子类时,其中关键是 beanName的定义:beanName是被调用EJB的类名 (不带包名,称为unqualified name ),或者, 如果被调用EJB有 XML descriptor定义, 它就是配置项ejb-name值(如果你使用过EJB2,就容易理解这个ejb-name了)。

@EJB还有一个属性mappedName,这是被调用者的JNDI名称,一般不使用,因为这个JNDI名称和具体服务器有关,如果是JBoss4,那么它的缺省形式是:”EAR-FILE-BASE-NAME/BEAN——CLASS-NAME/local” (or remote)。 也就是:被调用者EJB所在EAR包的名称/Bean实现子类(不带包名)/local,如果是remote调用,就是remote. 如果这个EJB被打包在jar包中,那么JNDI名称就是EJB-CLASS-NAME/local and EJB-CLASS-NAME/remote,当然,作为替换@RemoteBinding 和 @LocalBinding 也可定义JNDI名称。

也就是说:JBoss的EJB3中,如果你不使用XML配置,直接使用annotations,那么JNDI缺省名称没有一个统一规定名称,有的可以直接是类名;在JBoss中还和EJB打包的形式有关,是动态变化的。如果你以为在EJB3中不会接触到这个变化的JNDI缺省名称,那你就错了。

JBoss 4 在Servlet中不支持类似EJB调用EJB那样的依赖注射 binding-by-injection,因为Web容器和EJB容器是两个不同容器,当然借助另外JBoss Seam则是另外一回事,因此,在Web层调用EJB,就必须通过JNDI绑定一个session bean,这时,你就必须使用到那个变化不定的缺省JNDI名称了。

JNDI Naming Context

无论J2EE还是Java EE中,JNDI是一个好像不起眼,但是极其重要的概念,不理解JNDI可以说,对J2EE或JavaEE只了解一半。

JNDI本来是EJB2中比较复杂的一个概念,不同容器有自己的JNDI名称,由此EJB2引入了第三者EJB-Reference,虽然解决了代码中耦合JNDI名称问题,但是又带来了更加烦琐的配置,这种现象当然被JavaEE5.0继续继承了下来,问题远非这么简单。

J在Java EE5.0中(包括EJB3和Web环境),当我们需要访问一个JNDI环境下资源时,有两种方式:除了传统EJB2中的JNDI调用方式;还有一种就是:使用依赖注射Ioc模式,这个依赖注射的表达方式是使用annotations.

因此,在EJB3中,必须好好搞清楚annotations、依赖注射和JNDI之间的关系,如果这个问题不弄明白,EJB3就绝非EJB2那么容易搞定,当然,搞定了的结果很简单,让人感觉简化轻量了,真不知道EJB3这种简化是不是有点象“掩耳盗铃”。

可以总结一句:凡是EJB2中使用配置文件定义的;EJB3一般都可以使用 annotations定义(当然EJB3也支持配置文件定义);凡是EJB2通过JNDI寻找的资源(调用容器中其他EJB、调用环境变量等Resource资源等),都是可以依靠annotations+依赖注射机制完成。

Tags in this post...

面试题 相关文章推荐
一份全面的PHP面试问题考卷
Jul 15 面试题
你常见到的runtime exception
Sep 05 面试题
几道数据库的概念性面试题
May 30 面试题
什么是唯一索引
Jul 05 面试题
关于.NET, HTML的五个问题
Aug 29 面试题
2019年分享net面试的经历和题目
Aug 07 面试题
C#笔试题
Jul 14 面试题
GWT (Google Web Toolkit)有哪些主要的原件组成?
Jun 08 面试题
如何清空Session
Feb 23 面试题
Java如何支持I18N?
Oct 31 面试题
我们没有写servlet的构造方法,那么容器是怎么创建servlet的实例呢
Apr 24 面试题
如何定义一个可复用的服务
Sep 30 面试题
比较一下entity bean和session bean
Dec 27 #面试题
介绍一下RMI的基本概念
Dec 17 #面试题
JSP和EJB可以共享HttpSession么?EJB里面可以改变session里面的内容
Jun 05 #面试题
敏捷开发的主要原则都有哪些
Apr 26 #面试题
什么是规则表达式
May 03 #面试题
软件设计的目标是什么
Dec 04 #面试题
设计模式的基本要素是什么
Apr 21 #面试题
You might like
一个程序下载的管理程序(一)
2006/10/09 PHP
yii框架通过控制台命令创建定时任务示例
2014/04/30 PHP
Yii2中多表关联查询hasOne hasMany的方法
2017/02/15 PHP
关于PHP通用返回值设置方法
2017/03/31 PHP
js验证表单大全
2006/11/25 Javascript
javascript 简单抽屉效果的实现代码
2010/03/09 Javascript
js 处理URL实用技巧
2010/11/23 Javascript
利用webqq协议使用python登录qq发消息源码参考
2013/04/08 Javascript
JS和jquery获取各种屏幕的宽度和高度的代码
2013/08/02 Javascript
详解JavaScript数组和字符串中去除重复值的方法
2016/03/07 Javascript
javascript html5移动端轻松实现文件上传
2020/03/27 Javascript
js中的面向对象入门
2017/03/06 Javascript
webstorm添加vue.js支持的方法教程
2017/07/05 Javascript
详解如何将 Vue-cli 改造成支持多页面的 history 模式
2017/11/20 Javascript
利用Javascript获取选择文本所在的句子详解
2017/12/03 Javascript
微信小程序使用wxParse解析html的方法示例
2019/01/17 Javascript
解决IOS端微信H5页面软键盘弹起后页面下方留白的问题
2019/06/05 Javascript
Vue.js 中的实用工具方法【推荐】
2019/07/04 Javascript
python多进程和多线程究竟谁更快(详解)
2017/05/29 Python
机器学习经典算法-logistic回归代码详解
2017/12/22 Python
Python实现在某个数组中查找一个值的算法示例
2018/06/27 Python
python 使用turtule绘制递归图形(螺旋、二叉树、谢尔宾斯基三角形)
2019/05/30 Python
使用opencv将视频帧转成图片输出
2019/12/10 Python
Python 实现黑客帝国中的字符雨的示例代码
2020/02/20 Python
python 三种方法实现对Excel表格的读写
2020/11/19 Python
Python列表元素删除和remove()方法详解
2021/01/04 Python
前端面试必备之CSS3的新特性
2017/09/05 HTML / CSS
HTML5自定义属性前缀data-及dataset的使用方法(html5 新特性)
2017/08/24 HTML / CSS
C#面试题
2016/05/06 面试题
学生自我鉴定
2013/12/18 职场文书
经典毕业生求职信
2014/07/12 职场文书
电气工程师岗位职责
2015/02/12 职场文书
放假通知格式
2015/04/14 职场文书
幼儿园园长六一致辞
2015/07/31 职场文书
大学生安全教育主题班会
2015/08/12 职场文书
python使用tkinter实现透明窗体上绘制随机出现的小球(实例代码)
2021/05/17 Python