为什么要使用EJB
多层结构是J2EE的优势所在
开始进行J2EE学习,感触最深的莫过于分层了,ssh在分层,ejb还是在分层。使用J2EE的主要原因就是多层结构,传统的两层C/S结构难于维护,稳定性极差,界面代码和数据库代码混淆在一起,牵一动百,多层结构使得界面和数据库完全分离,并且诞生了中间件这样的技术,如下图
Web+EJB能组成多层结构
一个包含EJB的J2EE系统是这样的清晰地表达层次的:
Web完全只是一个MVC模式的实现,关键业务核心是在EJB的服务层实现,这样做的优点是,Web只负责界面相关部分,因为,如果是一个智能客户端,如Swing或J2ME,在不需要修改任何业务核心的情况下能够方便地更换。同样,提供WebServices功能,也只是在 Web层修改,不会涉及EJB方面的修改,同样保证了系统的稳定性,保证了系统升级和未来的扩展性。
如果不使用EJB,在EJB服务层实现的业务核心将由普通JavaBeans实现,使用何种架构或设计能够保证负责MVC的JavaBeans和负责业务核心的JavaBeans清晰地分开,又如何保证在新的程序员不会破坏和打乱你精心布局的JavaBeans架构?
EJB 的 性能优化
假定一个JavaBeans为A,那么一般使用这个JavaBeans命令如下:
A a = new A();
但是,在高访问量的环境中,newA()其实是很费时消耗系统性能的,因此,能不能在软件系统启动时候就预先建立一些对象,这样,系统运行时,从这些已经生成的对象池中借用一个,这样,就无需在使用时进行New,节约了开销,提高了性能,因此,真正成熟性能解决方案都是需要对象池等支持。
在一个纯Web结构的系统(也就是只能运行在Tomat环境中),例如Struts +Hibernate等这样的系统,除非自己动手做,一般是没有对象池技术支持的,因此他们的性能只能算是Demo演示版本的性能,根本无法承受大容量并发访问,也无法称为一个成熟的系统,所以,我们研究成熟的开源Web系统,如Jive、OFBize,LifeRay等,他们都在Web层拥有自己的对象池和缓存池。
对象池和缓存机制是J2EE必须的吗?当然,是所有成熟系统必须的,Windows系统如果去掉缓存将会变得怎样?
但是,EJB容器(如JBoss)已经提供了对象池和缓存机制,所以,没有事务机制的无状态SessionBean的性能肯定要强于普通JavaBeans。EJB容器不但在单机中提供了对象池和缓存,而且可以跨服务器实现动态负载平衡,这些都无需开发者自己开发任何软件代码,结构如下:
合理对待缓存
在享受着缓存带来的好处的同时,也不要忽视缓存带来的负面效应。
由于每个CMP在内存中都有一个缓存,在实际应用中,如果使用CMP批量读数据库数据,几万条查询完毕,内存中充满了几万条CMP缓存,如果这时你的EJB容器设置不当(如使用JBoss缺省配置),那么JVM的垃圾回收机制就会频繁启动,导致你的系统变慢甚至死机,这也是一些人抨击CMP慢的原因所在,其实他们使用方法不当,或者没有正确配置EJB容器CMP缓存。
对于这种情况,根据J2EE核心模式,推荐使用DAO+JDBC方式。
分布式应用且分布式对象之间支持事务
EJB设计目标与核心应用是部署分布式应用程序。分布式对象之间互相协作,完成特定的业务功能。
比如下面的代码就体现了跨越两个数据库之间的事务
persistence.xml
<!-- transaction-type 也跨越取值为RESOURCE_LOCAL --> <!-- 如果在一个EJB JAR包内定义两个以上的Persistence-unit, 则在这个EJB JAR 包内的所有实体类将要同时映射 到这个Persistence-unit所代表的数据库中 通过 class 和 exclude-unlisted-classes 属性配合使用,只映射指定类 --> <persistence-unit name="test1" transaction-type="JTA"> <jta-data-source>java:/MySqlDS1</jta-data-source> <class>com.jinbo.jpa.Person</class> <exclude-unlisted-classes>true</exclude-unlisted-classes> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/> <property name="hibernate.hbm2ddl.auto" value="update"/> </properties> </persistence-unit> <persistence-unit name="test2" transaction-type="JTA"> <jta-data-source>java:/MySqlDS2</jta-data-source> <class>com.jinbo.jpa.Student</class> <exclude-unlisted-classes>true</exclude-unlisted-classes> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/> <property name="hibernate.hbm2ddl.auto" value="update"/> </properties> </persistence-unit> </persistence>
PersonManagerBean.java
/** * 注明是Stateful * @author:tch */ @Stateful(name="personManager") @Remote public class PersonManagerBean implements PersonManager { /** * 定义PersistenceContext 类型 * 如果只定义了一个 Persistence Unit,则不需指定unitName */ @PersistenceContext(unitName="test1") private EntityManager em1; @PersistenceContext(unitName="test2") private EntityManager em2; public void addPerson() { Person p = new Person(); p.setName("李四"); em1.persist(p); Student s = new Student(); s.setName("小三"); em2.persist(s); //如果抛出异常,将会导致整个事务回滚, 这就是跨越数据库的管理 trow new RunTimeException("随便的一个异常"); } }
EBJ当然还有其他的好处,比如EJB组件能提供真正的可重用框架等,会随着不断深入学习讲给大家听的。