【问题标题】:JBoss JDBC MBean Prevent Startup If Server Not Found如果找不到服务器,JBoss JDBC MBean 会阻止启动
【发布时间】:2026-02-22 07:00:01
【问题描述】:

在 JBoss 启动期间,我有一个依赖于 JDBC 连接 (DefaultDS) 的持久性管理器。 JDBC 连接启动良好,无论它是否可以实际连接到数据库,因此当 Persistence Manager 启动时,它认为它有一个连接。然后它爆炸了,因为它无法连接到数据库并且永​​远不会启动。这会阻止我的 DestinationManager 启动并导致各种头痛。

有没有办法让依赖于 JDBC 连接的 MBean 不启动,除非 JDBC 连接可以真正连接到数据库?作为替代方案,有没有办法让 JDBC 连接依赖于仅在可以连接数据库时才处于活动状态的 MBean?

tl;博士;我所需要的只是让我的 MBeans/DestinationManager 等到数据库 (DefaultDS) 可用后再启动。

如果您需要有关环境的更多信息,请发表评论。

  • JBoss 4.2.3 版

  • 数据库:MsSql

【问题讨论】:

    标签: jdbc jboss mbeans persistence-manager


    【解决方案1】:

    如果我对问题的理解正确,那么您遇到了问题,因为即使 DefaultDS 数据源报告它已启动,但由于它没有获得任何连接,您不一定知道可以建立连接

    很遗憾,即使启用了prefill 选项,即使无法建立连接,数据源服务仍会正常启动。

    最好的办法是实现一个ServiceMBean,它会在报告启动之前检查来自数据源的实际连接。对于此示例,我们将其称为 org.bob.ConnChecker,并将使用 ObjectName org.bob:service=ConnChecker 进行部署。

    您的部署描述符应如下所示:

      <mbean code="org.bob.ConnChecker" name="jboss.mq:service=DestinationManager">
        <depends optional-attribute-name="DataSource">jboss.jca:name=DefaultDS,service=ManagedConnectionPool</depends>
      </mbean>
    

    因此,在数据源启动之前,您的服务不会启动。除非它可以建立连接,否则您的服务将不会启动。现在您只需添加 org.bob:service=ConnChecker 作为 DestinationManager 的依赖项:

    jboss.mq:service=MessageCache jboss.mq:service=PersistenceManager jboss.mq:service=StateManager jboss.mq:service=线程池 jboss:service=命名 org.bob:service=ConnChecker

    ConnChecker 的代码如下所示:

    ....
    import org.jboss.system.ServiceMBeanSupport;
    ....
    public class ConnChecker extends ServiceMBeanSupport implements ConnCheckerMBean {
        /** The ObjectName of the data source */
        protected ObjectName dataSourceObjectName = null;
        /** The Datasource reference */
        protected DataSource dataSource = null;
        /**
         * Called by JBoss when the dataSource has started
         * @throws Exception This will happen if the dataSource cannot provide a connection
         * @see org.jboss.system.ServiceMBeanSupport#startService()
         */
        public void startService() throws Exception {
            Connection conn = null;
            try {
                // Get the JNDI name from the DataSource Pool MBean
                String jndiName = (String)server.getAttribute(dataSourceObjectName, "PoolJndiName");
                // Get a ref to the DataSource from JNDI
                lookupDataSource(jndiName);
                // Try getting a connection
                conn = dataSource.getConnection();
                // If we get here, we successfully got a connection and this service will report being Started
            } finally {
                if(conn!=null) try { conn.close(); } catch (Exception e) {}
            }
        }
        /**
         * Configures the service's DataSource ObjectName
         * @param dataSourceObjectName The ObjectName of the connection pool
         */
        public void setDataSource(ObjectName dataSourceObjectName) {
            this.dataSourceObjectName = dataSourceObjectName;
        }
        /**
         * Acquires a reference to the data source from JNDI
         * @param jndiName The JNDI binding name of the data source
         * @throws NamingException
         */
        protected void lookupDataSource(String jndiName) throws NamingException {
            dataSource = (DataSource)new InitialContext().lookup(jndiName);
        }
    }
    

    ConnCheckerMBean 的代码如下所示:

    ....
    import org.jboss.system.ServiceMBeanSupport;
    ....
    public interface ConnCheckerMBean extends ServiceMBean {
        public void setDataSource(ObjectName dataSourceObjectName);
    }
    

    因此,如果无法与数据库建立连接,您将仍然遇到错误,但 DestinationManager 将不会启动,希望这会比您现在遇到的头疼问题要好。

    【讨论】:

    • 这就是我最终要做的事情,但无论如何都要让 bean 等待/停止,直到它能够获得连接。现在我让它旋转检查连接,直到它可以得到一个。但这不允许服务器启动。
    • 当然。在 ConnChecker 的 startService 方法中,循环连接测试,每次获取连接失败总共 y 次,然后简单地休眠 x 秒,然后抛出异常。
    • 所以没有办法让一堆豆子只是“等待”而仍然让 Jboss 一直启动?
    【解决方案2】:

    所以没有办法让一堆豆子只是“等待”而仍然 让 Jboss 一直开机?

    不是以任何标准方式。 JBoss 引导周期要么一直运行到完成,要么报告依赖关系失败。该过程是顺序的和单线程的(直到 JBoss 7)。

    你能做的(我只是简单地测试了一下)是:

    • 重新实现 ConnChecker 以在单独的线程中运行其连接测试。一旦产生该线程,它将被视为已启动。
    • 将您想要依赖的服务的所有 XML 配置文件拉出 ConnChecker(我猜这将是所有 JMS 部署 XML)文件到 deploy 之外的另一个目录中,例如 /jboss/server/bob/late-deploy
    • 由于后期服务文件现在不在 URLDeploymentScanner 的路径列表中,因此它们不会作为默认部署过程的一部分进行部署。

    部署后期服务文件的诀窍在于,您的新 ConnChecker 会愉快地旋转,等待建立连接(并且可能会超时并停在那里),但当它成功时获取连接,它将执行如下代码:

    import javax.management.*;
    .....
    // The JBoss URL Deployment Scanner MBean ObjectName
    ObjectName on = new ObjectName("jboss.deployment:flavor=URL,type=DeploymentScanner");
    // server is the JBossMBean server. ServiceMBeans automatically have this reference.
    server.invoke(on, "addURL", new Object[]{new URL("file:/jboss/server/bob/late-deploy")}, new String[]{String.class.getName});
    

    所以它的作用是告诉部署扫描器“也开始查看此目录”,几秒钟后,您的后期服务将部署,希望没有错误。此外,由于您在运行时添加了后期服务(因此是非持久性的),当服务器重新启动时,部署扫描程序将恢复到其原始配置,等待 ConnChecker 添加新的 URL给它。

    只需确保部署者已将 ScanEnabled 设置为 true 并且 ScanPeriod 足够低,以便您获得所需的响应时间来部署后期服务已建立 JDBC 连接。该 MBean 配置位于

    <jboss-home>/server/<server-name>/conf/jboss-service.xml
    

    寻找这个:

       <mbean code="org.jboss.deployment.scanner.URLDeploymentScanner"
          name="jboss.deployment:type=DeploymentScanner,flavor=URL">
    ....
          <!-- Frequency in milliseconds to rescan the URLs for changes -->
          <attribute name="ScanPeriod">5000</attribute>
          <!-- A flag to disable the scans -->
          <attribute name="ScanEnabled">true</attribute>
    ....
       </mbean>
    

    【讨论】: