Bean的依赖注入方式与数据类型

本文最后更新于:1 年前

  • IoC (Inverse of Control)—— 控制反转。通过Spring对象工厂完成对象的创建。

  • DI (Dependency Injection)——依赖注入。在Spring完成对象创建的同时,依赖Spring容器完成对象属性的赋值。

    依赖注入(Dependency Injection)是 Spring 框架核心 IOC 的具体实现。

案例引入

  1. 创建 UserService,UserService 内部在调用 UserDao的save() 方法

    1
    2
    3
    4
    5
    6
    7
    8
    public class UserServiceImpl implements UserService {
    @Override
    public void save() {
    ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserDao userDao = (UserDao) app.getBean("userDao");
    userDao.save();
    }
    }
  2. 将 UserServiceImpl 的创建权交给 Spring

    1
    2
    <bean id="userDao" class="cc.gaojie.dao.impl.UserDaoImpl" ></bean>
    <bean id="userService" class="cc.gaojie.service.impl.UserServiceImpl"></bean>
  3. 从 Spring 容器中获得 UserService 进行操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class UserController {

    public static void main(String[] args) {
    ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserService userService = (UserService) app.getBean("userService");
    userService.save();
    }

    }


目前 UserService 实例和 UserDao 实例都存在与Spring容器中,当前的做法是在容器外部获得 UserService 实例和 UserDao 实例,然后在程序中进行结合。

因为 UserService 和 UserDao 都在 Spring 容器中,而最终程序直接使用的是 UserService,所以可以在 Spring 容器中,将 UserDao 设置到 UserService 内部。

依赖注入简介

依赖注入(Dependency Injection)是 Spring 框架核心 IOC 的具体实现。

在编写程序时,通过控制反转,把对象的创建交给了 Spring,但是代码中不可能出现没有依赖的情况。IOC 解耦只是降低他们的依赖关系,但不会消除。例如:业务层仍会调用持久层的方法。

那这种业务层和持久层的依赖关系,在使用 Spring 之后,就让 Spring 来维护了。简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。

控制反转与依赖注入

控制反转(IoC )

当我们需要通过Spring对象工厂创建某个类的对象时候,需要将这个交给Spring管理——通过bean标签配置。

1
2
3
4
<!--通过bean将实体类配置给Spring进行管理,id表示实体类的唯一表示-->
<bean id="stu" class="cc.gaojie.ioc.bean.Student"></bean>

<bean id="book" class="cc.gaojie.ioc.bean.Book"></bean>

依赖注入(DI)

即通过Spring容器给创建的对象属性赋值。

1
2
3
4
5
6
<bean id="clazz" class="cc.gaojie.ioc.bean.Clazz"></bean>

<!--通过bean将实体类配置给Spring进行管理,id表示实体类的唯一表示-->
<bean id="stu" class="cc.gaojie.ioc.bean.Student" autowire="byName">
<property name="stuNum" value="10001"/>
</bean>

依赖注入方式与数据类型

怎么将UserDao注入到UserService内部呢?

Spring容器加载配置文件之后,通过反射创建类的对象,并给属性赋值。Spring容器通过反射实现属性注入有三种方式:

set方法注入

在bean标签中通过配置property标签给属性属性赋值,实际上就是通过反射调用set方法完成属性的注入。

Spring底层实现

常规 set 方法注入

  1. 在 UserServiceImpl 中添加 setUserDao 方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class UserServiceImpl implements UserService {

    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
    }

    @Override
    public void save() {
    userDao.save();
    }
    }
  2. 配置 Spring 容器调用 set 方法进行注入

    1
    2
    3
    4
    5
    <bean id="userDao" class="cc.gaojie.dao.impl.UserDaoImpl" ></bean>

    <bean id="userService" class="cc.gaojie.service.impl.UserServiceImpl">
    <property name="userDao" ref="userDao"></property>
    </bean>
  3. 从 Spring 容器中获得 UserService 进行操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class UserController {

    public static void main(String[] args) {
    ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserService userService = (UserService) app.getBean("userService");
    userService.save();
    }

    }

P 命名空间注入

P 命名空间注入本质也是 set 方法注入,但比起上述的 set 方法注入更加方便,主要体现在配置文件中。

  1. 首先,需要引入P命名空间:

    1
    xmlns:p="http://www.springframework.org/schema/p"
  2. 其次,需要修改注入方式:

    1
    2
    3
    <bean id="userDao" class="cc.gaojie.dao.impl.UserDaoImpl"></bean>
    <!--p命名空间注入-->
    <bean id="userService" class="cc.gaojie.service.impl.UserServiceImpl" p:userDao-ref="userDao"></bean>

不同数据类型属性的注入方式

上面的操作,都是注入的引用 Bean,除了对象的引用可以注入,普通数据类型,集合等都可以在容器中进行注入。

注入数据的三种数据类型:

  • 普通数据类型
  • 引用数据类型
  • 集合数据类型

简单类型及字符串

直接通过 property 标签的 value 属性赋值。

1
2
3
4
5
6
7
8
<!--通过bean将实体类配置给Spring进行管理,id表示实体类的唯一表示-->
<bean id="stu" class="cc.gaojie.ioc.bean.Student" autowire="byName">
<!-- 简单类型 -->
<property name="stuNum" value="10001"/>
<property name="stuAge" value="12"/>
<!-- 字符串类型-->
<property name="weight" value="62.3"/>
</bean>

日期类型

  • 方式1:在property标签中通过ref引用Spring容器中的一个对象

    1
    2
    3
    4
    5
    6
    <bean id="date" class="java.util.Date"></bean>

    <bean id="stu" class="cc.gaojie.ioc.bean.Student" >
    <!-- 日期类型-->
    <property name="enterenceTime" ref="date"/>
    </bean>
  • 方式2:在property标签中添加子标签bean来指定对象

    1
    2
    3
    4
    5
    6
    <bean id="stu" class="cc.gaojie.ioc.bean.Student" >
    <!-- 日期类型-->
    <property name="enterenceTime">
    <bean class="java.util.Date"/>
    </property>
    </bean>

自定义类对象属性

  • 方式1:在property标签中通过ref直接引用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <bean id="cla" class="cc.gaojie.ioc.bean.Clazz">
    <property name="classId" value="2010"/>
    <property name="className" value="Java2010"/>
    </bean>

    <bean id="stu" class="cc.gaojie.ioc.bean.Student">
    <!-- 自定义对象类型-->
    <property name="clazz" ref="cla"/>
    </bean>
  • 方式2:在property标签中添加子标签bean来指定对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <bean id="stu" class="cc.gaojie.ioc.bean.Student">
    <!-- 自定义对象类型-->
    <property name="clazz">
    <bean class="cc.gaojie.ioc.bean.Clazz">
    <property name="classId" value="2010"/>
    <property name="className" value="Java2010"/>
    </bean>
    </property>
    </bean>

集合类型

List
  • List<String> List中的元素是字符串或者简单类型的封装类,可直接赋值。

    1
    2
    <!-- 方式一 -->
    <property name="hobbies" value="旅游,电影"/>
    1
    2
    3
    4
    5
    6
    7
    8
    <!-- 方式二 -->
    <property name="hobbies" >
    <list>
    <value>旅游</value>
    <value>电影</value>
    <value>Java</value>
    </list>
    </property>
  • List<Object> List中的元素是对象类型

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <!-- 方式一 -->
    <property name="hobbies" >
    <list>
    <bean class="cc.gaojie.ioc.bean.Book"/>
    <bean class="cc.gaojie.ioc.bean.Book"/>
    <bean class="cc.gaojie.ioc.bean.Book"/>
    <bean class="cc.gaojie.ioc.bean.Book"/>
    </list>
    </property>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <!-- 方式二 -->
    <bean id="book" class="cc.gaojie.ioc.bean.Book"/>

    <property name="hobbies" >
    <list>
    <ref bean="book"></ref> <!--引用容器中的bean-->
    <ref bean="book"></ref>
    </list>
    </property>
Set
1
2
3
4
5
<property name="sets">
<set>
<!--和list元素注入方式相同-->
</set>
</property>
Map
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<property name="maps">
<map>
<entry>
<key>
<value>k1</value>
</key>
<value>123</value>
</entry>
<entry>
<key>
<value>k2</value>
</key>
<value>456</value>
</entry>
</map>
</property>
Properties
1
2
3
4
5
6
<property name="properties">
<props>
<prop key="k1">aaa</prop>
<prop key="k2">bbb</prop>
</props>
</property>

构造方法注入

所谓构造方法注入,是指使用被Spring管理的类的构造器,来完成属性的赋值。

简单类型、字符串、对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Student {

private String stuNum;
private String stuName;
private String stuGender;
private int stuAge;
private double weight;
private Date enterenceTime; //入学日期
private Clazz clazz;

public Student(String stuNum, String stuName, String stuGender, int stuAge, double weight, Date enterenceTime, Clazz clazz) {
this.stuNum = stuNum;
this.stuName = stuName;
this.stuGender = stuGender;
this.stuAge = stuAge;
this.weight = weight;
this.enterenceTime = enterenceTime;
this.clazz = clazz;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<bean id="date" class="java.util.Date"></bean>

<bean id="stu" class="cc.gaojie.ioc.bean.Student">
<!-- index是被管理类中属性的索引。如果不指定index的值,注入时书写的顺序必须与类中属性的顺序一致 -->
<constructor-arg index="0" value="10001"/> <!--字符串类型-->
<constructor-arg index="2" value="女"/>
<constructor-arg index="1" value="张三"/>
<constructor-arg index="3" value="21"/> <!--简单类型-->
<constructor-arg index="4" value="62.5"/>
<constructor-arg index="5" ref="date"/> <!--对象类型-->
<constructor-arg index="6"> <!--对象类型-->
<bean class="cc.gaojie.ioc.bean.Clazz"></bean>
</constructor-arg>
</bean>

集合类型属性

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Student{
private List<String> hobbies;
private Set<String> sets;
private Map<String,Object> maps;
private Properties properties;

public Student(List<String> hobbies, Set<String> sets, Map<String, Object> maps, Properties properties) {
this.hobbies = hobbies;
this.sets = sets;
this.maps = maps;
this.properties = properties;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<bean id="stu1" class="cc.gaojie.ioc.bean.Student">
<!-- index是被管理类中属性的索引。如果不指定,则注入时书写的顺序必须与类中属性的顺序一致 -->
<constructor-arg index="0">
<list>
<value>11</value>
<value>22</value>
<value>33</value>
</list>
</constructor-arg>
<constructor-arg index="1">
<set>
<value>aa</value>
<value>bb</value>
<value>cc</value>
</set>
</constructor-arg>
<constructor-arg index="2">
<map>
<entry>
<key><value>key1</value></key>
<value>value1</value>
</entry>
<entry>
<key><value>key2</value></key>
<value>value2</value>
</entry>
</map>
</constructor-arg>
<constructor-arg index="3">
<props>
<prop key="k1">v1</prop>
<prop key="k2">v2</prop>
</props>
</constructor-arg>
</bean>

案例演示

以 set 方法注入为例,演示普通数据类型和集合数据类型的注入。

普通数据类型的注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class UserDaoImpl implements UserDao {

private String userName;
private int age;

public void setUserName(String userName) {
this.userName = userName;
}

public void setAge(int age) {
this.age = age;
}

@Override
public void save() {
System.out.println(userName+ "------" + age);
System.out.println("save running…………");
}


}
1
2
3
4
<bean id="userDao" class="cc.gaojie.dao.impl.UserDaoImpl" >
<property name="userName" value="高杰"/>
<property name="age" value="22"/>
</bean>
1
2
3
4
5
6
7
8
public class UserDaoDemo {
public static void main(String[] args) {
//加载Spring核心文件
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) app.getBean("userDao");
userDao.save();
}
}

集合数据类型的注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class User {

private String name;
private String addr;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getAddr() {
return addr;
}

public void setAddr(String addr) {
this.addr = addr;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class UserDaoImpl implements UserDao {

private List<String> strList;
private Map<String, User> userMap;
private Properties properties;

public void setStrList(List<String> strList) {
this.strList = strList;
}

public void setUserMap(Map<String, User> userMap) {
this.userMap = userMap;
}

public void setProperties(Properties properties) {
this.properties = properties;
}

@Override
public void save() {
System.out.println(strList);
System.out.println(userMap);
System.out.println(properties);
System.out.println("save running…………");
}


}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<bean id="user1" class="cc.gaojie.domain.User">
<property name="name" value="Tom"/>
<property name="addr" value="江夏"/>
</bean>

<bean id="user2" class="cc.gaojie.domain.User">
<property name="name" value="Jack"/>
<property name="addr" value="十堰"/>
</bean>

<bean id="userDao" class="cc.gaojie.dao.impl.UserDaoImpl" >
<property name="strList">
<list>
<value>aaa</value>
<value>bbb</value>
<value>ccc</value>
</list>
</property>

<property name="userMap">
<map>
<entry key="u1" value-ref="user1"></entry>
<entry key="u2" value-ref="user2"></entry>
</map>
</property>

<property name="properties">
<props >
<prop key="p1">ppp1</prop>
<prop key="p2">ppp2</prop>
<prop key="p3">ppp3</prop>
</props>
</property>

</bean>
1
2
3
4
5
6
7
8
public class UserDaoDemo {
public static void main(String[] args) {
//加载Spring核心文件
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) app.getBean("userDao");
userDao.save();
}
}

构造器注入

  1. 创建有参构造方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public class UserServiceImpl implements UserService {

    private UserDao userDao;

    public UserServiceImpl() {
    }

    public UserServiceImpl(UserDao userDao) {
    this.userDao = userDao;
    }

    @Override
    public void save() {
    userDao.save();
    }
    }
  2. 配置 Spring 容器调用有参构造时进行注入

    不配置默认调无参,但无参构造方法获取不到 UserDao 实例,userDao 为空无法注入给 UserService。

    1
    2
    3
    4
    5
    <bean id="userDao" class="cc.gaojie.dao.impl.UserDaoImpl"></bean>

    <bean id="userService" class="cc.gaojie.service.impl.UserServiceImpl">
    <constructor-arg name="userDao" ref="userDao"></constructor-arg>
    </bean>
  3. 从 Spring 容器中获得 UserService 进行操作

    1
    2
    3
    4
    5
    6
    7
    8
    public class UserDaoDemo {
    public static void main(String[] args) {
    //加载Spring核心文件
    ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserService userService = (UserService) app.getBean("userService");
    userService.save();
    }
    }