JBoss JDBC MBean在未找到服务器时阻止启动

JBoss JDBC MBean在未找到服务器时阻止启动,jdbc,jboss,mbeans,persistence-manager,Jdbc,Jboss,Mbeans,Persistence Manager,在JBoss启动期间,我有一个依赖于JDBC连接(DefaultDS)的持久性管理器。无论JDBC连接是否可以实际连接到数据库,JDBC连接都可以正常启动,因此,当持久性管理器启动时,它认为它有一个连接。然后它就爆炸了,因为它无法连接到数据库,而且永远不会启动。这会阻止我的DestinationManager启动,并导致各种各样的头痛 有没有办法使依赖于JDBC连接的MBean不启动,除非JDBC连接可以实际连接到数据库?作为替代方案,是否有一种方法使JDBC连接依赖于只有在数据库可以连接时才处

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

有没有办法使依赖于JDBC连接的MBean不启动,除非JDBC连接可以实际连接到数据库?作为替代方案,是否有一种方法使JDBC连接依赖于只有在数据库可以连接时才处于活动状态的MBean

tl;博士我所需要的只是让我的MBean/DestinationManager在启动之前等待数据库(DefaultDS)可用。

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

  • JBoss版本4.2.3

  • 数据库:MsSql


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

不幸的是,即使启用了该选项,数据源服务仍然会正常启动,即使它无法建立连接

最好的办法是实现一个在数据源报告启动之前检查其实际连接的方法。对于本例,我们将其命名为org.bob.conncChecker,并将使用ObjectNameorg.bob:service=conncChecker进行部署

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

  <mbean code="org.bob.ConnChecker" name="jboss.mq:service=DestinationManager">
    <depends optional-attribute-name="DataSource">jboss.jca:name=DefaultDS,service=ManagedConnectionPool</depends>
  </mbean>
....
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);
    }
}
....
import org.jboss.system.ServiceMBeanSupport;
....
public interface ConnCheckerMBean extends ServiceMBean {
    public void setDataSource(ObjectName dataSourceObjectName);
}
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});
conncCheckerMBean的代码如下所示:

  <mbean code="org.bob.ConnChecker" name="jboss.mq:service=DestinationManager">
    <depends optional-attribute-name="DataSource">jboss.jca:name=DefaultDS,service=ManagedConnectionPool</depends>
  </mbean>
....
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);
    }
}
....
import org.jboss.system.ServiceMBeanSupport;
....
public interface ConnCheckerMBean extends ServiceMBean {
    public void setDataSource(ObjectName dataSourceObjectName);
}
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});

因此,如果无法连接到数据库,但DestinationManager无法启动,您仍然会出现错误,希望这比您现在遇到的麻烦要好。

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

不幸的是,即使启用了该选项,数据源服务仍然会正常启动,即使它无法建立连接

最好的办法是实现一个在数据源报告启动之前检查其实际连接的方法。对于本例,我们将其命名为org.bob.conncChecker,并将使用ObjectNameorg.bob:service=conncChecker进行部署

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

  <mbean code="org.bob.ConnChecker" name="jboss.mq:service=DestinationManager">
    <depends optional-attribute-name="DataSource">jboss.jca:name=DefaultDS,service=ManagedConnectionPool</depends>
  </mbean>
....
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);
    }
}
....
import org.jboss.system.ServiceMBeanSupport;
....
public interface ConnCheckerMBean extends ServiceMBean {
    public void setDataSource(ObjectName dataSourceObjectName);
}
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});
conncCheckerMBean的代码如下所示:

  <mbean code="org.bob.ConnChecker" name="jboss.mq:service=DestinationManager">
    <depends optional-attribute-name="DataSource">jboss.jca:name=DefaultDS,service=ManagedConnectionPool</depends>
  </mbean>
....
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);
    }
}
....
import org.jboss.system.ServiceMBeanSupport;
....
public interface ConnCheckerMBean extends ServiceMBean {
    public void setDataSource(ObjectName dataSourceObjectName);
}
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});
因此,如果无法连接到数据库,您仍然会出现错误,但DestinationManager不会启动,希望这比您现在遇到的麻烦要好


因此,没有办法让一堆豆子只是“等待”而不动 允许Jboss一直启动吗

不是以任何标准的方式。JBoss引导周期要么运行到完成,要么报告依赖项失败。这个过程是连续的和单线程的(直到JBoss7)

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

  • 重新执行ConnChecker以在单独的线程中运行其连接测试。它将被视为在该线程生成后立即启动
  • 将您想要依赖的服务的所有XML配置文件conncChecker(我猜这将是所有JMS部署XML)文件拉到部署之外的另一个目录中,例如/jboss/server/bob/late deploy
  • 由于延迟服务文件现在不在URLDeploymentScanner的路径列表中,因此它们不会作为默认部署过程的一部分进行部署
部署延迟服务文件的诀窍是,新的ConnChecker将愉快地旋转,等待获得连接(可能会超时并立即停止),但当它成功获得连接时,它将执行如下代码:

  <mbean code="org.bob.ConnChecker" name="jboss.mq:service=DestinationManager">
    <depends optional-attribute-name="DataSource">jboss.jca:name=DefaultDS,service=ManagedConnectionPool</depends>
  </mbean>
....
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);
    }
}
....
import org.jboss.system.ServiceMBeanSupport;
....
public interface ConnCheckerMBean extends ServiceMBean {
    public void setDataSource(ObjectName dataSourceObjectName);
}
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});
因此,这将告诉部署扫描程序“也开始查看此目录”,几秒钟后,您的后期服务将部署,希望不会出现错误。此外,由于您在运行时添加了延迟服务(因此是非持久性的),当服务器重新启动时,部署扫描程序将恢复为其原始配置,等待conncChecker向其添加新URL

只需确保部署人员已将scanabled设置为true,并且scanperion足够低,以便在建立JDBC连接后获得部署后期服务所需的响应时间。该MBean配置正在运行

<jboss-home>/server/<server-name>/conf/jboss-service.xml
/server//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>

....
5000
真的
....

因此,没有办法让一堆豆子只是“等待”而不动 允许Jboss一直启动吗

不是以任何标准的方式。JBoss引导周期要么运行到完成,要么报告依赖项失败。这个过程是连续的和单线程的(直到JBoss7)

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

  • 重新执行ConnChecker以在单独的线程中运行其连接测试。它将被视为在该线程生成后立即启动
  • 将您想要依赖的服务的所有XML配置文件conncChecker(我猜这将是所有JMS部署XML)文件拉到部署之外的另一个目录中,例如/jboss/