如果未找到服务器,JBoss JDBC MBean 会阻止启动

发布于 2024-11-25 20:00:40 字数 485 浏览 3 评论 0原文

在 JBoss 启动期间,我有一个依赖于 JDBC 连接(DefaultDS)的持久性管理器。无论 JDBC 连接是否能够真正连接到数据库,它都会正常启动,因此当持久性管理器启动时,它会认为它已建立连接。然后它就崩溃了,因为它无法连接到数据库并且永​​远不会启动。这会阻止我的 DestinationManager 启动并导致各种头痛。

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

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

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

  • JBoss 版本 4.2.3

  • 数据库:MsSql

During JBoss startup I have a Persistence Manager that depends on a JDBC connection (DefaultDS). The JDBC connection starts fine whether or not it can actually connect to the database so when the Persistence Manager starts it thinks it has a connection. Then it blows up because it cannot connect to the database and never starts. This prevents my DestinationManager from starting and causes all kinds of headache.

Is there a way to make MBeans that depend on the JDBC connection not start unless the JDBC connection can actually connect to the database? As an alternative, is there a way to make the JDBC connection depend on an MBean that is only active while the database can be connected to?

tl;dr; All I need is for my MBeans/DestinationManager to wait until the database (DefaultDS) is available before booting.

Please comment if you need more info about the enviornment.

  • JBoss version 4.2.3

  • Database: MsSql

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

無心 2024-12-02 20:00:41

如果我正确理解了该问题,那么您遇到了问题,因为即使 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 不会启动,希望这比您现在遇到的麻烦要好。

If I understand the issue correctly, you're having a problem because even though the DefaultDS data source reports that it has started, since it has not acquired any connections, you don't necessarily know that connections can be made .

Unfortunately, even with the prefill option enabled, the datasource service will still start normally even if it cannot make a connection.

Your best bet is to implement a ServiceMBean that checks an actual connection from the datasource before it reports being started. For this example, we'll call it org.bob.ConnChecker and will deployed using the ObjectName org.bob:service=ConnChecker.

Your deployment descriptor should look something like this:

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

So your service will not be started until the data source has started. Your service will not start unless it can get a connection. Now you just have to add org.bob:service=ConnChecker as a dependency of the DestinationManager:

jboss.mq:service=MessageCache
jboss.mq:service=PersistenceManager
jboss.mq:service=StateManager
jboss.mq:service=ThreadPool
jboss:service=Naming
org.bob:service=ConnChecker

The code for ConnChecker will look something like this:

....
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);
    }
}

The code for ConnCheckerMBean looks like this:

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

So you will still get errors if connections cannot be made to the database, but the DestinationManager will not start, and hopefully that will be better than the headaches you're having now.

长安忆 2024-12-02 20:00:41

所以没有办法让一堆豆子只是“等待”并且仍然
允许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>

So there is no way to have a bunch of beans just "waiting" and still
allow Jboss to boot all the way up?

Not in any standard fashion. The JBoss boot cycle either runs through to completion or reports a dependency failure. The process is sequential and single-threaded (until JBoss 7).

What you could do (and I only briefly tested this) is:

  • Re-implement the ConnChecker to run its connection test in a separate thread. It will be considered started as soon as that thread is spawned.
  • Pull out all the XML config files for services you want to depend on ConnChecker (I guess this would be all JMS deployment XML) files into another directory outside of deploy, say for example /jboss/server/bob/late-deploy.
  • Since the late-service files are now not in the URLDeploymentScanner's list of paths, they will not be deployed as part of the default deployment process.

The trick to getting the late-service files to deploy is that your new ConnChecker will happily spin, waiting to get a connection (and might possibly timeout and stop right there) but when it does successfully acquire a connection, it will execute code that looks like this:

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});

So what this does is tell the deployment scanner "start looking in this directory too" and a couple of seconds later, your late-services will deploy, hopefully error free. Additionally, since you added the late-service at runtime (and therefore non-persistently), when the server restarts, the deployment scanner will be reverted back to it's original configuration, waiting for ConnChecker to add new URLs to it.

Just make sure that the deployer has ScanEnabled set to true and that the ScanPeriod is low enough that you get the required response time to deploy your late-services once the JDBC connection is made. That MBean configuration is in

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

Look for this:

   <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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文