Пользовательский MBean в Tomcat - не удается найти javaURLContextFactory при создании InitialContext

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

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

Любые идеи относительно того, как я могу обойти это?

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

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

Воля


person Will    schedule 27.09.2011    source источник
comment
Можете ли вы опубликовать точную конфигурацию? web.xml, server.xml и так далее.   -  person Tarlog    schedule 02.10.2011


Ответы (1)


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

Основная идея: поскольку 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

Источники:

person palacsint    schedule 02.10.2011