java Spring框架-类加载器的关系

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/554963/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 12:50:36  来源:igfitidea点击:

Spring framework - class loader relationship

javaspringclassloader

提问by

I am having a problem which is probably related to the Spring / class loader relationship.

我遇到了一个问题,这可能与 Spring/类加载器的关系有关。

I will apologise for the verbosity of the question now.

我现在为这个问题的冗长道歉。

I have a number of legacy java applications which were originally written and intended to run within a dedicated JVM. We decided upon examination of the resource usage that efficiencies could be gained by running multiple applications within a single JVM. Within that context I wrote a container manager specifically designed for our environment which is capable of running each application within a container (or sandbox). The basis of this ability to isolate the containers is of course a custom class loader.

我有许多遗留的 Java 应用程序,它们最初是编写并打算在专用 JVM 中运行的。我们在检查资源使用情况后决定通过在单个 JVM 中运行多个应用程序来提高效率。在这种情况下,我编写了一个专门为我们的环境设计的容器管理器,它能够在容器(或沙箱)中运行每个应用程序。这种隔离容器的能力的基础当然是自定义类加载器。

All works well until we came across an application which uses the Spring framework. I have a Spring configuration file with fragments as below.

一切正常,直到我们遇到一个使用 Spring 框架的应用程序。我有一个带有片段的 Spring 配置文件,如下所示。

<bean id="MDDStructurPackager" class="abc.def.mdd.msg.alarm.huawei.MDDPackagerAlarmM2000">
    <property name="logger">
        <ref local="Logger"/>
    </property>
    <property name="realm">
        <value>unpack</value>
    </property>
</bean>

<bean id="Jakarta" class="abc.def.mdd.channel.corba.M2000AlarmChannel">
    <constructor-arg>
        <ref bean="MDDStructurPackager"/>
    </constructor-arg>
    <property name="interactionLayer">
        <ref local="MDDInteractionLayer"/>
    </property>
    <property name="logger">
        <ref local="Logger"/>
    </property>
    <property name="tempFile" value="/opt/app/abcdef/rt_dev/var/cache/dat/Huawei_M2000_Jakarta.dat"/>
    <property name="host" value="M2000Jakarta.ior"/>
    <property name="irpReference" value="clarity"/>
    <property name="name" value="M2000Jakarta"/>
    <property name="realm" value="Jakarta"/>
 <property name="natAddress" value="99.999.99.9" />
</bean>



The following is a fragment from the log file as Spring is instantiating the beans.

以下是 Spring 实例化 bean 时日志文件中的一个片段。

DEBUG [South Agent 1] (DefaultSingletonBeanRegistry.java:162) - Creating shared instance of singleton bean 'MDDStructurPackager'

DEBUG [South Agent 1] (DefaultSingletonBeanRegistry.java:162) - 创建单例 bean 'MDDStructurPackager' 的共享实例

DEBUG [South Agent 1] (AbstractAutowireCapableBeanFactory.java:378) - Creating instance of bean 'MDDStructurPackager'

DEBUG [South Agent 1] (AbstractAutowireCapableBeanFactory.java:378) - 创建 bean 'MDDStructurPackager' 的实例

DEBUG [South Agent 1] (AbstractAutowireCapableBeanFactory.java:453) - Eagerly caching bean 'MDDStructurPackager' to allow for resolving potential circular references

DEBUG [South Agent 1] (AbstractAutowireCapableBeanFactory.java:453) - 急切地缓存 bean 'MDDStructurPackager' 以允许解决潜在的循环引用

DEBUG [South Agent 1] (AbstractBeanFactory.java:213) - Returning cached instance of singleton bean 'Logger'

DEBUG [South Agent 1] (AbstractBeanFactory.java:213) - 返回单例 bean 'Logger' 的缓存实例

DEBUG [South Agent 1] (CachedIntrospectionResults.java:242) - Getting BeanInfo for class [abc.def.mdd.msg.alarm.huawei.MDDPackagerAlarmM2000]

DEBUG [South Agent 1] (CachedIntrospectionResults.java:242) - 获取类 [abc.def.mdd.msg.alarm.huawei.MDDPackagerAlarmM2000] 的 BeanInfo

DEBUG [South Agent 1] (CachedIntrospectionResults.java:258) - Caching PropertyDescriptors for class [abc.def.mdd.msg.alarm.huawei.MDDPackagerAlarmM2000]

DEBUG [South Agent 1] (CachedIntrospectionResults.java:258) - 缓存类 [abc.def.mdd.msg.alarm.huawei.MDDPackagerAlarmM2000] 的 PropertyDescriptors

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - Found bean property 'class' of type [java.lang.Class]

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - 找到 [java.lang.Class] 类型的 bean 属性“class”

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - Found bean property 'colectionDate' of type [java.lang.String]

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - 找到 [java.lang.String] 类型的 bean 属性“colectionDate”

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - Found bean property 'component' of type [abc.def.mdd.msg.MDDComponent]

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - 找到 [abc.def.mdd.msg.MDDComponent] 类型的 bean 属性“组件”

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - Found bean property 'fileType' of type [java.lang.String]

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - 找到 [java.lang.String] 类型的 bean 属性“fileType”

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - Found bean property 'listCommonWords' of type [java.util.ArrayList]

调试 [South Agent 1] (CachedIntrospectionResults.java:267) - 找到 [java.util.ArrayList] 类型的 bean 属性“listCommonWords”

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - Found bean property 'listHeader' of type [java.util.ArrayList]

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - 找到 [java.util.ArrayList] 类型的 bean 属性“listHeader”

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - Found bean property 'logger' of type [abc.def.mdd.logger.Logger]

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - 找到 [abc.def.mdd.logger.Logger] 类型的 bean 属性“logger”

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - Found bean property 'mapDelimiter' of type [java.util.Map]

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - 找到 [java.util.Map] 类型的 bean 属性“mapDelimiter”

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - Found bean property 'mapElement' of type [java.util.Map]

调试 [South Agent 1] (CachedIntrospectionResults.java:267) - 找到 [java.util.Map] 类型的 bean 属性“mapElement”

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - Found bean property 'namePackager' of type [java.lang.String]

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - 找到 [java.lang.String] 类型的 bean 属性“namePackager”

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - Found bean property 'nameSpaceXMLSchema' of type [java.lang.String]

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - 找到 [java.lang.String] 类型的 bean 属性“nameSpaceXMLSchema”

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - Found bean property 'nodeName' of type [java.lang.String]

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - 找到 [java.lang.String] 类型的 bean 属性“nodeName”

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - Found bean property 'packageXMLSchema' of type [java.lang.String]

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - 找到 [java.lang.String] 类型的 bean 属性“packageXMLSchema”

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - Found bean property 'processingLayerListener' of type [abc.def.mdd.channel.ProcessingLayerListener]

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - 找到 [abc.def.mdd.channel.ProcessingLayerListener] 类型的 bean 属性“processingLayerListener”

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - Found bean property 'realm' of type [java.lang.String]

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - 找到 [java.lang.String] 类型的 bean 属性“realm”

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - Found bean property 'statesObject' of type [java.lang.String]

DEBUG [South Agent 1] (CachedIntrospectionResults.java:267) - 找到 [java.lang.String] 类型的 bean 属性“statesObject”

DEBUG [South Agent 1] (AbstractAutowireCapableBeanFactory.java:406) - Finished creating instance of bean 'MDDStructurPackager'

DEBUG [South Agent 1] (AbstractAutowireCapableBeanFactory.java:406) - 完成创建 bean 'MDDStructurPackager' 的实例

DEBUG [South Agent 1] (DefaultSingletonBeanRegistry.java:162) - Creating shared instance of singleton bean 'ListAlarmChannel'

DEBUG [South Agent 1] (DefaultSingletonBeanRegistry.java:162) - 创建单例 bean 'ListAlarmChannel' 的共享实例

DEBUG [South Agent 1] (AbstractAutowireCapableBeanFactory.java:378) - Creating instance of bean 'ListAlarmChannel'

DEBUG [South Agent 1] (AbstractAutowireCapableBeanFactory.java:378) - 创建 bean 'ListAlarmChannel' 的实例

DEBUG [South Agent 1] (AbstractAutowireCapableBeanFactory.java:453) - Eagerly caching bean 'ListAlarmChannel' to allow for resolving potential circular references

DEBUG [South Agent 1] (AbstractAutowireCapableBeanFactory.java:453) - 急切地缓存 bean 'ListAlarmChannel' 以允许解决潜在的循环引用

DEBUG [South Agent 1] (DefaultSingletonBeanRegistry.java:162) - Creating shared instance of singleton bean 'Jakarta'

DEBUG [South Agent 1] (DefaultSingletonBeanRegistry.java:162) - 创建单例 bean 'Jakarta' 的共享实例

DEBUG [South Agent 1] (AbstractAutowireCapableBeanFactory.java:378) - Creating instance of bean 'Jakarta'

DEBUG [South Agent 1] (AbstractAutowireCapableBeanFactory.java:378) - 创建 bean 'Jakarta' 的实例

DEBUG [South Agent 1] (AbstractBeanFactory.java:213) - Returning cached instance of singleton bean 'MDDStructurPackager'

DEBUG [South Agent 1] (AbstractBeanFactory.java:213) - 返回单例 bean 'MDDStructurPackager' 的缓存实例

INFO: CORBA_HUAWEI_M2KJKT_ALARM (23447542): Added "/opt/app/abcdef/rt_dev/lib/logkit-1.2.jar" to the class path.

信息:CORBA_HUAWEI_M2KJKT_ALARM (23447542):在类路径中添加了“/opt/app/abcdef/rt_dev/lib/logkit-1.2.jar”。

INFO: CORBA_HUAWEI_M2KJKT_ALARM (23447542): Added "/opt/app/abcdef/rt_dev/lib/avalon-framework-4.1.5.jar" to the class path.

信息:CORBA_HUAWEI_M2KJKT_ALARM (23447542):在类路径中添加了“/opt/app/abcdef/rt_dev/lib/avalon-framework-4.1.5.jar”。

INFO: CORBA_HUAWEI_M2KJKT_ALARM (23447542): Added "/opt/app/abcdef/rt_dev/lib/concurrent-1.3.2.jar" to the class path.

信息:CORBA_HUAWEI_M2KJKT_ALARM (23447542):在类路径中添加了“/opt/app/abcdef/rt_dev/lib/concurrent-1.3.2.jar”。

INFO: CORBA_HUAWEI_M2KJKT_ALARM (23447542): Added "/opt/app/abcdef/rt_dev/lib/antlr-2.7.2.jar" to the class path.

信息:CORBA_HUAWEI_M2KJKT_ALARM (23447542):在类路径中添加了“/opt/app/abcdef/rt_dev/lib/antlr-2.7.2.jar”。

DEBUG [South Agent 1] (ConstructorResolver.java:195) -
Ignoring constructor [public abc.def.mdd.channel.corba.M2000AlarmChannel(
java.lang.String, int, java.lang.String, java.lang.String, com.citycorp.mdd.msg.MDDComponent ) throws java.lang.Exception ]
of bean 'Jakarta': org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'Jakarta' defined in file [/opt/app/abcdef/rt_dev/etc/HUAWEI_M2KJKT_ALARM.xml]:
Unsatisfied dependency expressed through constructor argument with index 0 of type [java.lang.String]:
Could not convert constructor argument value of type [abc.def.mdd.msg.alarm.huawei.MDDPackagerAlarmM2000] to required type [java.lang.String]:
Failed to convert value of type [abc.def.mdd.msg.alarm.huawei.MDDPackagerAlarmM2000] to required type [java.lang.String];
nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [abc.def.mdd.msg.alarm.huawei.MDDPackagerAlarmM2000] to required type [java.lang.String]:
no matching editors or conversion strategy found

DEBUG [South Agent 1] (ConstructorResolver.java:195) -
忽略构造函数 [public abc.def.mdd.channel.corba.M2000AlarmChannel(
java.lang.String, int, java.lang.String, java.lang.String, com.citycorp.mdd.msg.MDDComponent ) 抛出
bean 'Jakarta' 的java.lang.Exception ] :org.springframework.beans.factory.UnsatisfiedDependencyException:
创建名为 'Jakarta' 的 bean 时出错 [/opt/app/ abcdef/rt_dev/etc/HUAWEI_M2KJKT_ALARM.xml]:
通过构造函数参数表达的不满足的依赖关系,类型为 [java.lang.String] 的索引为 0:
无法将 [abc.def.mdd.msg.alarm.huawei.MDDPackagerAlarmM2000] 类型的构造函数参数值转换为所需类型 [java.lang.String]:
无法转换类型 [abc.def.mdd.msg.alarm ] 的值.huawei.MDDPackagerAlarmM2000] 到所需类型 [java.lang.String];
嵌套异常是 java.lang.IllegalArgumentException:无法将类型 [abc.def.mdd.msg.alarm.huawei.MDDPackagerAlarmM2000] 的值转换为所需类型 [java.lang.String]:
找不到匹配的编辑器或转换策略



The following are the signatures of the constructors for the abc.def.mdd.channel.corba.M2000AlarmChannel class:

以下是 abc.def.mdd.channel.corba.M2000AlarmChannel 类的构造函数的签名:

public M2000AlarmChannel( MDDComponent componenet )

公共 M2000AlarmChannel( MDDComponent 组件)

public M2000AlarmChannel( String host, int port, String username, String password, MDDComponent componenet )

public M2000AlarmChannel(字符串主机,int端口,字符串用户名,字符串密码,MDDComponent组件)

The class abc.def.mdd.msg.alarm.huawei.MDDPackagerAlarmM2000 implements MDDComponent (bean MDDStructurPackager).

abc.def.mdd.msg.alarm.huawei.MDDPackagerAlarmM2000类实现了MDDComponent(bean MDDStructurPackager)。





As you can see, Spring is instantiating some of the beans ie. MDDStructurPackager without problem.

如您所见,Spring 正在实例化一些 bean,即。MDDStructurPackager 没有问题。

The problem is instantiating the 'Jakarta' bean.

问题是实例化“Jakarta”bean。

The implications of the lines:

线的含义:

Error creating bean with name 'Jakarta' defined in file [/opt/app/abcdef/rt_dev/etc/HUAWEI_M2KJKT_ALARM.xml]:

创建名为“Jakarta”的 bean 在文件 [/opt/app/abcdef/rt_dev/etc/HUAWEI_M2KJKT_ALARM.xml] 中定义时出错:

Unsatisfied dependency expressed through constructor argument with index 0 of type [java.lang.String]:

通过构造函数参数表示不满足的依赖关系,类型为 [java.lang.String] 的索引为 0:

Could not convert constructor argument value of type [abc.def.mdd.msg.alarm.huawei.MDDPackagerAlarmM2000] to required type [java.lang.String]:

无法将类型 [abc.def.mdd.msg.alarm.huawei.MDDPackagerAlarmM2000] 的构造函数参数值转换为所需类型 [java.lang.String]:

are not clear. I am not sure the reasons for the type confusion when attempting to determine the appropriate constructor. It is possible that the problem is associated with the loading of the interface MDDComponent. If it was loaded twice, by different class loaders which are not related in the class loader hierarchy you could imagine problems associated with determining the correct constructor.

不清楚。在尝试确定适当的构造函数时,我不确定类型混淆的原因。该问题可能与接口 MDDComponent 的加载有关。如果它被在类加载器层次结构中不相关的不同类加载器加载两次,您可以想象与确定正确的构造函数相关的问题。

Any ideas gratefully received, I am grasping at straws.

感谢收到任何想法,我正在抓住稻草。

Thanks Bryan

谢谢布莱恩

回答by matt b

From the error message, it sounds like Spring is attempting to instantiate the object with this constructor:

从错误消息中,听起来 Spring 正在尝试使用此构造函数实例化对象:

public M2000AlarmChannel(String host, int port, String username, String password, MDDComponent componenet)

Looks like Spring is confused on which constructor to use, possibly because both constructors have a MDDComponentparameter (in a way, both constructors have this as their last parameter, I'm curious if that has something to do with the logic that Spring uses in determining which constructor to use. Anyway...).

看起来 Spring 对使用哪个构造函数感到困惑,可能是因为两个构造函数都有一个MDDComponent参数(在某种程度上,两个构造函数都将 this 作为他们的最后一个参数,我很好奇这是否与 Spring 用于确定的逻辑有关使用哪个构造函数。无论如何......)。

According to the Spring manual, there are parameters you can add to the <constructor-arg>element to help the container resolve which constructor to use:

根据Spring 手册,您可以向<constructor-arg>元素添加参数以帮助容器解析要使用的构造函数:

You can add "type":

您可以添加“类型”:

<bean id="exampleBean" class="examples.ExampleBean">
  <constructor-arg type="int" value="7500000"/>
  <constructor-arg type="java.lang.String" value="42"/>
</bean>

or you can add an index:

或者您可以添加索引:

<bean id="exampleBean" class="examples.ExampleBean">
  <constructor-arg index="0" value="7500000"/>
  <constructor-arg index="1" value="42"/>
</bean>

(You can probably specify both, if you really want to)

(如果你真的想,你可以指定两者)

Adding one or both of these should help Spring resolve which constructor to use.

添加其中一个或两个应该有助于 Spring 解决要使用的构造函数。

As a corollary, if this doesn't help, can you simply change the XML definition to pass in the parameters required for the other constructor, the one Spring is attempting to use?

作为推论,如果这没有帮助,您是否可以简单地更改 XML 定义以传递另一个构造函数所需的参数,即 Spring 试图使用的构造函数?

BTW, it might make your question a lot more readable to use the quote tags within WMD.

顺便说一句,在 WMD 中使用引号可能会使您的问题更具可读性。

回答by duffymo

Actually, I think it is. The first constructor argument you pass to the Jakarta object is of type abc.def.mdd.msg.alarm.huawei.MDDPackagerAlarmM2000, but the ctor wants a String. Make the types match properly.

事实上,我认为是的。您传递给 Jakarta 对象的第一个构造函数参数的类型是 abc.def.mdd.msg.alarm.huawei.MDDPackagerAlarmM2000,但构造函数需要一个字符串。使类型正确匹配。

It reads as a straight-forward message. What am I missing?

它读起来是一条直截了当的消息。我错过了什么?

I'll assume from the package structure that those are your classes. True?

我将从包结构中假设这些是您的类。真的?

回答by oxbow_lakes

Are you in control of the AlarmChannelclass? If so, can you roll a new version which has a print statement in the constructor (also you could use try-catchwithin a staticinitializer to get a stack trace from where the class is being initialized from)?

你能控制AlarmChannel班级吗?如果是这样,您是否可以推出在构造函数中具有打印语句的新版本(您也可以try-catchstatic初始化程序中使用以从初始化类的位置获取堆栈跟踪)?

That way, you might get some idea of whether there are duplicate classes involved

这样,您可能会了解是否涉及重复的类

Also in the Spring config file you could cause the ClassLoaderto be printed out using a MethodInvokingFactoryBean- this might also shed some light on the matter?

同样在 Spring 配置文件中,您可能会导致ClassLoader使用 a 打印出来MethodInvokingFactoryBean- 这也可能对此事有所了解?