MetadataMBeanInfoAssembler does not support JDK dynamic proxies – Eine der ekelhaftesten Spring Exceptions.

Das exportieren von MBeans mit Spring ist kinderleicht und macht Spaß!

Folgende Exception hat mich und auch einige Kollegen (hallo David!:)) kürzlich einige Nerven gekostet.


Caused by: java.lang.IllegalArgumentException: MetadataMBeanInfoAssembler does not support JDK dynamic proxies - export the target beans directly or use CGLIB proxies instead
at org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler.checkManagedBean(MetadataMBeanInfoAssembler.java:105)
at org.springframework.jmx.export.assembler.AbstractMBeanInfoAssembler.getMBeanInfo(AbstractMBeanInfoAssembler.java:63)
at org.springframework.jmx.export.MBeanExporter.getMBeanInfo(MBeanExporter.java:819)
at org.springframework.jmx.export.MBeanExporter.createAndConfigureMBean(MBeanExporter.java:792)

Um dies nachzustellen definieren wir folgenden Spring-Context:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">

<bean id="transactionManager">
<property name="userTransaction" ref="dummyTransaction"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>

<context:mbean-export/>
<context:mbean-server id="mBeanServer"/>
<context:component-scan base-package="de.effective"/>
</beans>

Dieses Service-Interface:


public interface MyService {
public void sagDochMal(String was);
}

Und diese Implementierung:


@Component
@ManagedResource(objectName="effective:name=laberService")
@Transactional
public class MyServiceImpl implements MyService {
@Override
@ManagedOperation()
public void sagDochMal(String was) {
System.out.println("Ich sag " + was);
}
}

Startet man die Testapplikation


/**
* @author martin.dilger
*/
public class SpringApplication {

public static void main(String[] args) throws Exception {

new Thread(new Runnable() {
@Override
public void run() {
ClassPathXmlApplicationContext appCtx = new ClassPathXmlApplicationContext("de/effective/spring-context.xml");

MyService myService = appCtx.getBean(MyService.class);
myService.sagDochMal("Heureka, ich habs!");
while(true)
try {
Thread.sleep(1000);
System.out.println("still running");
} catch (InterruptedException e) {
e.printStackTrace();
}

}
}).start();       ;

}
}

kriegt man direkt eine Exception vor den Latz geknallt:


Exception in thread "Thread-0" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mbeanExporter': Invocation of init method failed; nested exception is org.springframework.jmx.export.UnableToRegisterMBeanException: Unable to register MBean [de.effective.MyServiceImpl@3adec164] with key 'myServiceImpl'; nested exception is org.springframework.jmx.export.MBeanExportException: Could not create ModelMBean for managed resource [de.effective.MyServiceImpl@3adec164] with key 'myServiceImpl'; nested exception is java.lang.IllegalArgumentException: MetadataMBeanInfoAssembler does not support JDK dynamic proxies - export the target beans directly or use CGLIB proxies instead
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1455)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at de.effective.SpringApplication$1.run(SpringApplication.java:17)
at java.lang.Thread.run(Thread.java:722)
Caused by: org.springframework.jmx.export.UnableToRegisterMBeanException: Unable to register MBean [de.effective.MyServiceImpl@3adec164] with key 'myServiceImpl'; nested exception is org.springframework.jmx.export.MBeanExportException: Could not create ModelMBean for managed resource [de.effective.MyServiceImpl@3adec164] with key 'myServiceImpl'; nested exception is java.lang.IllegalArgumentException: MetadataMBeanInfoAssembler does not support JDK dynamic proxies - export the target beans directly or use CGLIB proxies instead
at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:602)
at org.springframework.jmx.export.MBeanExporter.registerBeans(MBeanExporter.java:527)
at org.springframework.jmx.export.MBeanExporter.afterPropertiesSet(MBeanExporter.java:413)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1514)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1452)
... 13 more
Caused by: org.springframework.jmx.export.MBeanExportException: Could not create ModelMBean for managed resource [de.effective.MyServiceImpl@3adec164] with key 'myServiceImpl'; nested exception is java.lang.IllegalArgumentException: MetadataMBeanInfoAssembler does not support JDK dynamic proxies - export the target beans directly or use CGLIB proxies instead
at org.springframework.jmx.export.MBeanExporter.createAndConfigureMBean(MBeanExporter.java:797)
at org.springframework.jmx.export.MBeanExporter.registerBeanInstance(MBeanExporter.java:654)
at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:592)
... 17 more
Caused by: java.lang.IllegalArgumentException: MetadataMBeanInfoAssembler does not support JDK dynamic proxies - export the target beans directly or use CGLIB proxies instead
at org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler.checkManagedBean(MetadataMBeanInfoAssembler.java:105)
at org.springframework.jmx.export.assembler.AbstractMBeanInfoAssembler.getMBeanInfo(AbstractMBeanInfoAssembler.java:63)
at org.springframework.jmx.export.MBeanExporter.getMBeanInfo(MBeanExporter.java:819)
at org.springframework.jmx.export.MBeanExporter.createAndConfigureMBean(MBeanExporter.java:792)
... 19 more

Quizfrage:

Was muss man tun, um die Applikation startbar zu machen und woran liegts?

Die Sourcen gibts übrigens auch auf github: git@github.com:dilgerma/playground.git im Unterverzeichnis spring-riddle.

Die Lösung ist sehr, sehr einfach, aber man muss drauf kommen.

Hier nochmals der spring-context:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">

<bean id="transactionManager">
<property name="userTransaction" ref="dummyTransaction"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>

<context:mbean-export/>
<context:mbean-server id="mBeanServer"/>
<context:component-scan base-package="de.effective"/>
</beans>

Der Trick ist folgender:

Die beiden Direktiven <context:mbean-export/> und
<context:component-scan base-package=“de.effective“/> sind in der falschen Reihenfolge im spring-context deklariert.

Dadurch, dass die Beans am Transaktionsmanagement teilnehmen erzeugt Spring Proxy-Klassen für die Beans. Proxy-Klassen dürfen aber nicht
als MBeans registriert werden (warum genau weiß ich nicht).
Dreht man die Reihenfolge um, funktioniert das Ganze.


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">

<bean id="transactionManager">
<property name="userTransaction" ref="dummyTransaction"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<context:component-scan base-package="de.effective"/>
<context:mbean-export/>
<context:mbean-server id="mBeanServer"/>
</beans>

Die Reihenfolge im Spring-Context spielt also tatsächlich eine Rolle! MBean-Deklarationen sollten immer möglichst weit
unten im Spring-Context platziert werden.

Es gibt haufenweise Einträge mit diesem Problem und mindestens eben so viele Lösungsvorschläge:), beispielsweise hier:

http://forum.springsource.org/showthread.php?14349-My-JMX-beans-no-longer-work-in-RC2

http://nelz.net/2008/10/10/spring-jmx-challenges/


War dieser Blogeintrag für Sie interessant? Evtl. kann ich noch mehr für Sie tun.

Trainings & Know-How aus der Praxis zu

  • Apache Wicket 1.4.x, 1.5.x, 1.6.x
  • GIT – Best Practices, Einsatz, Methoden
  • Spring
  • Java
  • Scrum & Kanban
  • Agiles Arbeiten
Consulting & Softwareentwicklung

  • Requirements Engineering
  • Qualitätssicherung
  • Software-Entwicklung
  • Architektur
  • Scrum & Kanban
Advertisements

2 Gedanken zu „MetadataMBeanInfoAssembler does not support JDK dynamic proxies – Eine der ekelhaftesten Spring Exceptions.

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s