Пользовательский MBean в Tomcat - не удается найти javaURLContextFactory при создании InitialContext - PullRequest
3 голосов
/ 27 сентября 2011

Я написал собственный MBean, который развертывается в Tomcat 6. Одна из его задач - запрос значения базы данных. Я делаю это, загружая ресурс базы данных, используя JNDI - ресурс определен в Tomcat's server.xml.

Проблема в том, что когда я создаю экземпляр javax.naming.InitialContext, он выдает ClassNotFoundException, так как не может найти org.apache.naming.java.javaURLContextFactory. Этот класс находится в catalina.jar и загружается общим загрузчиком классов. Jar-файл, содержащий мой MBean-код, загружается общим загрузчиком классов.

Есть идеи, как мне это обойти?

Обратите внимание: мой MBean загружается ContextListener, который я определил в tomcat/conf/web.xml. Я также определил это в веб-приложении web.xml, которое не имеет значения. Я действительно не могу переместить свой jar так, чтобы он загружался общим загрузчиком классов, поскольку он опирается на классы, загруженные общим загрузчиком классов.

Заранее спасибо,

Будет

1 Ответ

6 голосов
/ 03 октября 2011

Это выглядит странной проблемой загрузки классов или безопасности / разрешений. Ниже представлен обходной путь.

Основная идея: поскольку ServletContextListener может вызывать new InitialContext() без ClassNotFoundException, получите его в слушателе и передайте его конструктору объекта MBean перед регистрацией MBean. Я использовал простое веб-приложение и не изменил tomcat/conf/web.xml.

Конфигурация ресурса в tomcat/conf/context.xml:

<Context>
...
    <Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"
        maxActive="100" maxIdle="30" maxWait="10000"
        username="root" password="..." driverClassName="com.mysql.jdbc.Driver"
        url="jdbc:mysql://localhost:3306/javatest?autoReconnect=true"/>
...
<Context>

Конфигурация ресурса web.xml:

<resource-ref>
    <description>DB Connection</description>
    <res-ref-name>jdbc/TestDB</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref>

ServletContextListener, который регистрирует MBean:

import java.lang.management.ManagementFactory;

import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class ContextListener implements ServletContextListener {

    private ObjectName objectName;

    public void contextInitialized(final ServletContextEvent sce) {
        System.out.println("---> bean context listener started");

        final MBeanServer mbeanServer = 
            ManagementFactory.getPlatformMBeanServer();
        try {
            final InitialContext initialContext = new InitialContext();
            final Context envContext = 
                (Context) initialContext.lookup("java:/comp/env");

            objectName = new ObjectName("com.example:type=Hello");
            final Hello helloMbean = new Hello(envContext);
            mbeanServer.registerMBean(helloMbean, objectName);
            System.out.println("---> registerMBean ok");
        } catch (final Exception e) {
            e.printStackTrace();
        }
    }

    public void contextDestroyed(final ServletContextEvent sce) {
        System.out.println("---> bean context listener destroyed");
        final MBeanServer mbeanServer = 
            ManagementFactory.getPlatformMBeanServer();
        try {
            mbeanServer.unregisterMBean(objectName);
            System.out.println("---> unregisterMBean ok");
        } catch (final Exception e) {
            e.printStackTrace();
        }
    }
}

Интерфейс MBean:

public interface HelloMBean {
    void sayHello();
}

Реализация MBean:

import java.sql.Connection;

import javax.naming.Context;
import javax.sql.DataSource;

public class Hello implements HelloMBean {

    private final Context envContext;

    public Hello(final Context envContext) {
        this.envContext = envContext;
        System.out.println("new hello " + envContext);
    }

    @Override
    public void sayHello() {
        System.out.println("sayHello()");

        try {
            final DataSource ds = 
                (DataSource) envContext.lookup("jdbc/TestDB");
            final Connection conn = ds.getConnection();
            System.out.println("   conn: " + conn);
            // more JDBC code
        } catch (final Exception e) {
            e.printStackTrace();
        }
    }
}

В дескрипторе MBean How To говорится, что mbeans-descriptor.xml требуется, но он работал без него хорошо. Я мог бы подключиться к HelloMBean с jconsole. Вызов sayHello() через jconsole напечатал следующее:

conn: jdbc:mysql://localhost:3306/javatest?autoReconnect=true, \
UserName=root@localhost, MySQL-AB JDBC Driver

Источники:

...