【Spring系列】自动注入(装配)
我们把 Spring 在 Bean 与 Bean 之间建立依赖关系的行为称为“装配”。
Spring 的 IOC 容器虽然功能强大,但它本身不过只是一个空壳而已,它自己并不能独自完成装配工作。需要我们主动将 Bean 放进去,并告诉它 Bean 和 Bean 之间的依赖关系,它才能按照我们的要求完成装配工作。
在前面的学习中,我们都是在 XML 配置中通过 和 中的 ref 属性,手动维护 Bean 与 Bean 之间的依赖关系的。
对于只包含少量 Bean 的应用来说,这种方式已经足够满足我们的需求了。但随着应用的不断发展,容器中包含的 Bean 会越来越多,Bean 和 Bean 之间的依赖关系也越来越复杂,这就使得我们所编写的 XML 配置也越来越复杂,越来越繁琐。
我们知道,过于复杂的 XML 配置不但可读性差,而且编写起来极易出错,严重的降低了开发人员的开发效率。为了解决这一问题,Spring 框架还为我们提供了“自动装配”功能。
Spring 自动装配(基于xml配置文件)
Spring 的自动装配功能可以让 Spring 容器依据某种规则(自动装配的规则,有五种),为指定的 Bean 从应用的上下文(AppplicationContext 容器)中查找它所依赖的 Bean,并自动建立 Bean 之间的依赖关系。而这一过程是在完全不使用任何 和 元素 ref 属性的情况下进行的。
Spring 的自动装配功能能够有效地简化 Spring 应用的 XML 配置,因此在配置数量相当多时采用自动装配降低工作量。
Spring 框架式默认不支持自动装配的,要想使用自动装配,则需要对 Spring XML 配置文件中 元素的 autowire 属性进行设置
Spring 共提供了 5 中自动装配规则,它们分别与 autowire 属性的 5 个取值对应

不使用自动装配(autowire=“no”)
autowire=“no” 表示不使用自动装配,此时我们必须通过 <bean> 元素的 <constructor-arg>和 <property> 元素的 ref 属性维护 Bean 的依赖关系
Dept部门类
public class Dept {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Dept{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
- 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
Employee员工类
public class Employee {
private Integer E_id;
private String name;
private Dept dept;
public Integer getE_id() {
return E_id;
}
public void setE_id(Integer e_id) {
E_id = e_id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Employee{" +
"E_id=" + E_id +
", name='" + name + '\'' +
", dept=" + dept +
'}';
}
}
- 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
- 36
- 37
- 38
autowire="no"
<?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">
<!--管理DEPT-->
<bean id="dept" class="com.liu.pojo.Dept">
<property name="id" value="1"/>
<property name="name" value="技术部"/>
</bean>
<!--管理员工-->
<bean id="employee" class="com.liu.pojo.Employee" autowire="no">
<property name="e_id" value="1"/>
<property name="name" value="李白"/>
<property name="dept" ref="dept"/>
</bean>
</beans>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
Test
public class AutoDITest {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
Employee employee = context.getBean("employee", Employee.class);
System.out.println(employee);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
结果
Employee{E_id=1, name='李白', dept=Dept{id=1, name='技术部'}}
- 1
按名称自动装配(autowire=“byName”)
autowire=“byName” 表示按属性名称自动装配,XML 文件中 Bean 的 id 或 name 必须与类中的属性名称相同。
<!--管理DEPT-->
<bean id="dept" class="com.liu.pojo.Dept">
<property name="id" value="1"/>
<property name="name" value="技术部"/>
</bean>
<!--管理员工-->
<bean id="employee" class="com.liu.pojo.Employee" autowire="byName">
<property name="e_id" value="1"/>
<property name="name" value="李白"/>
</bean>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
Employee{E_id=1, name='李白', dept=Dept{id=1, name='技术部'}}
- 1
如果名字不一样,比如改下dept的id,则就会注入不成功,部门为null
<!--管理DEPT-->
<bean id="dept1" class="com.liu.pojo.Dept">
<property name="id" value="1"/>
<property name="name" value="技术部"/>
</bean>
<!--管理员工-->
<bean id="employee" class="com.liu.pojo.Employee" autowire="byName">
<property name="e_id" value="1"/>
<property name="name" value="李白"/>
</bean>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
Employee{E_id=1, name='李白', dept=null}
- 1
按类型自动装配(autowire=“byType”)
autowire=“byType” 表示按类中对象属性数据类型进行自动装配。即使 XML 文件中 Bean 的 id 或 name 与类中的属性名不同,只要 Bean 的 class 属性值与类中的对象属性的类型相同,就可以完成自动装配。
<!--管理DEPT-->
<bean id="dept1" class="com.liu.pojo.Dept">
<property name="id" value="1"/>
<property name="name" value="技术部"/>
</bean>
<!--管理员工-->
<bean id="employee" class="com.liu.pojo.Employee" autowire="byType">
<property name="e_id" value="1"/>
<property name="name" value="李白"/>
</bean>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
现在虽然id不一样了,但是是按照类型进行注入的,需要com.liu.pojo.Dept类型的,去spring工厂里找,咦,找到了,就把找到这个bean注入给需要的bean,如果没找到,就无法注入
Employee{E_id=1, name='李白', dept=Dept{id=1, name='技术部'}}
- 1
如果同时存在多个相同类型的 Bean,则注入失败,并且引发异常。
IDEA还是很智能的,直接提示了,并且这样运行也会报错,因为spring也蒙蔽了,他也不知道要注入哪个bean了,他解决不了这个问题,就报错了

构造函数自动装配(autowire=“constructor”)
autowire=“constructor” 表示按照 Java 类中构造函数进行自动装配。
<!--管理DEPT-->
<bean id="dept1" class="com.liu.pojo.Dept">
<constructor-arg name="id" value="1"/>
<constructor-arg name="name" value="技术部"/>
</bean>
<!--管理员工-->
<bean id="employee" class="com.liu.pojo.Employee" autowire="constructor">
<constructor-arg index="0" value="1"/>
<constructor-arg index="1" value="李白"/>
</bean>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Employee{E_id=1, name='李白', dept=Dept{id=1, name='技术部'}}
- 1
默认的自动装配模式(autowire=“default”)
<!--管理DEPT-->
<bean id="dept1" class="com.liu.pojo.Dept">
<property name="id" value="1"/>
<property name="name" value="技术部"/>
</bean>
<!--管理员工-->
<bean id="employee" class="com.liu.pojo.Employee" autowire="default">
<property name="e_id" value="1"/>
<property name="name" value="李白"/>
</bean>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Employee{E_id=1, name='李白', dept=Dept{id=1, name='技术部'}}
- 1
Spring自动装配 (基于注解)
从 Java 5 开始,Java 增加了对注解(Annotation)的支持,它是代码中的一种特殊标记,可以在编译、类加载和运行时被读取,执行相应的处理。开发人员可以通过注解在不改变原有代码和逻辑的情况下,在源代码中嵌入补充信息。
Spring 从 2.5 版本开始提供了对注解技术的全面支持,我们可以使用注解来实现自动装配,简化 Spring 的 XML 配置。
Spring 通过注解实现自动装配的步骤如下:
- 引入依赖
- 开启组件扫描
- 使用注解定义 Bean
- 依赖注入
1. 引入AOP依赖
使用注解的第一步,就是要在项目中引入以下 Jar 包。
org.springframework.core-5.3.13.jar
org.springframework.beans-5.3.13.jar
spring-context-5.3.13.jar
spring-expression-5.3.13.jar
commons.logging-1.2.jar
spring-aop-5.3.13.jar
maven项目直接导入以下依赖坐标即可
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
- 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
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
2. 开启组件扫描
Spring 默认不使用注解装配 Bean,因此我们需要在 Spring 的 XML 配置中,通过 <context:component-scan> 元素开启 Spring Beans的自动扫描功能。开启此功能后,Spring 会自动从扫描指定的包(base-package 属性设置)及其子包下的所有类,如果类上使用了 @Component 注解,就将该类装配到容器中。
<?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">
<!--xmlns:context="http://www.springframework.org/schema/context" 注意别导错了-->
<!--开启组件扫描功能 扫描com.liu包下所有类是否添加了@Component注解-->
<context:component-scan base-package="com.liu"/>
</beans>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
注意:在使用 context:component-scan 元素开启自动扫描功能前,首先需要在 XML 配置的一级标签 中添加 context 相关的约束
3. 使用注解定义 Bean
Spring 提供了以下多个注解,这些注解可以直接标注在 Java 类上,将它们定义成 Spring Bean。

4. 基于注解方式实现依赖注入
我们可以通过以下注解将定义好 Bean 装配到其它的 Bean 中。

1.创建maven工程
2.导入相关依赖在pom.xm配置文件中
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<!--springmvc核心依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<!--servlet-api-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<!--jstl-->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.3</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--log4j-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
<!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
</dependencies>
- 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
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
3.在 com.liu.dao 包下,创建一个名为 UserDAO 的接口

public interface UserDAO {
void print();
}
- 1
- 2
- 3
4.在com.liu.dao.impl 包下,创建 UserDao 的实现类 UserDAOImpl

/*注解 @Repository 将这个dao层类交给spring容器管理
* 尽管我们并没有在spring.xml中进行相应配置,这里的字符串
* value就相当于spring.xml配置bean时的id属性,底层反射代理*/
@Repository(value = "userDAO")
public class UserDAOImpl implements UserDAO {
@Override
public void print() {
System.out.println("hello auto");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
5.在 com.liu.service 包下,创建一个名为 UserService 的接口

public interface UserService {
void out();
}
- 1
- 2
- 3
6.在 com.liu.service.impl 包下,创建 UserService 的实现类 UserServiceImpl
/*这里@Service注解用于标识他是业务层类,然后
* 添加此注解,它就会被spring容器所管理,value
* 属性还是同理*/
@Service(value = "userService")
public class UserServiceImpl implements UserService {
/*这里的@Resource注解是用于依赖注入的,以前我们就是通过配置
* 现在直接在需要的地方,添加相应注解,就实现对他的注入,简化了
* 配置文件的大小以及开发的繁琐,@Resource默认是按照类型进行注入的,
* 你也可以指定它的name属性,让他按照name进行注入,或者指定name和
* type这时,他会先按照name进行找,找不到在按照type进行查找,还找不到
* 就会报错了*/
@Resource
private UserDAO userDAO;
public UserDAO getUserDAO() {
return userDAO;
}
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
@Override
public void out() {
userDAO.print();
System.out.println("我来了");
}
}
- 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
7. 在 com.liu.controller 包下,创建一个名为 UserController 的类

什么时候给value呢,如果他被其他类需要,或者需要被main调用,就需要给value,就相当于我们在配置文件中给他了一个唯一标识id,然后工厂可以根据id拿到该bean,因为接下来要实例化它,所以给他添加了一个value属性
@Controller("userController")
public class UserController {
@Resource
private UserService userService;
public UserService getUserService() {
return userService;
}
public void setUserService(UserService userService) {
this.userService = userService;
}
public void doStr(){
userService.out();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
8.创建 Spring 配置文件 Beans.xml,配置内容如下
注意: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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--xmlns:context="http://www.springframework.org/schema/context" 注意别导错了-->
<!--开启组件扫描功能 扫描com.liu包下所有类是否添加了@Component注解-->
<context:component-scan base-package="com.liu"></context:component-scan>
</beans>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
9.测试
前端来一个请求,被springmvc拦截,交给了controller,然后controller被spring创建管理,controller的方法调用 service 层,service等去调用 dao 层,完成业务逻辑的处理,返回结果,然而spring为我们做了太多,对象的创建管理,虽然我们没有配置文件xml,但是我们通过注解的方式,注解传入了重要的信息,注解其实就是通过反射去创建对象,单例多例可以看设计模式,还有工厂模式,代理,动态代理,一下子全穿起来吧,是不是觉得豁然开朗,多学,重复写,这种领悟会越来越深刻,越来越清晰,就是在这种状态下进步的,ok
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserController userController = context.getBean("userController", UserController.class);
userController.doStr();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
输出
hello auto
我来了
- 1
- 2
OK,到这就结束了,紧张又刺激,哈哈,拜拜了,下次见,如果还想见的话记得关注我哦!嘻嘻🤪,在线厚脸皮

文章来源: blog.csdn.net,作者:周棋洛ყ ᥱ ᥉,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/m0_53321320/article/details/123572797
- 点赞
- 收藏
- 关注作者
评论(0)