技术开发 频道

JCA 1.5: 优化和生命周期管理

      征募,还是不征募

  大家都知道事务代价很高——特别是 XA(全局)事务。这使得让事务不执行非必需的工作变得很重要。JCA 1.5 中的另外两个新接口防止了 XAResource 对象的不必要征募。

  我们现在来更详细地分析一下这种增强所针对的问题。假定取用 清单 1 中的 EJB,并用容器托管的事务部署它,将业务方法的事务属性设定为 RequiresNew。调用这个方法时便开始一个新的事务。创建连接时,连接管理器不知道如何使用它,因此它必须从关联的托管连接获得一个 XAResource,并在事务中征募它。连接可能只用于查询数据库或者根本不被使用。但是连接管理器必须征募连接,以备插入或者更新操作。这意味着,资源适配器至少必须进行开始、提交或者回滚,并结束流程返回后端。图 4 展示了这样的事务流程。

  图 4. 急切事务征募

   在图 4 中可以看到,获得连接后,XAResource 立即征募到了事务中(即接收一个开始流程)。这意味着当事务方法结束时,流程需要在资源处结束,即使方法没有在事务中使用连接。

  如果在事务中涉及另一项资源,就会强制进行不必要的两阶段提交,导致额外的准备流程。这里的惟一可取之处是资源管理器仍然可以从准备调用中返回 XA_RDONLY (用于“read only”)以表明它实际没有做任何工作。事务管理器不需要在那个资源管理器处完成调用,并且如果在事务中只有一个资源管理器真正做了工作,那么事务管理器也许可以避免日志文件中的惰性写操作。

  惰性征募

  现在您应当认识到除非绝对需要,否则不要在事务中征募。JCA 1.5 规范提供了一个解决方案:惰性征募。清单 4 显示了支持这各种优化所引入的两个接口。

  清单 4. 惰性征募的接口

1 public interface LazyEnlistableManagedConnection {
2 }
3 public interface LazyEnlistableConnectionManager {
4     void lazyEnlist(ManagedConnection mc)
5             throws ResourceException;
6 }

  LazyEnlistableManagedConnection 接口是由托管连接实现的标记接口,用以向连接管理器表明在事务中创建新的连接或者在连接已经存在的情况下开始一个新的事务时,它不需要将托管连接急切征募到现有事务中。如果连接句柄准备执行应当是任一事务中的一部分的某些工作,并且它的托管连接还没有征募,那么应当确定连接管理器是否实施了 LazyEnlistableConnectionManager 接口。如果实施了,那么它应当调用传递托管连接的 lazyEnlist 方法。这个方法不返回任何结果,但是如果调用线程关联了一个事务,那么这时就征募托管连接的 XAResource。如果连接没有被征募,那么它需要在后面每一项工作之前再次调用 lazyEnlist,以检查在上次调用这个方法之后,是不是没有启动过事务。

  图 5 显示了这个新的事件序列。

  图 5. 惰性事务征募

  在图 5 中可以看到,在获得连接时,XAResource 不再急切征募。相反,连接管理器会等待,直到连接用 lazyEnlist 调用表明它要完成一些事务工作时,才会征募 XAResource。

  什么时候出现错误

  JCA 规范的第一个版本提供了一种让资源适配器在连接出现严重错误时通知连接管理器的机制。这是 ConnectionEventListener 接口的 connectionErrorOccurred 方法。收到这个通知后,连接管理器就会毁环发送事件的托管连接,这样就不会再使用它。这些都是不错的。但是,如果到后端的连接丢失了,那么池中的许多托管连接也很有可能不能再使用。

  针对这个问题,JCA 1.5 以 ValidatingManagedConnectionFactory 接口的方式引入了一种雅洁的解决方案,如清单 5 所示。

  清单 5. 用于确定无效连接的接口

1 public interface ValidatingManagedConnectionFactory {
2     Set getInvalidConnections(Set connectionSet)
3             throws ResourceException;
4 }
5

  由托管连接厂实现的 ValidatingManagedConnectionFactory 接口包含一个方法——getInvalidConnections——它以一组托管连接为参数,返回资源适配器认为无效的一个子集。资源适配器的验证可以采取任何形式,不过通常涉及到对后端的某种“ping”操作,以测试连接。然后连接管理器在资源适配器指示连接错误时调用这个方法,甚至定期调用该方法,以便从池中排除坏掉的连接。

  开始和结束

  最初的 JCA 版本为托管连接及其相关联的连接句柄提供了详细的生命周期模式,但是它没有为资源适配器提供这种概念。只有当创建了托管连接厂后,部署的资源适配器才知道它的存在。JCA 1.5 中引入的 ResourceAdapter 接口对此进行了纠正,如清单 6 所示。

  清单 6. 新资源适配器接口的生命周期方法

1 public interface ResourceAdapter {
2     void start(BootstrapContext ctx)
3             throws ResourceAdapterInternalException;
4     void stop();
5     ...
6 }

  资源适配器可以在其部署描述符(ra.xml)的 resourceadapter-class 元素中给出实现这个接口的类的名称。除了实现 ResourceAdapter 接口,这个类可以通过 JavaBean 样式支持某些属性。与托管连接厂一样,在部署描述符中可以声明这些属性及其默认值,如清单 7 所示。在安装了资源适配器后,应用服务器将允许管理员覆盖这些默认值。

  清单 7. 资源适配器部署描述符

1 <connector>
2   ...
3   <resourceadapter>
4     <resourceadapter-class>
5       example.ExampleResourceAdapterImpl
6     </resourceadapter-class>
7     <config-property>
8       <config-property-name>ServerName</config-property-name>
9       <config-property-type>java.lang.String</config-property-type>
10       <config-property-value>MyServer</config-property-value>
11     </config-property>
12     <config-property>
13       <config-property-name>PortNumber</config-property-name>
14       <config-property-type>java.lang.String</config-property-type>
15       <config-property-value>1976</config-property-value>
16     </config-property>
17   </resourceadapter>
18   ...
19 </connector>

  在启动时,应用服务器会创建在部署描述符中指定的类的一个实例,并设置管理员提供的属性。这个类必须根据这些属性实现一个 equals 方法,这样应用服务器就可以保证它不会创建一个以上同样的实例。然后会调用 start 方法,向它传递一个实现了 BootstrapContext 接口的对象。可以用这个对象创建计时器、调度其他线程上的工作和控制导入的事务,在本系列的第 2 部分中将更详细地讨论所有这些内容。这个方法将不会堵塞并会及时返回。

  应用服务器通常会在关闭或者解除部署资源适配器之前,对资源适配器调用 stop 方法。JCA 1.5 规范描述了这个过程的两个阶段。首先,应用服务器保证依赖资源适配器的所有应用程序都已停止。这可保证程序线程不再使用资源适配器对象,并且所有事务都已完成。然后应用服务器调用 stop 方法。这时,资源适配器将执行一个有序的关闭(例如,释放网络和应用服务器资源,并将所有缓存的数据强行送回后端)。调用 stop 后,应用服务器将不会重新使用资源适配器实例。

  为了保留向后兼容性,ManagedConnectionFactory 没有改变,但是如果希望外部资源可以利用资源适配器具有的功能,那么还要实现清单 8 所示的新的 ResourceAdapterAssociation 接口。

  清单 8. ResourceAdapterAssociation 接口

1 public interface ResourceAdapterAssociation {
2     ResourceAdapter getResourceAdapter();
3     void setResourceAdapter(ResourceAdapter ra)
4             throws ResourceException;
5 }

  构建了托管连接厂之后,应用服务器将调用 setResourceAdapter 方法以便将它与其资源适配器关联在一起。在托管连接厂的生命周期内这种关联将会固定下来。这种方法只调用一次。

  结束语

  本文展示了 JCA 1.5 为现有出站契约带来的四项增强功能。惰性关联和征募优化会提高使用连接的应用程序的性能,验证托管连接厂会改善对故障情况的处理。在资源适配器级别引入生命周期管理为资源适配器提供了多种有趣的新机会。本系列的第 2 部分将分析如何在这个基础上建立新的工作管理和事务流入契约。

0
相关文章