使用spring进行依赖注入

1.Spring IoC容器

在这里,我们先不具体深入的了解Spring IoC容器,只需要知道它是做什么的。Spring的核心就是IoC容器,它的作用是可以在对象生成或初始化时直接将数据注入到对象中,也可以通过将对象引用注入到对象数据域中的方式来注入对方法调用的依赖。也就是实现了所谓的依赖控制反转。Bean的实例化、初始化和装配都是由Spring容器来管理

1.1 配置元数据

首先,我们需要向Spring容器提供相关信息,以便于实例化Bean并指定如何对这些Bean进行装配。所提供的信息被称为配置元数据

有三种方式来配置元数据,一是XML配置,二是基于java配置,三是基于java注解的配置,三者的区别:

1
2
3

具体说一下,java配置和java注解配置的不同:

Java注解配置:需要在Serivce层,DAO层的时候,需要在类上进行注解,就可获得spring的依赖注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package di;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
//注解配置
@Service
public class UseFunctionService {
@Autowired
FunctionService functionService;

public String sayHello(String word) {
return functionService.toHello(word);
}
}

Java配置:不需要在类上写注解了,直接在配置类里面进行申明即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14

package javaconfig;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JavaConfig {
//通过这种方式,获得spring的依赖注入
@Bean
public UseFunctionService useFunctionService () {
return new UseFunctionService ();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package di;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

public class UseFunctionService {

FunctionService functionService = new FunctionService();

public void setFunctionService(FunctionService functionService) {
this.functionService = functionService;
}

public String sayHello(String word) {
return functionService.toHello(word);
}
}

2.依赖注入

依赖注入有两种方法:Setter注入构造函数注入

2.1 Setter注入

Setter注入是在Bean实例创建完毕之后执行。通过调用与Bean的配置元数据中定义的所有属性相对应的Setter方法注入这些属性。

具体实现:

1
2
3
4
5
6
7
8
//xml配置中
...

<bean id="selfIntroductionService" class="com.lanhuigu.spring.setter.SelfIntroductionServiceImpl">
<property name="helloService" ref="helloService"/>
</bean>

...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.lanhuigu.spring.setter;

import com.lanhuigu.spring.common.HelloService;

public class SelfIntroductionServiceImpl implements SelfIntroductionService {
private HelloService helloService;

// setter方式注入Bean
public void setHelloService(HelloService helloService) {
this.helloService = helloService;
}

@Override
public void selfIntroduction() {
// 向大家打招呼
helloService.sayHello("大家好!");
}

}

2.2 构造函数注入

构造函数注入在组建创建期间被执行。依赖项被表示为构造函数的参数,容器通过检查Bean定义中指定的构造函数参数来确定调用哪个构造函数。

具体实现:

1
2
3
4
5
6
7
8
9
//xml配置
...
<bean id="accountService" class="com.wiley.beginningspring.ch2.AccountServiceImpl">
<constructor-arg ref="accountDao"/>
</bean>

<bean id="accountDao" class="com.wiley.beginningspring.ch2.AccountDaoInMemroyImpl">
</bean>
...

1
2
3
4
5
6
7
public class AccountServiceImpl implements AccountService{
private AccountDao accountDao;

public AccountServiceImpl(AccountDao accountDao){
this.accountDao = accountDao;
}
}

2.3 循环依赖

构造函数注入有一个缺点,就是无法处理循环依赖。

1
2
3
4
5
6
7
public class A{
private B b;

public A(B b){
this.b = b;
}
}
1
2
3
4
5
6
7
public class B{
private A a

public B(A a){
this.a = a;
}
}
1
2
3
4
5
6
7
<bean id="a" class="com.wiley.beginningspring.ch2.A">
<constructor-arg ref="b"/>
</bean>

<bean id="b" class="com.wiley.beginningspring.ch2.B">
<constructor-arg ref="a"/>
</bean>

如上就是形成了循环依赖。构造函数注入的方法是无法处理的,但Setter注入的方法能够处理此类循环,但还是不建议在配置中使用循环依赖。

2.4 依赖解析过程

Spring容器的启动过程大致可分为两个主要阶段。在第一个阶段,容器处理配置元数据并建立元数据中存在的Bean定义,并对这些Bean进行验证。在该步骤中,Bean并没有被创建,相关的属性也没有被注入。在第二个阶段,首先完成Bean的创建,然后完成依赖注入。但实际上,并不是所有的Bean都被创建,在容器启动期间,仅创建了无状态作用域的Bean。

一个Bean在被完全创建且自己的依赖项被注入之前是不会作为一个依赖项被注入到其他Bean中去的。因此,必须确保被注入某一Bean中的Bean依赖项被完全配置且在目标Bean中使用。唯一的例外就是循环依赖,可以通过Setter方法来处理循环依赖,但存在缺陷,最好不要这样。

0%