在之前的java开发中,某个类中须要依赖其它类的方法时,一般是new一个依赖类再调用类实例的方法,这种方法耦合度过高而且不容易测试,spring提出了依赖注入的思想,即依赖类不禁程序员实例化,而是经过spring容器帮咱们new指定实例而且将实例注入到须要该对象的类中。java
依赖注入有3种方式:构造器注入、set注入和注解注入。程序员
构造器注入保证一些必要的属性在Bean实例化时就获得设置,而且确保了Bean实例在实例化后就可使用。spring
使用方式:less
例子1:函数
public class SpringAction { //注入对象springDao private SpringDao springDao; private User user; public SpringAction(SpringDao springDao,User user){ this.springDao = springDao; this.user = user; System.out.println("构造方法调用springDao和user"); } public void save(){ user.setName("卡卡"); springDao.save(user); } }
<bean name="springAction" class="com.bless.springdemo.action.SpringAction"> <!--(2)建立构造器注入,若是主类有带参的构造方法则需添加此配置--> <constructor-arg index="0" ref="springDao"></constructor-arg> <constructor-arg index="1" ref="user"></constructor-arg> </bean> <bean name="springDao" class="com.bless.springdemo.dao.impl.SpringDaoImpl"></bean> <bean name="user" class="com.bless.springdemo.vo.User"></bean>
其中index属性表示注入的bean在构造方法中的参数顺序。测试
例子2:this
有时须要联合使用type和index才能肯定匹配项和构造函数入参的对应关系,看下面的代码。spa
public Car(String brand, String corp,double price){ this.brand=brand; this.corp=corp; this.price=price; } public Car(String brand, String corp,int maxSpeed){ this.brand=brand; this.corp=corp; this.maxSpeed=maxSpeed; }
这里,Car拥有两个重载的构造函数,它们都有三个入参。针对这种状况,按照入参索引的配置方式又难以知足要求了,这时须要联合使用<constructor-arg>的type和index才能解决问题.net
<!-- 构造函数注入(经过入参类型和位置索引肯定对应关系) --> <!-- 对应public Car(String brand, String corp,int maxSpeed)构造函数 --> <bean id="car3" class="com.spring.model.Car"> <constructor-arg index="0" type="java.lang.String" value="奔驰"></constructor-arg> <constructor-arg index="1" type="java.lang.String" value="中国一汽"></constructor-arg> <constructor-arg index="2" type="int" value="200"></constructor-arg> </bean>
对于因为参数数目相同而类型不一样所引发的潜在配置歧义问题,Spring容器能够正确启动且不会给出报错信息,它将随机采用一个匹配的构造函数实例化Bean,而被选择的构造函数可能并非用户所但愿的。所以,必须特别谨慎,以免潜在的错误。code
set注入要求Bean提供一个默认的构造函数,并为须要注入的属性提供对应的Setter方法。
Spring先调用Bean的默认构造函数实例化Bean对象,而后经过反射的方式调用Setter方法注入属性值。
假设Bean显示定义了一个带参的构造函数,则须要同时提供一个默认无参的构造函数,不然使用属性注入时将抛出异常。
例子1:
package com.bless.springdemo.action; public class SpringAction { //注入对象springDao private SpringDao springDao; //必定要写被注入对象的set方法 public void setSpringDao(SpringDao springDao) { this.springDao = springDao; } public void ok(){ springDao.ok(); } }
<!--配置bean,配置后该类由spring管理--> <bean name="springAction" class="com.bless.springdemo.action.SpringAction"> <!--(1)依赖注入,配置当前类中相应的属性--> <property name="springDao" ref="springDao"></property> </bean> <bean name="springDao" class="com.bless.springdemo.dao.impl.SpringDaoImpl"></bean>
这里再也不使用“constructor-arg”而是使用“property”属性。
注解注入实际上是使用注解的方式进行构造器注入或者set注入。
spring2.5开始提供了基于注解(Annotation-based)的配置,咱们能够经过注解的方式来完成注入依赖。在Java代码中可使用 @Resource或者@Autowired注解方式来经行注入。
虽然@Resource和@Autowired均可以来完成注入依赖,但它们之间是有区别的:
例子:
package com.bless.springdemo.action; public class SpringAction { //注入对象springDao @Resource private SpringDao springDao; //不须要要写被注入对象的set方法,spring会帮你get/set public void ok(){ springDao.ok(); } }
<context:annotation-config/>
<bean name="springAction" class="com.bless.springdemo.action.SpringAction"> <!--不须要配置属性,@Resource默认按照名称装配注入--> </bean> <bean name="springDao" class="com.bless.springdemo.dao.impl.SpringDaoImpl"></bean>
<context:annotation-config/>的做用是开启注解。
@Autowired的同理,只不过默认是按照类型装配注入。
补充:
@Autowired 能够对成员变量、方法以及构造函数进行注释。那么对成员变量和构造函数进行注释又有什么区别呢?
先来看下面一段代码:
@Autowired private User user; private String school; public UserAccountServiceImpl(){ this.school = user.getSchool(); }
这段代码执行会报错,由于Java类会先执行构造方法,而后再给注解了@Autowired 的user注入值,因此在执行构造方法的时候,就会报错。
解决办法是,使用构造器注入,以下:
private User user; private String school; @Autowired public UserAccountServiceImpl(User user){ this.user = user; this.school = user.getSchool(); }
参考: