前言
Spring 容器作为超级大工厂,负责创建、管理所有的 Java 对象,这些对象统称为 Bean。
Spring 容器使用依赖注入(Dependency Injection, DI)的方式,管理容器中 Bean 之间的依赖关系,达成控制反转(Inversion of Control, IoC)的目的。
依赖注入
依赖注入的几种方式
设值注入
原理解析:
IoC 容器通过成员变量的 setter 方法注入被依赖对象。
代码示例:
想要在 Person 类里注入 Axe 类,从而在 Person 类的方法里,访问到 Axe 类的方法。
类 Person
public class Person {
private Axe axe;
/**
* 设值注入
*/
public void setAxe(Axe axe) {
System.out.println("设值注入 Axe");
this.axe = axe;
}
public void useAxe() {
System.out.println("I want to chop wood");
// 访问 Axe 类的方法
System.out.println(axe.chop());
}
类 Axe
public class Axe {
public String chop(){
return "use an axe to chop wood";
}
}
配置文件 Beans.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.xsd">
<bean id="person" class="org.autumn.boot.ssm.study.di.Person">
<property name="axe" ref="axe"/>
</bean>
<bean id="axe" class="org.autumn.boot.ssm.study.di.Axe"/>
</beans>
配置文件中,
<bean>
声明 spring bean,id
指定唯一标识,class
指定实现类。
XML 解析器读取配置的内容,由Spring 容器通过反射的方式来创建该实现类,作为 Bean 来使用。
Spring 会检测每个<bean>
中的<property>
元素,根据元素内容,调用对应的 setter 方法为 Bean 的成员变量注入值。
通过创建 Spring 容器 ApplicationContext 来获取 beans.xml 中 配置的 Bean 实例。
public class Main {
public static final String CONFIG_LOCATION = "beans.xml";
public static void main(String[] args) {
// 创建 ApplicationContext 容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(CONFIG_LOCATION);
// 从容器中获取 Bean 实例
Person person = context.getBean(Person.class);
// 访问 Bean 实例的方法
person.useAxe();
// 为 Spring 容器注册关闭钩子
context.registerShutdownHook();
}
}
执行结果:
设值注入 Axe
I want to chop wood
use an axe to chop wood
可以看到 Person 类在使用 Axe 类的过程中,不需要自己去创建、维护,直接由 Spring 容器注入。
可以说由依赖注入实现了控制反转,达到了依赖类之间解耦的目的。
构造注入
原理解析:
驱动 Spring 在底层以反射的方式执行带参数的构造器,在执行带参数构造器时,可利用构造器参数对成员变量执行初始化。
代码示例:
想要在 Person 类里注入 Axe 类,从而在 Person 类的方法里,访问到 Axe 类的方法。
类 Person
public class Person {
private Axe axe;
/**
* 构造注入
*/
public Person(Axe axe) {
System.out.println("构造注入 Axe");
this.axe = axe;
}
public void useAxe() {
System.out.println("I want to chop wood");
// 访问 Axe 类的方法
System.out.println(axe.chop());
}
类 Axe
public class Axe {
public String chop(){
return "use an axe to chop wood";
}
}
配置文件 Beans.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.xsd">
<bean id="person" class="org.autumn.boot.ssm.study.di.Person">
<constructor-arg ref="axe"/>
</bean>
<bean id="axe" class="org.autumn.boot.ssm.study.di.Axe"/>
</beans>
Spring 根据
<constructor-arg>
元素的定义反射执行相应的构造方法。
如果由多个参数,则可以使用 index=0
来标记,例如:
<bean id="person" class="org.autumn.boot.ssm.study.di.Person">
<constructor-arg index="0" value="123"/>
<constructor-arg index="1" value="hello"/>
</bean>
通过创建 Spring 容器 ApplicationContext 来获取 beans.xml 中 配置的 Bean 实例。
public class Main {
public static final String CONFIG_LOCATION = "beans.xml";
public static void main(String[] args) {
// 创建 ApplicationContext 容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(CONFIG_LOCATION);
// 从容器中获取 Bean 实例
Person person = context.getBean(Person.class);
// 访问 Bean 实例的方法
person.useAxe();
// 为 Spring 容器注册关闭钩子
context.registerShutdownHook();
}
}
执行结果:
构造注入 Axe
I want to chop wood
use an axe to chop wood
两种注入方法的对比
设值注入和构造注入这两种方法对比而言:
- 设值注入依赖关系显得更加直观、自然。
- 对于复杂的依赖关系,构造注入会导致构造器过于笨重。
- 构造注入更符合高内聚的原则
接口注入
参见下文 : 在 Bean 中获取 Spring 容器
https://blog.csdn.net/u010541670/article/details/113809866