要调用一个本地或者远程无状态session bean上的方法,客户端代码必须进行JNDI查找,以获取(本地或远程的)EJB Home对象,然后调用该对象的"create"方法,才能得到实际的(本地或远程的)EJB对象。然后才能调用一个或者多个EJB组件的方法。
为了避免重复的底层代码,很多EJB应用使用了服务定位器(Service Locator)和业务委托(Bussiness Delegate)模式,这样比在客户端代码中到处都进行JNDI查找要好些,不过它们的常见实现都有严重的缺陷。例如:
-
通常如果代码通过服务定位器或业务代理单件来使用EJB,则很难对其进行测试。
-
如果只使用了服务定位器模式而不使用业务委托模式,应用程序代码仍然需要调用EJB Home组件的create方法,并且要处理由此产生的异常。这样代码依然存在和EJB API的耦合并感染了EJB编程模型的复杂性。
-
实现业务委托模式通常会导致大量的重复代码,因为对于EJB组件的同一个方法,我们不得不编写很多方法去调用它。
Spring的解决方式是允许用户创建并使用代码量很少的业务委托代理对象,通常在Spring的容器里配置。而不再需要编写额外的服务定位器或JNDI查找的代码,以及编码的业务委托对象里面的冗余方法,除非它们可以带来实质性的好处。
在一个企业级应用系统中,业务逻辑通常会被封装成EJB,开发者需要通过JNDI来访问EJB中的业务逻辑;异步的消息传递通常会使用JMS服务器,开发者需要通过调用服务器支持的队列或者主题来完成消息发送和接收;更多的情况下,开发者需要通过JDBC来访问企业数据库,完成相关数据的持久化工作,下面我们简单的看看访问这些资源所需要编写的代码片断。 |
访问一个EJB需要完成的代码 //初始化EJB访问上下文 Context context = new InitialContext(); //查找jndiName对应的EJB调用入口 Object o = ctx.lookup(“jndiName”); //生成EJB访问的home接口 XXXHome home = (XXXHome) javax.rmi.PortableRemoteObject .narrow(o,XXXHome.class); //创建EJB对象 XXX xxx = home.create(); //完成相关业务方法调用 … //EJB使用完毕,清除EJB对象 xxx.remove();
访问JDBC数据源要完成的代码
//加载数据库驱动 Class.forName(“driver_name_of_jdbc_driver”); //通过DriverManager获取数据库连接 Connection conn = DriverManager .getConnection(jdbcUrl,userName,password); //创建Statement对象 Statement stmt = conn.createStatement(); //完成相关数据的访问 … //关闭Statement对象 stmt.close(); //关闭数据库连接 conn.close(); 以上是硬编码获取Connection ,在EJB中还有另一种方法: @Resource DataSource dataSource; @Resource(mappedName="java:/DefaultDS") DataSource dataSource; Connection con = dataSource.getConnection(); 访问JMS需要完成的部分代码 //初始化EJB访问上下文 Context context = new InitialContext(); //通过JNDI查询连接工厂 TopicConnectionFactory factory = (TopicConnectionFactory) ctx lookup(“weblogic.jws.jms. TopicConnectionFactory”); //使用连接工厂创建JMS连接 TopicConnection conn = factory.createTopicConnection(); //创建JMS会话 TopicSession session = connection createTopicSession(false,Session.AUTO_ACKNOWLEDGE); //通过jndiName查找目的地(主题) Topic topic = (Topic) ctx.lookup(“jndiName”); //创建消息发生者 TopicPublisher publisher = session.createPublisher(topic); //创建要发送的文本消息 TextMessage message = session.createTextMessage(); message.setText(“Hello World!”); //发送文本消息 publisher.publish(message); 这些只是J2EE标准中不到四分之一服务的客户端调用代码片断,从中我们可以发现每种企业资源的访问方式和API都不相同,而且每一种调用代码的编写都不是一件非常轻松的事情,而J2EE中还提供了更多的企业资源接访问接口方式如Web Services,JavaMail等,对于开发者而言,要完全掌握J2EE1.4客户端调用代码对每一个开发者而言都不是一件轻松的事情。 控件(Controls)架构为解决这个难题提供了行之有效的方法。在控件(Controls)架构中,我们使用Java控件(Control)对资源访问进行封装,隐藏资源访问细节。开发者只需要继承这些Java控件(Control),而后提供自己的业务方法,使用Java控件(Control)中提供的特定注释(Annotation)来注释这些业务方法,就可以完成企业资源的访问工作。这种方式不但快捷高效,而且对于资源访问者而言,他始终采用同一接口去调用不同的资源,根本不需要去了解资源访问的细节。 |