【问题标题】:idref and ref difference in SpringSpring中的idref和ref区别
【发布时间】:2015-06-29 12:37:13
【问题描述】:

我只使用文档来学习 Spring。当 idref 出现时,我感到很困惑。我的理解是为了在 bean 中定义一个属性,我们需要使用带有“name”和“value”属性的“property”标签。 “name”应该是我们为 POJO 中的属性指定的名称,“value”可以是任何原始数据类型。如果我们需要将它映射到一个单独的 bean,那么我们应该使用“ref”属性。这个“ref”属性必须持有我们引用的bean的“id”。

现在根据文档,我们有一个 sn-p,它显示引用另一个 bean 的“值”属性。文档建议改用“idref”。当我实时尝试时,我得到以下异常。

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'theClientBean' defined in class path resource [ConstructorInjectionDemo.xml]: Initialization of bean failed; nested exception is org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'java.lang.String' to required type 'com.javagrasp.dependencies.TheTargetBean' for property 'targetName'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [com.javagrasp.dependencies.TheTargetBean] for property 'targetName': no matching editors or conversion strategy found

豆定义:

<bean id="theTargetBean" class="com.javagrasp.dependencies.TheTargetBean"/>

<bean id="theClientBean" class="com.javagrasp.dependencies.TheClientBean">
<property name="targetName">
    <idref bean="theTargetBean" />
</property>
</bean>

课程详情:

ClientBean 类:

public class TheClientBean  {

private TheTargetBean targetName;

public void setTargetName(TheTargetBean targetName) {
    this.targetName = targetName;
}
}

TargetBean 类:

package com.javagrasp.dependencies;
public class TheTargetBean {

}

还有:

以下行是什么意思,我是否需要始终以某种约定命名属性?

17:44:22.270 [main] DEBUG org.springframework.beans.BeanUtils - No property editor [com.javagrasp.dependencies.TheTargetBeanEditor] found for type com.javagrasp.dependencies.TheTargetBean according to 'Editor' suffix convention

【问题讨论】:

标签: spring spring-4


【解决方案1】:

"idref" 与 "ref" 完全不同。很容易混淆。我认为最好用一个例子来解释这一点,而不是一行一行的文字。

考虑任何两个只有字符串作为属性的类{ NOT REFERENCES}

package com.imran.beanwrapper;

public class IdrefOne {

String first;

public String getFirst() {
    return first;
}

public void setFirst(String first) {
    this.first = first;
}

}

package com.imran.beanwrapper;

public class IdrefTwo {

String second;

public String getSecond() {
    return second;
}

public void setSecond(String second) {
    this.second = second;
}

}

xml:

<bean id="one" 
class="com.imran.beanwrapper.IdrefOne">
<property name="first" value="hai first"/>
</bean>

<bean id="two" 
class="com.imran.beanwrapper.IdrefTwo">

<property name="second">
<idref bean="one"/>
</property>
</bean>

</beans>

Main class : 
ApplicationContext context=new 

ClassPathXmlApplicationContext
("wrapperTest.xml");
    
IdrefOne 
one=context.getBean("one",IdrefOne.class);
    
IdrefTwo 
two=context.getBean("two",IdrefTwo.class);
    
System.out.println(one.getFirst());
System.out.println(two.getSecond());

输出:

先喂

一个


你注意到 System.out.println(two.getSecond()) 的输出了吗?

一个
等于第一个bean的“id值”,即com.imran.beanwrapper.IdrefOne(不等于bean本身或bean依赖的字符串值。避免混淆)

请注意,两个类(IdrefOne、IdrefTwo)必须将字符串作为依赖项,而不是将对象子类作为依赖项,即引用类

如果在上面的代码中,如果我们的 pojo 类有 Object 子类作为依赖项,上面的代码最终会出现异常

原因:java.lang.IllegalStateException:无法将类型“java.lang.String”的值转换为属性“”所需的类型“com.imran.beanwrapper.IdrefOne”:找不到匹配的编辑器或转换策略

因此,我们可以总结上述代码设置,其中字符串作为 pojo 类 IdrefOne 、 IdrefTwo 的依赖项。代码

<property name="second">
<idref bean="one"/>
</property>

产生与以下代码相同的结果

<property name="second" value="one">
</property>

使用第一个 XML sn-p 使用 'idref' ,如果在容器中找不到名为“one”的 bean,则会引发异常。使用第二个 xml sn-p ,您可以根据需要为“值”属性提供任何字符串值。 所以问题是为什么不使用通常使用的常规“值”并避免所有这些混淆?

答案在 spring 文档中: https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/beans.html#beans-idref-element

第一种形式比第二种形式更可取,因为使用“idref”标签允许容器在部署时验证引用的命名 bean 确实存在。在第二个变体中,不对传递给客户端 bean 的 targetName 属性的值执行验证。只有在实际实例化客户端 bean 时才会发现拼写错误(很可能会导致致命结果)。如果客户端 bean 是原型 bean,那么这个错字和导致的异常可能只有在容器部署很久之后才会被发现。

'idref' 元素带来价值的常见地方(至少在 Spring 2.0 之前的版本中)是在 ProxyFactoryBean bean 定义中的 AOP 拦截器配置中。在指定拦截器名称时使用 'idref' 元素可防止您拼错拦截器 ID。

【讨论】:

    【解决方案2】:

    由于 IdRef 传递了 bean 的名称,因此您的 bean 应该是这样的

    public class TheClientBean  {
    
        private String targetName;
    
       //Name of the Bean is passed here.
        public void setTargetName(String targetName) {
          this.targetName = targetName;
       }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-13
      • 1970-01-01
      • 2020-03-19
      • 1970-01-01
      • 1970-01-01
      • 2019-10-26
      • 1970-01-01
      • 2021-03-30
      相关资源
      最近更新 更多