【问题标题】:Exporting a lazily initialized bean (which implements SelfNaming and is annotated with ManagedResource annotation) gives IllegalStateException导出一个延迟初始化的 bean(实现 SelfNaming 并使用 ManagedResource 注释进行注释)给出 IllegalStateException
【发布时间】:2018-12-10 18:31:04
【问题描述】:

我的豆子是

  • 注解ManagedResource
  • 延迟初始化
  • 实现SelfNaming

我正在使用 spring 的AnnotationMBeanExporter 导出它。

当我使用 spring 版本 4.3.16.RELEASE 时,这一切都很好,但是当我将 spring 版本升级到 5.0.5.RELEASE 或 5.1.3.RELEASE 时,这个代码开始给我IllegalStateException。

我的 Bean 定义和 spring 的 context.xml 看起来像这样:

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

应用程序上下文.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>

我知道添加了额外的验证 here,这导致了 IllegalStateException,但我不完全确定为什么要添加。

堆栈跟踪如下所示:

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

我的实验:

  • 当我不懒惰地初始化sampleBean 时,我没有得到这个IllegalStateException。
  • 当我用ManagedResource(objectName = "com.jmx.trial:name=sampleBean") 注释SampleBean 并使SampleBean 不 实现SelfNaming 接口时,我又没有得到IllegalStateException

虽然不太确定,但我认为实现SelfNaming 接口并不是一个好主意,因为SelfNaming 接口的javadocs 说:

此接口主要供内部使用。

我不确定是使用SelfNaming 接口的问题还是我做错了什么。您能否解释一下这种行为并指出我所缺少的基础知识。

PS:我的一些发现:(可能无关) 从here我发现了这个注意点:

不要将基于接口的 AOP 代理与 bean 类中 JMX 注释的自动检测结合使用。

我不完全明白这一点,但这是我违反的规则吗?

【问题讨论】:

    标签: java spring jmx lazy-initialization spring-jmx


    【解决方案1】:

    这可能是一个错误; injectNotificationPublisherIfNecessary 只有在你的类也实现了NotificationPublisherAware 时才会采取任何行动。

    这将是无效的,因为我们还没有 objectName,因为 bean 是惰性的,这将违反 ModelMBeanNotificationPublisher 的合同。

    我不知道如果资源没有实现发布者感知接口,postProcessTargetObject 是否可以忽略断言,或者发布者注入是否也需要延迟进行。我不太了解内部结构。

    我建议你打开一个SPRJIRA issue,这样 Spring 团队可以看看并给你一个明确的答案。

    【讨论】:

    • 感谢您的快速回答。我提出了一个 Jira 问题。
    • 这是一个错误。修复将从 5.0.12 5.1.4 SPR-17592 开始提供
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-08
    • 2017-08-09
    相关资源
    最近更新 更多