导出延迟初始化的 bean(实现 SelfNaming 并使用 ManagedResource 注释进行注释)给出 IllegalStateException
Exporting a lazily initialized bean (which implements SelfNaming and is annotated with ManagedResource annotation) gives IllegalStateException
我有一个豆子
- 注释为
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");
}
}
应用-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>
我知道添加了额外的验证 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(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.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.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access[=12=]0(ParentRunner.java:58)
at org.junit.runners.ParentRunner.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$cd1c95b.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 说:
This interface is mainly intended for internal usage.
我不确定这是使用 SelfNaming
界面的问题还是我做的根本错误。您能否解释一下这种行为并指出我所缺少的基本原理。
PS:我的一些发现:(可能无关)
从 here 我发现了这个警告点:
Do not use interface-based AOP proxies in combination with autodetection of JMX annotations in your bean classes.
我不是很明白,但这是我违反的规则吗?
这可能是一个错误; injectNotificationPublisherIfNecessary
仅当您的 class 也实现了 NotificationPublisherAware
.
时才采取任何行动
这将是无效的,因为我们没有 objectName
,但是,因为 bean 是惰性的,这会违反 ModelMBeanNotificationPublisher
.
的约定
我不知道如果资源没有实现发布者感知接口,postProcessTargetObject
是否可以忽略断言,或者发布者注入是否也需要延迟进行。我不太了解内部结构。
我建议你打开一个 SPR
JIRA issue 以便 Spring 团队可以查看并给你一个明确的答案。
我有一个豆子
- 注释为
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");
}
}
应用-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>
我知道添加了额外的验证 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(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.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.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access[=12=]0(ParentRunner.java:58)
at org.junit.runners.ParentRunner.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$cd1c95b.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 说:
This interface is mainly intended for internal usage.
我不确定这是使用 SelfNaming
界面的问题还是我做的根本错误。您能否解释一下这种行为并指出我所缺少的基本原理。
PS:我的一些发现:(可能无关) 从 here 我发现了这个警告点:
Do not use interface-based AOP proxies in combination with autodetection of JMX annotations in your bean classes.
我不是很明白,但这是我违反的规则吗?
这可能是一个错误; injectNotificationPublisherIfNecessary
仅当您的 class 也实现了 NotificationPublisherAware
.
这将是无效的,因为我们没有 objectName
,但是,因为 bean 是惰性的,这会违反 ModelMBeanNotificationPublisher
.
我不知道如果资源没有实现发布者感知接口,postProcessTargetObject
是否可以忽略断言,或者发布者注入是否也需要延迟进行。我不太了解内部结构。
我建议你打开一个 SPR
JIRA issue 以便 Spring 团队可以查看并给你一个明确的答案。