Lavish Kothari opened SPR-17592 and commented
I'm having a bean that is
- annotated with
ManagedResource
- lazily initialized
- implements
SelfNaming
I'm exporting it using spring's AnnotationMBeanExporter.
All this works good when I'm using spring version 4.3.16.RELEASE, but when I upgraded my spring version to 5.0.5.RELEASE or 5.1.3.RELEASE this code started giving me IllegalStateException.
My Bean definition and the spring's context.xml looks like this:
SampleBean.java
package com.jmx.trial.dummybeans;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.jmx.export.naming.SelfNaming;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
@ManagedResource
public class SampleBean implements SelfNaming {
@Override
public ObjectName getObjectName() throws MalformedObjectNameException {
return new ObjectName("com.jmx.trial:name=sampleBean");
}
}
application-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="server" class="org.springframework.jmx.support.MBeanServerFactoryBean"/>
<bean id="exporter" class="org.springframework.jmx.export.annotation.AnnotationMBeanExporter">
<property name="server" ref="server"/>
</bean>
<bean id="sampleBean" class="com.jmx.trial.dummybeans.SampleBean" lazy-init="true"/>
</beans>
I understand that an extra validation was added here, and this is causing IllegalStateException but I'm not completely sure why that was added.
The stack-trace looks like this:
org.springframework.jmx.export.UnableToRegisterMBeanException: Unable to register MBean [sampleBean] with key 'sampleBean'; nested exception is java.lang.IllegalStateException: Not initialized
at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:625)
at org.springframework.jmx.export.MBeanExporter.lambda$registerBeans$2(MBeanExporter.java:551)
at java.base/java.util.HashMap.forEach(HashMap.java:1336)
at org.springframework.jmx.export.MBeanExporter.registerBeans(MBeanExporter.java:551)
at org.springframework.jmx.export.MBeanExporter.afterSingletonsInstantiated(MBeanExporter.java:434)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:863)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:863)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:144)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:85)
at com.jmx.trial.MBeanExporterTest.testBeanExportedWithXml(MBeanExporterTest.java:79)
at com.jmx.trial.MBeanExporterTest.testForLazyAutoDetectWithSelfNaming(MBeanExporterTest.java:44)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: java.lang.IllegalStateException: Not initialized
at org.springframework.util.Assert.state(Assert.java:73)
at org.springframework.jmx.export.MBeanExporter$NotificationPublisherAwareLazyTargetSource.postProcessTargetObject(MBeanExporter.java:1115)
at org.springframework.aop.target.LazyInitTargetSource.getTarget(LazyInitTargetSource.java:72)
at org.springframework.jmx.export.MBeanExporter$NotificationPublisherAwareLazyTargetSource.getTarget(MBeanExporter.java:1103)
at org.springframework.aop.framework.CglibAopProxy$DynamicUnadvisedInterceptor.intercept(CglibAopProxy.java:475)
at com.jmx.trial.dummybeans.SampleBean$$EnhancerBySpringCGLIB$$9cd1c95b.getObjectName(<generated>)
at org.springframework.jmx.export.MBeanExporter.getObjectName(MBeanExporter.java:752)
at org.springframework.jmx.export.MBeanExporter.registerLazyInit(MBeanExporter.java:726)
at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:596)
... 33 more
My experiments:
- When I don't lazily initialize the
SampleBean, I don't get this IllegalStateException.
- When I annotate SampleBean with
ManagedResource(objectName = "com.jmx.trial:name=sampleBean") and make SampleBean not implement SelfNaming interface, again I don't get IllegalStateException
- When I debug this and place a lot of breakpoints in
MBeanExporter and CGLibAopProxy I don't get this exception. (This is specifically interesting that in debug-mode the tests run successfully but in normal run mode the tests fails.)
Though not very sure, but I think implementing SelfNaming interface is not a very good idea as the javadocs of SelfNaming interface says that:
This interface is mainly intended for internal usage.
I'm not sure if it is the problem with using SelfNaming interface or I'm doing something fundamentally wrong. Can you please explain this behavior and point me to the fundamentals that I'm missing.
PS: some of my findings: (might be unrelated) From here I found this caution point:
Do not use interface-based AOP proxies in combination with autodetection of JMX annotations in your bean classes.
I don't completely understand this, but is this the rule that I'm violating?
I feel that the Assert.state that is getting called in postProcessTargetObject should be moved into the method injectNotificationPublisherIfNecessary and should be called only if managedResource instanceof NotificationPublisherAware is true.
Affects: 5.0.5, 5.1.3
Reference URL: https://stackoverflow.com/questions/53711613/exporting-a-lazily-initialized-bean-which-implements-selfnaming-and-is-annotate
Attachments:
Issue Links:
Referenced from: commits e95c1b3, 2c98c1b
Backported to: 5.0.12
Lavish Kothari opened SPR-17592 and commented
I'm having a bean that is
ManagedResourceSelfNamingI'm exporting it using spring's
AnnotationMBeanExporter.All this works good when I'm using spring version
4.3.16.RELEASE, but when I upgraded my spring version to5.0.5.RELEASEor5.1.3.RELEASEthis code started giving meIllegalStateException.My Bean definition and the spring's context.xml looks like this:
SampleBean.java
application-context.xml
I understand that an extra validation was added here, and this is causing
IllegalStateExceptionbut I'm not completely sure why that was added.The stack-trace looks like this:
My experiments:
SampleBean, I don't get thisIllegalStateException.ManagedResource(objectName = "com.jmx.trial:name=sampleBean")and makeSampleBeannot implementSelfNaminginterface, again I don't getIllegalStateExceptionMBeanExporterandCGLibAopProxyI don't get this exception. (This is specifically interesting that in debug-mode the tests run successfully but in normal run mode the tests fails.)Though not very sure, but I think implementing
SelfNaminginterface is not a very good idea as the javadocs ofSelfNaminginterface says that:I'm not sure if it is the problem with using
SelfNaminginterface or I'm doing something fundamentally wrong. Can you please explain this behavior and point me to the fundamentals that I'm missing.PS: some of my findings: (might be unrelated) From here I found this caution point:
I don't completely understand this, but is this the rule that I'm violating?
I feel that the
Assert.statethat is getting called inpostProcessTargetObjectshould be moved into the methodinjectNotificationPublisherIfNecessaryand should be called only ifmanagedResource instanceof NotificationPublisherAwareistrue.Affects: 5.0.5, 5.1.3
Reference URL: https://stackoverflow.com/questions/53711613/exporting-a-lazily-initialized-bean-which-implements-selfnaming-and-is-annotate
Attachments:
Issue Links:
Referenced from: commits e95c1b3, 2c98c1b
Backported to: 5.0.12