依赖注入

Spring主要提供以下两种方法用于依赖注入

  • 基于属性Setter方法注入
  • 基于构造方法注入

Setter方法注入

例子:

public class Communication {

    private Messaging messaging;

     /*
* DI via Setter
*/
public void setMessaging(Messaging messaging){
this.messaging = messaging;
} public void communicate(){
messaging.sendMessage();
}
}

如上Communication类有一个messaging属性,并含有setMessaging方法,那么使用Setter方法注入的时候,只需要使用如下XML配置即可:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <bean id="activeMqMessaging" class="com.websystique.spring.domain.impl.ActiveMQMessaging" /> <bean id="communication" class="com.websystique.spring.Communication">
<property name="messaging">
<ref bean="activeMqMessaging" />
</property>
</bean> </beans>

这里省略了ActiveMQMessaging的定义,实际上ActiveMQMessaging类是Messaging接口的一个实现类。

构造方法注入

例子

public class Communication {

    private Encryption encryption;

    /*
* DI via Constructor Injection
*/
public Communication(Encryption encryption){
this.encryption = encryption;
} public void communicate(){
encryption.encryptData();
} }

注意以上Communication类有一个构造方法Communication(Encryption encryption),且含有一个入参,类型为Encryption,那么使用构造方法注入的时候,XML配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <bean id="rsaEncryption" class="com.websystique.spring.domain.impl.RSAEncryption" /> <bean id="communication" class="com.websystique.spring.Communication">
<constructor-arg type="com.websystique.spring.domain.Encryption">
<ref bean="rsaEncryption" />
</constructor-arg>
</bean> </beans>

注意,这里省略了RSAEncryption的定义,不用在意这些细节,该类是Encryption接口的一个实现类。

另外,为了避免构造方法重载带来的歧义,这里指定了入参类型为com.websystique.spring.domain.Encryption。

装配

bean的装配有两种方式,手动装配和自动装配。注意,不要混淆,bean的装配是依赖注入的具体行为,依赖注入的时候需要根据bean的名称或类型等进行装配。

手动装配:通过在<property> 或者 <constructor>标签中使用ref属性,在上一小节的“依赖注入”部分使用的就是手动装配;

<!-- default example (autowire="no") -->
<bean id="driver" class="com.websystique.spring.domain.Driver">
<property name="license" ref="license"/>
</bean> <bean id="license" class="com.websystique.spring.domain.License" >
<property name="number" value="123456ABCD"/>
</bean>

自动装配:在<bean>标签中使用autowire属性;

<bean id="application" class="com.websystique.spring.domain.Application" autowire="byName"/>

本小节主要关注自动装配,自动装配有以下四种方式:

  • autowire="byName" : 根据名称
  • autowire="byType" : 根据类型
  • autowire="constructor" : 根据构造方法入参类型
  • autowire="no" : 不使用自动装配,即默认方式,手动装配

autowire="byName"

例子:

public class Application {

    private ApplicationUser applicationUser;

    public ApplicationUser getApplicationUser() {
return applicationUser;
} public void setApplicationUser(ApplicationUser applicationUser) {
this.applicationUser = applicationUser;
} @Override
public String toString() {
return "Application [applicationUser=" + applicationUser + "]";
}
}

该类有一个属性叫applicationUser,那么根据名称自动装配的XML配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- byName example -->
<bean id="application" class="com.websystique.spring.domain.Application" autowire="byName"/> <bean id="applicationUser" class="com.websystique.spring.domain.ApplicationUser" >
<property name="name" value="superUser"/>
</bean>
</beans>

autowire="byType"

例子

public class Employee {

    private EmployeeAddress address;

    public EmployeeAddress getAddress() {
return address;
} public void setAddress(EmployeeAddress address) {
this.address = address;
} @Override
public String toString() {
return "Employee [address=" + address + "]";
}
}

该类有一个属性类型为EmployeeAddress,那么根据类型自动装配的XML配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- byType example -->
<bean id="employee" class="com.websystique.spring.domain.Employee" autowire="byType"/> <bean id="employeeAddress" class="com.websystique.spring.domain.EmployeeAddress" >
<property name="street" value="112/223,SantaVila"/>
<property name="city" value="Nebraska"/>
</bean> </beans>

autowire="constructor"

例子

public class Performer {

    private Instrument instrument;

    public Performer(Instrument instrument){
this.instrument = instrument;
} @Override
public String toString() {
return "Performer [instrument=" + instrument + "]";
}
}

该类有一个构造方法,入参的类型为Instrument,那么根据构造方法自动装配的XML配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- constructor example -->
<bean id="performer" class="com.websystique.spring.domain.Performer" autowire="constructor"/> <bean id="instrument" class="com.websystique.spring.domain.Instrument" >
<property name="name" value="PIANO"/>
</bean> </beans>

autowire="no"

public class Driver {

    private License license;

    public void setLicense(License license) {
this.license = license;
} public License getLicense() {
return license;
} @Override
public String toString() {
return "Driver [license=" + license + "]";
}
}

该类有一个属性license,由于我们不打算使用自动装配功能,那么只能使用手动装配了,XML配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- default example (autowire="no") -->
<bean id="driver" class="com.websystique.spring.domain.Driver" autowire="no">
<property name="license" ref="license"/>
</bean> <bean id="license" class="com.websystique.spring.domain.License" >
<property name="number" value="123456ABCD"/>
</bean> </beans>

注意,如果不配置license的ref引用的话,license将为null。

相关注解

主要涉及以下三个注解

  • @Autowired
  • @Resource
  • @Qualifier

@Autowired可应用于构造方法、属性、setter方法或配置类@Configuration的方法上,该注解根据bean的数据类型进行装配,如果你想希望根据bean的名称进行装配可以使用带name属性的@Resource注解;另外@Qualifier注解经常与@Autowired注解结合使用,用于解决一个应用中存在多个同种类型的bean的情况,下面将给出各个注解的示例。

@Autowired(根据类型自动装配)

setter方法上

@Component("driver")
public class Driver { private License license; @Autowired
public void setLicense(License license) {
this.license = license;
} @Override
public String toString() {
return "Driver [license=" + license + "]";
}
//getter
}

构造方法上

@Component("driver")
public class Driver { private License license; @Autowired
public Driver(License license){
this.license = license;
} @Override
public String toString() {
return "Driver [license=" + license + "]";
}
}

属性上

@Component("driver")
public class Driver {
@Autowired
private License license; //getter,setter @Override
public String toString() {
return "Driver [license=" + license + "]";
}
}

@Resource(根据名称装配)

@Component("application")
public class Application { @Resource(name="applicationUser")
private ApplicationUser user; @Override
public String toString() {
return "Application [user=" + user + "]";
}
}

@Qualifier(与@Autowired结合使用,实现按名称装配)

例子背景::存在两个Car接口的实现类,其中一个Car接口的实现类已被注册为bean,且name为Mustang

@Component
public class Bond { @Autowired
@Qualifier("Mustang")
private Car car; public void showCar(){
car.getCarName();
}
}

注意,以上例子如果不使用@Qualifier限定的话,将抛出如下异常,表明存在多个类型相同的bean:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.websystique.spring.domain.Car] is defined: expected single matching bean but found 2: Ferari,Mustang
    at
org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:970)
   
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:858)
   
at
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:480)
    ... 14 more

最后提醒下,被@Autowired注解标注默认情况下能保证成功注入,如果注入不成功(往往是找不到,或存在歧义),Spring会抛出异常。当然,有时候可能会有特殊需求,不希望bean被强制装配,那么可以在@Autowired上添加required=false属性,表明该bean的装配是可选的,找不到的话,就为null吧,如下示例:

@Component("driver")
public class Driver {
@Autowired(required=false)
private License license; //getter,setter @Override
public String toString() {
return "Driver [license=" + license + "]";
}
}

基于以上原因,虽然@Autowired注解与@Resource功能类似,但是@Autowired还是比@Resource强大了那么一点点,个人建议使用@Autowired注解。

参考资料

http://websystique.com/spring/spring-dependency-injection-example-with-constructor-and-property-setter-xml-example/

http://websystique.com/spring/spring-beans-auto-wiring-example-using-xml-configuration/

http://websystique.com/spring/spring-dependency-injection-annotation-beans-auto-wiring-using-autowired-qualifier-resource-annotations-configuration/

 

Spring bean依赖注入、bean的装配及相关注解的更多相关文章

  1. 【串线篇】spring泛型依赖注入原理

    spring泛型依赖注入原理 不管三七二十一 servlet :加注解@servlet service:加注解@service dao:加注解@Repository 这相当于在容器中注册这些个类

  2. Spring 源码分析之 bean 依赖注入原理(注入属性)

         最近在研究Spring bean 生命周期相关知识点以及源码,所以打算写一篇 Spring bean生命周期相关的文章,但是整理过程中发现涉及的点太多而且又很复杂,很难在一篇文章中把Spri ...

  3. 002-Spring4 快速入门-项目搭建、基于注解的开发bean,Bean创建和装配、基于注解的开发bean,Bean初始化销毁、Bean装配,注解、Bean依赖注入

    一.项目搭建 1.项目创建 eclipse→project explorer→new→Project→Maven Project 默认配置即可创建项目 2.spring配置 <dependenc ...

  4. [转载]Spring下IOC容器和DI(依赖注入) @Bean及@Autowired

    Spring下IOC容器和DI(依赖注入) @Bean及@Autowired自动装配 bean是什么 bean在spring中可以理解为一个对象.理解这个对象需要换一种角度,即可将spring看做一门 ...

  5. 开涛spring3(12.2) - 零配置 之 12.2 注解实现Bean依赖注入

    12.2  注解实现Bean依赖注入 12.2.1  概述 注解实现Bean配置主要用来进行如依赖注入.生命周期回调方法定义等,不能消除XML文件中的Bean元数据定义,且基于XML配置中的依赖注入的 ...

  6. 注解实现Bean依赖注入

    12.2.1  概述 注解实现Bean配置主要用来进行如依赖注入.生命周期回调方法定义等,不能消除XML文件中的Bean元数据定义,且基于XML配置中的依赖注入的数据将覆盖基于注解配置中的依赖注入的数 ...

  7. java框架篇---spring IOC依赖注入

    spring依赖注入的方式有4种 构造方法注入 属性注入 工厂注入 注解注入 下面通过一个实例统一讲解: User.java package com.bjsxt.model; public class ...

  8. Spring笔记——依赖注入

    依赖注入有三种方式: 1. 使用构造器注入  2. 使用属性setter方法注入 3. 使用Field注入(用于注解方式) 注入依赖对象可以采用手工装配或自动装配,在实际应用中建议使用手工装配,因为自 ...

  9. Spring中依赖注入的四种方式

    在Spring容器中为一个bean配置依赖注入有三种方式: · 使用属性的setter方法注入  这是最常用的方式: · 使用构造器注入: · 使用Filed注入(用于注解方式). 使用属性的sett ...

  10. Spring系列.依赖注入配置

    依赖注入的配置 Spring的依赖注入分为基于构造函数的依赖注入和基于setter方法的依赖注入. 基于构造函数的依赖注入 <!-- 通过构造器参数索引方式依赖注入 --> <bea ...

随机推荐

  1. Nodejs之MEAN栈开发(五)---- Angular入门与页面改造

    这个系列一共会涉及两个JavaScript框架的讲解,一个是Express用做后端,一个是Angular用于前端.和Express一样,Angular分离内容,处理视图.数据和逻辑.和MVC模式很相似 ...

  2. 用Go实现的简易TCP通信框架

    接触到GO之后,GO的网络支持非常令人喜欢.GO实现了在语法层面上可以保持同步语义,但是却又没有牺牲太多性能,底层一样使用了IO路径复用,比如在LINUX下用了EPOLL,在WINDOWS下用了IOC ...

  3. 玩转Windows服务系列汇总

    玩转Windows服务系列汇总 创建Windows服务 Debug.Release版本的注册和卸载及其原理 无COM接口Windows服务启动失败原因及解决方案 服务运行.停止流程浅析 Windows ...

  4. ASP.NET MVC 视图(五)

    ASP.NET MVC 视图(五) 前言 上篇讲解了视图中的分段概念.和分部视图的使用,本篇将会对Razor的基础语法简洁的说明一下,前面的很多篇幅中都有涉及到视图的调用,其中用了很多视图辅助器,也就 ...

  5. 新思想、新技术、新架构——更好更快的开发现代ASP.NET应用程序

    在博客园学习很长时间了,今天终于自己也开通了博客,准备分享一些感悟和经验.首先感谢博客园园主提供了这么好的程序员学习交流平台,也非常感谢张善友.dax.net.netfocus.司徒正美 等技术大牛的 ...

  6. iOS-----App闪退,程序崩溃---解决方案

    1.iOS-中app启动闪退的原因 2.iOS开发-闪退问题-解决之前上架的 App 在 iOS 9 会闪退问题 3.iOS-应用闪退总结 4.iOS开发-捕获程序崩溃日志 5.iOS开发-应用崩溃日 ...

  7. Python 资源大全中文版

    Python 资源大全中文版 我想很多程序员应该记得 GitHub 上有一个 Awesome - XXX 系列的资源整理.awesome-python 是 vinta 发起维护的 Python 资源列 ...

  8. 【.net 深呼吸】聊聊WCF服务返回XML或JSON格式数据

    有时候,为了让数据可以“跨国经营”,尤其是HTTP Web有关的东东,会将数据内容以 XML 或 JSON 的格式返回,这样一来,不管客户端平台是四大文明古国,还是处于蒙昧时代的原始部落,都可以使用这 ...

  9. MySql常用数据类型分析

    整数类型 TINYINT.SMALLINT.MEDIUMINT.INT.BIGINT 分别使用8,16,24,32,64位存储空间,值得范围-2的(N-1)方到2的(N-1)方-1.根据需要存储的范围 ...

  10. Handler系列之使用

    作为一个Android开发者,我们肯定熟悉并使用过Handler机制.最常用的使用场景是"在子线程更新ui",实际上我们知道上面的说话是错误的.因为Android中只有主线程才能更 ...