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.

[code language=”java”]

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)

[/code]

Um dies nachzustellen definieren wir folgenden Spring-Context:

[code language=”xml”]

<?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>

[/code]

Dieses Service-Interface:

[code language=”java”]

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

[/code]

Und diese Implementierung:

[code language=”java”]

@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);
}
}

[/code]

Startet man die Testapplikation

[code language=”java”]

/**
* @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();       ;

}
}

[/code]

kriegt man direkt eine Exception vor den Latz geknallt:

[code language=”java”]

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

[/code]

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:

[code language=”xml”]

<?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>

[/code]

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.

[code language=”xml”]

<?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>

[/code]

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

Effective Trainings & Consulting - Martin Dilger



Hat Ihnen dieser Blog-Eintrag gefallen? Ich stelle in diesem Blog Informationen über Tools, Frameworks und Werkzeuge zur Verfügung, die mich produktiver machen. Vielleicht kann ich auch Ihnen helfen, produktiver zu werden.


Ich unterstütze Sie als freier Mitarbeiter bei der Entwicklung von Software-Projekten, Agiler Arbeit sowie Schulungen / Fortbildungen.


Jeden Tag ein bisschen produktiver - ab heute