zoukankan      html  css  js  c++  java
  • Spring-Context之六:基于Setter方法进行依赖注入

    上文讲了基于构造器进行依赖注入,这里讲解基于Setter方法进行注入。在Java世界中有个约定(Convention),那就是属性的设置和获取的方法名一般是:set+属性名(参数)及get+属性名()的方式。boolean类型稍有不同,可以使用is+属性名()方式来获取。

    以下是一个示例。

    MessageHandler.java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    public class MessageHandler {
    
        private MessageService messageService;
    
        public MessageService getMessageService() {
            return messageService;
        }
    
        public void setMessageService(MessageService messageService) {
            this.messageService = messageService;
        }
    
        public String handle() {
            return messageService.sendService();
        }
    }
    

    使用Setter方法注入如下所示。

    1
    2
    3
    4
    
    <bean id="messageService" class="huangbowen.net.DependecyInjection.ConstructorInjection.SimpleMessageService"/>
        <bean id="messageHandler" class="huangbowen.net.DependecyInjection.SetterInjection.MessageHandler">
            <property name="messageService" ref="messageService"/>
        </bean>
    

    如果property的name为messageService,那么必须在类中有个叫做setMessageService的方法,这样才能完成注入。如果将MessageHandler.java中的setMessageService方法改为setMessageService1,那么注入就会失败,失败message如下所示。

    1
    2
    3
    4
    5
    6
    7
    
    ...
    java.lang.IllegalStateException: Failed to load ApplicationContext
    
    ...
    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'messageHandler' defined in class path resource [spring-context.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'messageService' of bean class [huangbowen.net.DependecyInjection.SetterInjection.MessageHandler]: Bean property 'messageService' is not writable or has an invalid setter method. Did you mean 'messageService1'?
    
    ...
    

    当然可以同时使用构造器注入和setter方法注入。

    Person.java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    public class Person {
    
        private String name;
    
        public Person(String name) {
            this.name = name;
        }
    
        private int age;
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    }
    

    bean定义如下:

    1
    2
    3
    4
    
        <bean id="person" class="huangbowen.net.DependecyInjection.SetterInjection.Person">
            <constructor-arg value="Tom"/>
            <property name="age" value="20"/>
        </bean>
    

    要实现一个bean,即可以使用构造器注入,也可以使用setter注入,甚至可以在一个bean中综合使用这两种方式。那么在真正开发中应该作何取舍那?一般来说,使用构造器注入的依赖必须是强制的依赖,而使用setter注入的依赖则是可选的依赖。使用构造器注入生成的对象是完全初始化了的,用户可以直接拿来用,但是相比于setter方法而言用户也就失去了定制化的能力。如果你发现构造器参数过多,那么很可能说明该类承担的职责过多,应该从设计解耦的角度对类的职责进行拆分。使用setter注入的对象好处是,用户可以按需重新注入新的属性。

    另外在进行依赖注入时,可以将某些属性抽出来成为一个元素,或者将元素内联成为一个属性。比如ref这个属性。

    1
    2
    3
    
        <bean id="messageHandler" class="huangbowen.net.DependecyInjection.SetterInjection.MessageHandler">
            <property name="messageService" ref="messageService" />
        </bean>
    

    它与以下xml配置完全等价。

    1
    2
    3
    4
    5
    
     <bean id="messageHandler" class="huangbowen.net.DependecyInjection.SetterInjection.MessageHandler">
            <property name="messageService">
                <ref bean="messageService"/>
            </property>
        </bean>
    

    value属性也可以独立为元素。

    1
    2
    3
    4
    
        <bean id="person" class="huangbowen.net.DependecyInjection.SetterInjection.Person">
            <constructor-arg value="Tom"/>
            <property name="age" value="20"/>
        </bean>
    

    其等价于:

    1
    2
    3
    4
    5
    6
    
        <bean id="person" class="huangbowen.net.DependecyInjection.SetterInjection.Person">
            <constructor-arg value="Tom"/>
            <property name="age">
                <value>20</value>
            </property>
        </bean>
    

    也可以显式指定value的类型。

    1
    2
    3
    4
    5
    6
    
        <bean id="person" class="huangbowen.net.DependecyInjection.SetterInjection.Person">
            <constructor-arg value="Tom"/>
            <property name="age">
                <value type="int">20</value>
            </property>
        </bean>
    

    比如有一个属性是个boolean值,如果想将其注入为true的话,不指定具体类型的话,Spring可能会将其作为字符串true对待。当然Spring会尝试将传入的字符串转换为setter方法希望的类型,但这种自动转换有时候并不是你期望的,这种情况下你就需要显式指定其类型。

    本例中的源码请在我的GitHub上自行下载。

  • 相关阅读:
    numpy百题冲关,pandas百题冲关
    mapreduce过程以及相关类总结
    mapreduce,数据结构和类型介绍
    精确度、召回率、混淆矩阵的关系
    小程序点击图片放大效果 单张图片 多张图片
    小程序动态添加class及调接口传递多个参数
    小程序for循环嵌套
    小程序富文本转换
    jquery函数加载及生成随机数
    微信小程序 swiper 显示图片计数 当前/总数
  • 原文地址:https://www.cnblogs.com/huang0925/p/3606382.html
Copyright © 2011-2022 走看看