Skip to content

Exporting a lazily initialized bean (which implements SelfNaming and is annotated with ManagedResource annotation) gives IllegalStateException [SPR-17592] #22124

Closed
@spring-projects-issues

Description

@spring-projects-issues

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

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)status: backportedAn issue that has been backported to maintenance branchestype: regressionA bug that is also a regression

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions