概述
Spring中依赖注入
dependency injection
(DI)一般来说有两种形式: 1)基于xml的依赖注入, 2)基于注解的依赖注入。
基于xml的依赖注入方式通常又可以分为:1)构造函数方式注入。2)setter方式注入。
环境
Spring4.3.9, JDK1.8 pom添加spring依赖如下:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
一个包就够了。
测试项目结构:
目的:将HelloService的实例HelloServiceImpl注入到HelloPrinter中并在Application中通过容器取出来使用。
代码如下:
HelloService接口
public interface HelloService {
String sayHello();
}
HelloService实现
public class HelloServiceImpl implements HelloService {
public String sayHello() {
return "hello";
}
}
HelloPrinter类(未完成版本,在这里使用不同的方法依赖注入)
public class HelloPrinter {
private HelloService helloService;
public void print() {
System.out.println(helloService.sayHello());
}
}
Application类
public class Application {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
HelloPrinter printer = (HelloPrinter) context.getBean("helloPrinter");
printer.print();
}
}
依赖注入
构造函数方式
单个参数
HelloPrinter类:
public class HelloPrinter {
private HelloService helloService;
public HelloPrinter(HelloService helloService) {
this.helloService = helloService;
}
public void print() {
System.out.println(helloService.sayHello());
}
}
添加了构造函数,同时通过构造函数初始化helloService
spring.xml配置(以下helloService的配置省略):
<?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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="helloService" class="io.spring.hello.HelloServiceImpl" />
<bean id="helloPrinter" class="io.spring.hello.HelloPrinter">
<constructor-arg ref="helloService" />
</bean>
</beans>
首先使用<bean id="xx" class="xxx" />的方式将helloService的实例加入容器。
再使用上面的<constructor-arg>注入
运行输出:
hello
多个参数
1. 按照顺序注入
HelloPrinter类:
public class HelloPrinter {
private HelloService helloService;
public HelloPrinter(HelloService helloService, String s1, String s2, int id) {
this.helloService = helloService;
System.out.println(s1 + s2 + id);
}
public void print() {
System.out.println(helloService.sayHello());
}
}
xml配置:
<bean id="helloService" class="io.spring.hello.HelloServiceImpl" />
<bean id="helloPrinter" class="io.spring.hello.HelloPrinter">
<constructor-arg ref="helloService" />
<constructor-arg value="aaa"/>
<constructor-arg value="bbb"/>
<constructor-arg value="123"/>
</bean>
运行输出:
aaabbb123
hello
2. 按照类型注入
HelloPrinter
xml配置
public class HelloPrinter {
private HelloService helloService;
public HelloPrinter(HelloService helloService, String s, int id) {
this.helloService = helloService;
System.out.println(s + id);
}
public void print() {
System.out.println(helloService.sayHello());
}
}
xml配置
<bean id="helloService" class="io.spring.hello.HelloServiceImpl" />
<bean id="helloPrinter" class="io.spring.hello.HelloPrinter">
<constructor-arg type="int" value="123"/>
<constructor-arg type="io.spring.hello.HelloService" ref="helloService" />
<constructor-arg type="java.lang.String" value="aaa"/>
</bean>
即使顺序不同也可以正确注入。
如果有多个相同的类型,则按照实际注入的顺序和构造器中参数类型的顺序决定。(相同的类型先到先得)
运行输出:
aaa123
hello
3. 按照name注入
HelloPrinter
public class HelloPrinter {
private HelloService helloService;
public HelloPrinter(HelloService helloService, String s, int id) {
this.helloService = helloService;
System.out.println(s + id);
}
public void print() {
System.out.println(helloService.sayHello());
}
}
<bean id="helloPrinter" class="io.spring.hello.HelloPrinter">
<constructor-arg name="id" value="123"/>
<constructor-arg name="helloService" ref="helloService" />
<constructor-arg name="s" value="aaa"/>
</bean>
指定构造器中参数的name
输出:
aaa123
hello
4. 按照index注入
HelloPrinter
public class HelloPrinter {
private HelloService helloService;
public HelloPrinter(HelloService helloService, String s, int id) {
this.helloService = helloService;
System.out.println(s + id);
}
public void print() {
System.out.println(helloService.sayHello());
}
}
<bean id="helloPrinter" class="io.spring.hello.HelloPrinter">
<constructor-arg index="2" value="123"/>
<constructor-arg index="0" ref="helloService" />
<constructor-arg index="1" value="aaa"/>
</bean>
index从0开始,分别对应构造器中的参数顺序。
setter注入
HelloPrinter
public class HelloPrinter {
private HelloService helloService;
private String s;
private int id;
public void setHelloService(HelloService helloService) {
this.helloService = helloService;
}
public void setS(String s) {
this.s = s;
}
public void setId(int id) {
this.id = id;
}
public void print() {
System.out.println(helloService.sayHello() + s + id);
}
}
xml配置:
<bean id="helloPrinter" class="io.spring.hello.HelloPrinter">
<property name="helloService" ref="helloService" />
<property name="s" value="hhhh" />
<property name="id" value="123123" />
</bean>
运行输出:
hellohhhh123123
注意:使用构造器注入方式不能出现循环的依赖注入
例:
<bean id="helloService" class="io.spring.hello.HelloServiceImpl">
<constructor-arg name="helloPrinter" ref="helloPrinter" />
</bean>
<bean id="helloPrinter" class="io.spring.hello.HelloPrinter">
<constructor-arg name="helloService" ref="helloService" />
</bean>
spring会报错
Error creating bean with name 'helloService': Requested bean is currently in creation: Is there an unresolvable circular reference?