这里感谢 CSDN 的原博客: https://blog.csdn.net/zhaoraolin/article/details/78941062
1. IOC理论的背景
在平时的java应用开发中,我们要实现某一个功能或者说是完成某个业务逻辑时至少需要两个或以上的对象来协作完成,在没有使用Spring的时候,每个对象在需要使用它的合作对象时,自己均要使用像new object() 这样的语法来将合作对象创建出来,这个合作对象是由自己主动创建出来的,创建合作对象的主动权在自己手上,自己需要哪个合作对象,就主动去创建,创建合作对象的主动权和创建时机是由自己把控的,而这样就会使得对象间的耦合度高了,A对象需要使用合作对象B来共同完成一件事,A要使用B,那么A就对B产生了依赖,也就是A和B之间存在一种耦合关系,并且是紧密耦合在一起,而使用了Spring之后就不一样了,创建合作对象B的工作是由Spring来做的,Spring创建好B对象,然后存储到一个容器里面,当A对象需要使用B对象时,Spring就从存放对象的那个容器里面取出A要使用的那个B对象,然后交给A对象使用,至于Spring是如何创建那个对象,以及什么时候创建好对象的,A对象不需要关心这些细节问题(你是什么时候生的,怎么生出来的我可不关心,能帮我干活就行),A得到Spring给我们的对象之后,两个人一起协作完成要完成的工作即可。
2. code
/**
* 一个伟大的程序员类
* */
public class Programmer {
private String name;
private String sex;
public void coding(){
//要用到computer对象,调用computer的coding方法,
//在这里new computer对象,控制权在Programmer手里
Computer computer = new Computer();
computer.coding();
}
}
public class Computer {
private String brand;
private String color;
private double size;
public void coding() {
System.out.println("Computer is coding!!!");
}
}
上面,就是用传统方式创建依赖对象。接下来,看看Spring IOC是怎样反转控制权来创建对象的。
3. 三种方式:属性注入,构造器注入,自动装配。
3.1 属性注入(setter注入)
public class Programmer {
private String name;
private String sex;
// 在这里定义要依赖的computer属性,加上set方法
private Computer computer;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Computer getComputer() {
return computer;
}
/**
* 加上Setter方法
* */
public void setComputer(Computer computer) {
this.computer = computer;
}
}
public class Computer {
private String brand;
private String color;
private String size;
public void coding() {
System.out.println("Computer is coding!!!");
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
}
看上面的代码,可以发现,Programmer类里面,有3个属性,name,sex,computer,并且都有对应的getter、setter方法;Computer类里面也有三个属性,分别是品牌、颜色、尺寸,也都有对应的getter、setter方法。这只是第一步,在类里面声明属性并且实现set方法。
接下来,要写一个spring的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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="programmer" class="com.spring.demo2.entity.Programmer">
<property name="name" value="小李"></property>
<property name="sex" value="男"></property>
<property name="computer" ref="computer"></property>
</bean>
<bean id="computer" class="com.spring.demo2.entity.Computer">
<property name="brand" value="hp"></property>
<property name="color" value="黑"></property>
<property name="size" value="14"></property>
</bean>
</beans>
解读一下这个xml文件:
1.声明一个bean,可以理解为实例化了一个对象。那这里实例化了两个对象(programmer和computer),各个属性都已经赋值上去。
2.id为programmer的bean,其实就是Programmer类;通过给property赋值,Spring就会通过Programmer类的各个属性的set方法,逐一给Programmer的属性赋值。
3.在programmer里面,有一个属性是computer的,可以看到它属性值是 ref=“computer”,这就说明computer这个属性是个引用,这里ref后面的值其实就是指向另一个bean的id值,所以这里引用的是id为computer的bean。
以上,就是属性注入了。关键的是在类里面声明属性,写set方法,然后在xml里面配置bean和property的值。
3.2. 构造器注入
构造器注入,顾名思义,就是在构造器里面注入依赖对象。那是怎么实现的呢?其实跟属性注入差不多,定义一个有参构造器,然后配置xml文件就行了。看代码:
import com.spring.demo02.entity.Computer;
public class Programmer {
private Computer computer;
public Programmer(Computer computer){
this.computer = computer;
}
}
public class Computer {
private String brand;
private String color;
private String size;
public Computer(String brand, String color, String size) {
this.brand = brand;
this.color = color;
this.size = size;
}
}
上面两个类都有一个有参的构造器,接下来,在xml里面配置这两个bean,然后再配置构造器的参数值就可以了
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="programmer" class="com.spring.demo3.entity.Programmer">
<constructor-arg ref="computer"></constructor-arg>
</bean>
<!-- 构造器里面没有name字段,只有value,是根据构造器的方法参数顺序来定义的 -->
<bean id="computer" class="com.spring.demo3.entity.Computer">
<constructor-arg value="联想"></constructor-arg>
<constructor-arg value="红色"></constructor-arg>
<constructor-arg value="15.6寸"></constructor-arg>
</bean>
</beans>
3.3. 自动装配
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Programmer {
@Autowired
Computer computer;
}
import org.springframework.stereotype.Component;
@Component
public class Computer {
private String brand;
private String color;
private String size;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
}
<?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/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<context:component-scan base-pakage="com.spring.demo04">
</beans>
关键点:在类前面加注解:@Component,在需要注入的类里面加注解:@Autowired,这样xml里面的自动扫描就会扫描到这些加了注解的类和属性,在实例化bean的时候,Spring容器会把加了@Component的类实例化;在实际运行时,会给加了@Autowired的属性注入对应的实例。
Spring中的自动装配有哪些限制?
- 如果使用了构造器注入或者setter注入,那么将覆盖自动装配的依赖关系。
- 基本数据类型的值、字符串字面量、类字面量无法使用自动装配来注入。
- 优先考虑使用显式的装配来进行更精确的依赖注入而不是使用自动装配。
和自动装配相关的注解有哪些?
- @Required:该依赖关系必须装配(手动或自动装配),否则将抛出BeanInitializationException异常。
- @Autowired:自动装配,默认按类型进行自动装配。
- @Qualifier:如果按类型自动装配时有不止一个匹配的类型,那么可以使用该注解指定名字来消除歧义。
- 注释的作用