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...

面试题 相关文章推荐
weblogic面试题
Mar 07 面试题
你所知道的集合类都有哪些?主要方法?
Dec 31 面试题
Ibatis如何使用动态表名
Jul 12 面试题
字符串str除首尾字符外的其他字符按升序排列
Mar 08 面试题
写出一个方法实现冒泡排序
Jul 08 面试题
求∏的近似值,直到最后一项的绝对值小于指定的数
Feb 12 面试题
一道写SQL的面试题和答案
Nov 19 面试题
.NET remoting中对象激活的两种方式
Jun 08 面试题
什么是ARP(Address Resolution Protocol)地址解析协议
Oct 31 面试题
linux面试题参考答案(6)
Jun 23 面试题
如果重写了对象的equals()方法,需要考虑什么
Nov 02 面试题
介绍一下SOA和SOA的基本特征
Feb 24 面试题
比较一下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
phpstorm编辑器乱码问题解决
2014/12/01 PHP
PHP伪造来源HTTP_REFERER的方法实例详解
2015/07/06 PHP
如何把php5.3版本升级到php5.4或者php5.5
2015/07/31 PHP
php中目录操作opendir()、readdir()及scandir()用法示例
2019/06/08 PHP
PHP中define() 与 const定义常量的区别详解
2019/06/25 PHP
PHP高并发和大流量解决方案整理
2021/03/09 PHP
js实现的网页颜色代码表全集
2007/07/17 Javascript
clientX,pageX,offsetX,x,layerX,screenX,offsetLeft区别分析
2010/03/12 Javascript
JS与C#编码解码
2013/12/03 Javascript
实例分析js和C#中使用正则表达式匹配a标签
2014/11/26 Javascript
NodeJS Web应用监听sock文件实例
2015/02/18 NodeJs
js操作table元素实现表格行列新增、删除技巧总结
2015/11/18 Javascript
Spring mvc 接收json对象
2015/12/10 Javascript
如何解决手机浏览器页面点击不跳转浏览器双击放大网页
2016/07/01 Javascript
JS实现n秒后自动跳转的两种方法
2020/11/30 Javascript
第一次接触神奇的Bootstrap基础排版
2016/07/26 Javascript
基于JavaScript实现树形下拉框
2016/08/10 Javascript
bootstrap-Treeview实现级联勾选
2017/11/23 Javascript
vue2.0+ 从插件开发到npm发布的示例代码
2018/04/28 Javascript
jsonp跨域及实现百度首页联想功能的方法
2018/08/30 Javascript
vue+egg+jwt实现登录验证的示例代码
2019/05/18 Javascript
vue 使用axios 数据请求第三方插件的使用教程详解
2019/07/05 Javascript
Vue 通过公共字段,拼接两个对象数组的实例
2019/11/07 Javascript
python连接远程ftp服务器并列出目录下文件的方法
2015/04/01 Python
使用Python的Zato发送AMQP消息的教程
2015/04/16 Python
使用HTML5捕捉音频与视频信息概述及实例
2018/08/22 HTML / CSS
理肤泉美国官网:La Roche-Posay
2018/01/17 全球购物
Delphi笔试题
2016/11/14 面试题
食堂个人先进事迹
2014/01/22 职场文书
幼儿园教师岗位职责
2014/03/17 职场文书
找工作求职信
2014/07/07 职场文书
2014年反洗钱工作总结
2014/11/22 职场文书
2015年乡镇信访工作总结
2015/04/07 职场文书
MySQL修改默认引擎和字符集详情
2021/09/25 MySQL
python在package下继续嵌套一个package
2022/04/14 Python
Golang jwt身份认证
2022/04/20 Golang