spring依赖注入的方式

摘要

Spring 为何如此流行?我们用 Spring 的原因是什么?想想你会发现原来 Spring 解决了一个非常关键的问题:他可以让你把对象之间的依赖关系转而用配置文件来管理,也就是他的依赖注入机制。
依赖注入(dependency injection)的过程指类被实例化后,由容器负责将它的依赖(一起工作的其他类)准备好,提供给被实例化的bean使用。本节学习笔记主要关于两种常用的的依赖注入的方式:基于构造函数参数和基于属性setter方法注入,及让开发更轻松的自动装配技术(Autowired)说明。

1 基于构造函数参数注入

相似的注入方法是用定义静态工厂方法创建对象,将依赖作为工厂方法的参数。

优点是清楚的告诉调用者使用对象时必须注入的依赖,实例化后可得到完全可用的实例。适用于注入必须存在的依赖对象。

// 类定义
public class SimpleMovieLister {
// SimpleMovieLister类依赖了movieFinder对象
private MovieFinder movieFinder;

// 带参数的构造函数,通过它注入movieFinder
public SimpleMovieLister(MovieFinder movieFinder) {
    this.movieFinder = movieFinder;
}

// 业务代码使用movieFinder

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

对应的配置代码

<beans>
    <bean id="simpleMovieLister " class="x.y.SimpleMovieLister ">
        <constructor-arg ref="movieFinder"/>
    </bean>
&lt;bean id="movieFinder" class="x.y.MovieFinder "/&gt;

</beans>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

1.1 多个构造函数参数

如果构造函数参数有多个,需要避免解析参数时发生歧义。

  • 当多个参数都是引用类,且互相间无继承关系,则构造函数通过参数类型就可以区分不同参数,不需要给constructor-arg加其他属性;
  • 当参数中有简单类型(非引用类型)如int,构造函数无法通过类型区分,如下所示类
//java类
package examples;

public class ExampleBean {
private int years;
private String ultimateAnswer;

public ExampleBean(int years, String ultimateAnswer) {
    this.years = years;
    this.ultimateAnswer = ultimateAnswer;
}

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

方法1 通过指定constructor-arg标签的type属性区分

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

 
 
  • 1
  • 2
  • 3
  • 4

方法2 如果构造函数多个参数存在类型相同,则可以通过index属性代表构造函数签名中参数顺序(index从0开始)

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

 
 
  • 1
  • 2
  • 3
  • 4

方法3 构造函数定义时用@ConstructorProperties注解给参数命名,在定义bean时可以指定constructor-arg标签的name属性

package examples;

public class ExampleBean {

// 省略属性定义

@ConstructorProperties({"years", "ultimateAnswer"})
public ExampleBean(int years, String ultimateAnswer) {
    this.years = years;
    this.ultimateAnswer = ultimateAnswer;
}

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg name="years" value="7500000"/>
    <constructor-arg name="ultimateAnswer" value="42"/>
</bean>

 
 
  • 1
  • 2
  • 3
  • 4

1.2 循环依赖问题(circle dependencies)

使用构造函数参数注入依赖,需要注意避免循环依赖问题。

当A对象的构造函数里依赖B对象,且B同时在构造函数里依赖A,就出现循环依赖,因为A和B都在等对方先创建

Spring容器启动时检测bean之间如果存在循环依赖会报BeanCurrentlyInCreationException
解决循环依赖的方法是,改用基于属性setter方法注入依赖,下面我们来一起学习这种依赖注入方式。

2 基于属性setter方法注入

基于Setter方法的依赖注入是由Spring容器在调用类的无参构造函数后调用属性的setter方法。它提供了运行时再次注入的机会,适用于选择依赖的对象。

// 在1中出现的类,这次使用基于属性Setter方法注入方式定义
public class SimpleMovieLister {
private MovieFinder movieFinder;

public void setMovieFinder(MovieFinder movieFinder) {
    this.movieFinder = movieFinder;
}

//…
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

对应bean配置

<beans>
    <bean id="simpleMovieLister " class="x.y.SimpleMovieLister ">
        <property name="movieFinder">
        	<ref bean="movieFinder"/>
    	</property>
    </bean>
&lt;bean id="movieFinder" class="x.y.MovieFinder "/&gt;

</beans>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

上面配置中,property标签就是告诉Spring容器实例化MovieFinder对象并通过setMovieFinder方法给SimpleMovieLister对象注入依赖

3 自动装配(Autowired)

开启自动装配后,Spring 会自动从ApplicatonContext中寻找要依赖的bean并完成装配。

如何开启自动装配

通过配置文件bean标签的autowired属性开启自动装配并指定自动装配类型

4种自动装配模式

  • autowired = “no”
    默认设置,代表不需要装配
  • autowired=“byName”
    按属性name匹配,Spring检查容器中与属性有相同名称的bean
  • autowired=“byType”
    按属性类型匹配, Spring检查容器中与属性规定的类型相同的bean,如果存在多个抛出异常
  • autowired=“constructor”
    按构造函数参数匹配,Spring检查容器中与构造函数参数类型相同的bean,如果不存在唯一一个则抛出异常

优点

1,在项目中统一使用自动装配可以大量减少通过属性Setter方法或构造函数参数注入依赖的配置
2,对象定义改变时自动装配产生的配置会自动随之更新

局限性

1, 如果同时定义了基于构造函数参数和属性Setter方法的依赖,自动装配会被覆盖而无法生效
2, 不能用于注入基本数据类型,String类型和Class类型,及它们的Array
3, 不如显示的指定依赖准确,通过属性和构造函数装配可以使自己对对象结构更清晰

参考资料

1, Spring Core Technologies

                                </div>
            <link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-60ecaf1f42.css" rel="stylesheet">
                                            <div class="more-toolbox">
            <div class="left-toolbox">
                <ul class="toolbox-list">
                    
                    <li class="tool-item tool-active is-like "><a href="javascript:;"><svg class="icon" aria-hidden="true">
                        <use xlink:href="#csdnc-thumbsup"></use>
                    </svg><span class="name">点赞</span>
                    <span class="count"></span>
                    </a></li>
                    <li class="tool-item tool-active is-collection "><a href="javascript:;" data-report-click="{&quot;mod&quot;:&quot;popu_824&quot;}"><svg class="icon" aria-hidden="true">
                        <use xlink:href="#icon-csdnc-Collection-G"></use>
                    </svg><span class="name">收藏</span></a></li>
                    <li class="tool-item tool-active is-share"><a href="javascript:;" data-report-click="{&quot;mod&quot;:&quot;1582594662_002&quot;}"><svg class="icon" aria-hidden="true">
                        <use xlink:href="#icon-csdnc-fenxiang"></use>
                    </svg>分享</a></li>
                    <!--打赏开始-->
                                            <!--打赏结束-->
                                            <li class="tool-item tool-more">
                        <a>
                        <svg t="1575545411852" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M179.176 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5718"></path><path d="M509.684 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5719"></path><path d="M846.175 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5720"></path></svg>
                        </a>
                        <ul class="more-box">
                            <li class="item"><a class="article-report">文章举报</a></li>
                        </ul>
                    </li>
                                        </ul>
            </div>
                        </div>
        <div class="person-messagebox">
            <div class="left-message"><a href="https://blog.csdn.net/Lamb_IT">
                <img src="https://profile.csdnimg.cn/7/5/5/3_lamb_it" class="avatar_pic" username="Lamb_IT">
                                        <img src="https://g.csdnimg.cn/static/user-reg-year/1x/2.png" class="user-years">
                                </a></div>
            <div class="middle-message">
                                    <div class="title"><span class="tit"><a href="https://blog.csdn.net/Lamb_IT" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}" target="_blank">Lamb_IT</a></span>
                                        </div>
                <div class="text"><span>发布了25 篇原创文章</span> · <span>获赞 25</span> · <span>访问量 6万+</span></div>
            </div>
                            <div class="right-message">
                                        <a href="https://im.csdn.net/im/main.html?userName=Lamb_IT" target="_blank" class="btn btn-sm btn-red-hollow bt-button personal-letter">私信
                    </a>
                                                        <a class="btn btn-sm  bt-button personal-watch" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}">关注</a>
                                </div>
                        </div>
                </div>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值