我编写了一个在Tomcat 6中部署的自定义MBean。其任务之一是查询数据库值。我这样做是通过使用JNDI加载数据库资源 - 资源是在Tomcat的server.xml中定义的。
问题在于,当我创建javax.naming.InitialContext
的实例时,它会抛出ClassNotFoundException
,因为找不到org.apache.naming.java.javaURLContextFactory
。
此类位于catalina.jar
中,并由公共类加载器加载。包含我的MBean代码的jar由共享类加载器加载。
关于如何解决这个问题的任何想法?
要注意:我的MBean是由我在tomcat/conf/web.xml
中定义的ContextListener加载的。我也在webapp web.xml
中定义了它,没有任何区别。我无法真正移动我的jar以便由公共类加载器加载,因为它依赖于共享类加载器加载的类。
提前致谢,
威尔
答案 0 :(得分:6)
看起来很奇怪的类加载或安全/权限问题。以下是解决方法。
主要思想:由于ServletContextListener
可以在没有new InitialContext()
的情况下调用ClassNotFoundException
在监听器中获取它,并在注册MBean之前将其传递给MBean对象的构造函数。我使用了一个简单的Web应用程序,但我没有修改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>
注册MBean的ServletContextListener
:
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 Descriptor How To说mbeans-descriptor.xml
是必需的,但是没有它就能正常工作。我可以使用jconsole
连接到HelloMBean。致电sayHello()
至jconsole
打印了以下内容:
conn: jdbc:mysql://localhost:3306/javatest?autoReconnect=true, \
UserName=root@localhost, MySQL-AB JDBC Driver
来源: