在JBoss AS6中通过JMX调用EJB方法时的类加载器问题

时间:2011-07-20 13:41:19

标签: classloader jmx jboss6.x

我目前正在使用AS6.final,Weld已升级到1.1.1.final。 EAR类隔离已关闭。我有一个EJB单例,我已经注册了JMX - EJB类打包在EAR中的JAR中。当我通过JMX控制台调用此bean上的一个方法时,我收到此错误:


09:13:49,984 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[localhost].[/jmx-console].[HtmlAdaptor]] Servlet.service() for servlet HtmlAdaptor threw exception: java.lang.IllegalStateException: Singleton not set for BaseClas
sLoader@c68740c{vfs:///C:/jboss-6.0.0.Final/common/deploy/jmx-console.war}
        at org.jboss.weld.integration.provider.JBossSingletonProvider$EarSingleton.get(JBossSingletonProvider.java:59) [:6.0.0.Final]
        at org.jboss.weld.Container.instance(Container.java:58) [:2011-04-04 15:54]
        at org.jboss.weld.resolution.ResolvableBuilder.checkQualifier(ResolvableBuilder.java:209) [:2011-04-04 15:54]
        at org.jboss.weld.resolution.ResolvableBuilder.addQualifier(ResolvableBuilder.java:174) [:2011-04-04 15:54]
        at org.jboss.weld.resolution.ResolvableBuilder.addQualifiers(ResolvableBuilder.java:202) [:2011-04-04 15:54]
        at org.jboss.weld.bean.builtin.InstanceImpl.get(InstanceImpl.java:108) [:2011-04-04 15:54]
        at org.jboss.seam.transaction.TransactionInterceptor.aroundInvoke(TransactionInterceptor.java:188) [:3.0.0.Final]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [:1.6.0_07]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) [:1.6.0_07]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) [:1.6.0_07]
        at java.lang.reflect.Method.invoke(Method.java:597) [:1.6.0_07]
        at org.jboss.interceptor.proxy.InterceptorInvocation$InterceptorMethodInvocation.invoke(InterceptorInvocation.java:72) [:2.0.0.CR1]
        at org.jboss.interceptor.proxy.SimpleInterceptionChain.invokeNextInterceptor(SimpleInterceptionChain.java:82) [:2.0.0.CR1]
        at org.jboss.interceptor.proxy.InterceptorMethodHandler.executeInterception(InterceptorMethodHandler.java:133) [:2.0.0.CR1]
        at org.jboss.interceptor.proxy.InterceptorMethodHandler.invoke(InterceptorMethodHandler.java:112) [:2.0.0.CR1]
        at org.jboss.weld.bean.proxy.CombinedInterceptorAndDecoratorStackMethodHandler.invoke(CombinedInterceptorAndDecoratorStackMethodHandler.java:65) [:2011-04-04 15:54]
        at uk.co.myApp.myService.service.org$jboss$weld$bean-jboss$classloader$id="vfs$$$$C$$jboss-6$0$0$Final$server$all$deploy$myService-ear-2011$1$2-SNAPSHOT$ear"-ManagedBean-uk$co$myApp$myService$service$MyServiceerDAO$@org$jboss$seam$transaction$
Transactional(value=REQUIRED)@org$jboss$seam$transaction$TransactionalInterceptorBinding()${uk$co$myApp$myService$service$MyServiceerDAO$jamJobTrackerDAO$@javax$inject$Inject()$$uk$co$myApp$myService$service$MyServiceerDAO$linkDAO$@javax$inject$Inject
()$$uk$co$myApp$myService$service$MyServiceerDAO$ruleDAO$@javax$inject$Inject()$$uk$co$myApp$myService$service$MyServiceerDAO$sliceDAO$@javax$inject$Inject()$$uk$co$myApp$myService$service$MyServiceerDAO$myServiceJobDAO$@javax$inject$Inject()$$}_$$_WeldSubclass.l
oadSliceInitialiseMyServiceCollections(org$jboss$weld$bean-jboss$classloader$id="vfs$$$$C$$jboss-6$0$0$Final$server$all$deploy$myService-ear-2011$1$2-SNAPSHOT$ear"-ManagedBean-uk$co$myApp$myService$service$MyServiceerDAO$@org$jboss$seam$transaction$Tr
ansactional(value=REQUIRED)@org$jboss$seam$transaction$TransactionalInterceptorBinding()${uk$co$myApp$myService$service$MyServiceerDAO$jamJobTrackerDAO$@javax$inject$Inject()$$uk$co$myApp$myService$service$MyServiceerDAO$linkDAO$@javax$inject$Inject()
$$uk$co$myApp$myService$service$MyServiceerDAO$ruleDAO$@javax$inject$Inject()$$uk$co$myApp$myService$service$MyServiceerDAO$sliceDAO$@javax$inject$Inject()$$uk$co$myApp$myService$service$MyServiceerDAO$myServiceJobDAO$@javax$inject$Inject()$$}_$$_WeldSubclass.jav
a)
        at uk.co.myApp.myService.service.MyServiceService.startCDIJob(MyServiceService.java:96) [:]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [:1.6.0_07]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) [:1.6.0_07]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) [:1.6.0_07]
        at java.lang.reflect.Method.invoke(Method.java:597) [:1.6.0_07]
        at org.gescobar.management.util.MBeanImpl.invoke(MBeanImpl.java:181) [:]
        at org.jboss.mx.server.RawDynamicInvoker.invoke(RawDynamicInvoker.java:164) [:6.0.0.GA]
        at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:670) [:6.0.0.GA]
        at org.jboss.jmx.adaptor.control.Server.invokeOpByName(Server.java:258) [:]
        at org.jboss.jmx.adaptor.control.Server.invokeOp(Server.java:223) [:]
        at org.jboss.jmx.adaptor.html.HtmlAdaptorServlet$3.run(HtmlAdaptorServlet.java:380) [:]
        at org.jboss.jmx.adaptor.html.HtmlAdaptorServlet$3.run(HtmlAdaptorServlet.java:377) [:]
        at java.security.AccessController.doPrivileged(Native Method) [:1.6.0_07]
        at org.jboss.jmx.adaptor.html.HtmlAdaptorServlet.invokeOp(HtmlAdaptorServlet.java:376) [:]
        at org.jboss.jmx.adaptor.html.HtmlAdaptorServlet.invokeOp(HtmlAdaptorServlet.java:287) [:]
        at org.jboss.jmx.adaptor.html.HtmlAdaptorServlet.processRequest(HtmlAdaptorServlet.java:104) [:]
        at org.jboss.jmx.adaptor.html.HtmlAdaptorServlet.doPost(HtmlAdaptorServlet.java:86) [:]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:754) [:1.0.0.Final]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:847) [:1.0.0.Final]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:324) [:6.0.0.Final]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:242) [:6.0.0.Final]
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [:6.0.0.Final]
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) [:6.0.0.Final]
        at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:181) [:6.0.0.Final]
        at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:88) [:6.0.0.Final]
        at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:100) [:6.0.0.Final]
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) [:6.0.0.Final]
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [:6.0.0.Final]
        at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158) [:6.0.0.Final]
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [:6.0.0.Final]
        at org.jboss.web.tomcat.service.request.ActiveRequestResponseCacheValve.invoke(ActiveRequestResponseCacheValve.java:53) [:6.0.0.Final]
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:362) [:6.0.0.Final]
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [:6.0.0.Final]
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:654) [:6.0.0.Final]
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:951) [:6.0.0.Final]
        at java.lang.Thread.run(Thread.java:619) [:1.6.0_07]

该方法涉及打开事务,您可以从跟踪中看到。我认为一般错误与类加载有关(参见https://issues.jboss.org/browse/SEAMJMS-16);通过在浏览器中通过JMX控制台调用该方法,我在包含EJB类的EAR应用程序的“外部”进行。

我已经尝试通过在EAR jboss-app.xml和EAR jboss-app.xml中添加以下代码(在文件之间进行必要的语法更改)来指定作用域类加载(http://community.jboss.org/wiki/ClassLoadingConfiguration)。 jmx-console.war jboss-web.xml:

<class-loading java2ClassLoadingCompliance="false">
  <loader-repository>
     my.domain:archive=myapp-ear
     <loader-repository-config>java2ParentDelegation=false</loader-repository-config>
  </loader-repository>
</class-loading>

但是这没有效果。

我已被提及https://issues.jboss.org/browse/WELD-888,并认为我可以寻求类似的解决方案;关闭jmx-console.war的WAR类隔离,以便它可以看到已部署的其他类(EAR类隔离已经关闭)。

http://community.jboss.org/wiki/UseJBossWebClassLoaderInJBoss5提供了2种方法:

  1. 在所有/ deployers / jbossweb.deployer / META-INF / war-deployers-jboss-beans.xml中注释掉WarClassLoaderDeployer bean
  2. 使用以下内容将新文件jboss-classloading添加到jmx-console.war / WEB-INF /中:

    <?xml version="1.0" encoding="UTF-8"?>
    <classloading xmlns="urn:jboss:classloading:1.0"
        name="jmx-console.war"
        domain="DefaultDomain"
        parent-domain="Ignored"           
        export-all="NON_EMPTY"
        import-all="true">
    </classloading>
    
  3. 我已经尝试了这两个,分别使用common / deploy和server / all / deploy中的jmx-console.war目录 - 它们似乎都不起作用。

    即使将所有必需的lib放在jmx-console.war / WEB-INF / lib /中也不起作用,因为它在您调用JMX控制台时尝试再次部署EJB(至少部署到Weld)!无论如何,这不是一个好的解决方案 - 每次部署时,你都必须更新lib。

    那么......任何想法如何实现jmx-console.war的EAR类可见性?实际上用它来做一些有意义的事情?

1 个答案:

答案 0 :(得分:0)

现在对此进行排序,感谢JBoss.org论坛上的Ales Justin(http://community.jboss.org/message/616328)。

基本上,我的注册码是调用唯一可用于注册mbean MBeanServer.registerMBean(Object object, ObjectName name)的公共方法。这不指定类加载器,因此在JMX注册表中使用bean注册的类加载器为null。

这意味着当你通过浏览器中的JMX控制台调用bean上的方法时,它会回退到调用线程上的类加载器 - 如果你试图做任何涉及的事情就没有用,因为它不会有你的任何课程,因此上面的错误。

Ales向我指出了另一种注册bean的方法,该方法克服了这个问题,该问题在JBoss服务代码中使用。

DynamicMBean mBean = getMBeanFactory().createMBean(this);
MBeanServer mBeanServer = MBeanServerLocator.instance().getmBeanServer();
ObjectName name;
try {
    name = new ObjectName(jmxObjectName);
    mBeanServer.registerMBean(mBean, name);
}
catch (Throwable t) {
    log.error(String.format("Unable to register [%s] with JMX under [%s]:", serviceName, jmxObjectName), t);
}

我现在正在使用

DynamicMBean mBean = getMBeanFactory().createMBean(this);
MBeanServer mBeanServer = MBeanServerLocator.instance().getmBeanServer();
ObjectName name;
try {
    name = new ObjectName(jmxObjectName);

    Map<String, Object> values = new HashMap<String, Object>();
    ClassLoader classLoader = this.getClass().getClassLoader();
    log.info(String.format("Registering to JMX with classLoader [%s]",classLoader.toString()));
    values.put(ServerConstants.CLASSLOADER, classLoader);

    mBeanServer.invoke(
        ObjectNameFactory.create(ServerConstants.MBEAN_REGISTRY), 
        "registerMBean", 
        new Object[] { mBean, name, values }, 
        new String[] { Object.class.getName(), ObjectName.class.getName(), Map.class.getName() }
    );
} catch (Throwable t) {
    log.error(String.format("Unable to register [%s] with JMX under [%s]:", serviceName, jmxObjectName), t);
}

这取自org.jboss.system.ServiceCreator.installPlainMBean(MBeanServer server, ObjectName objectName, ServiceMetaData metaData)。您可以在MbeanResgistry bean本身上调用registerMBean,在这里您可以传递一个类加载器,然后在浏览器中调用bean方法时将其切换到。