文章目录
- 先看这部分
- 1. Spring简介
- 1.1 Spring框架优点
- 1.2 Spring体系结构
- 2. 核心功能IOC
- 2.1 IOC简介
- 2.2 IOC创建对象
- 2.2.1 单例模式对象
- 2.2.2 多例模式对象
- 2.3 获取容器信息
- 2.3.1 对象数量
- 2.3.2 对象名称
- 2.4 基于XML的DI
- 2.4.1 set注入
- 2.4.2 构造注入
- 2.4.3 引用类型自动注入
- byName
- byType
- 2.4.4 多个XML文件创建
- 2.5 基于注解的DI
- 2.5.1 组件扫描器
- 2.5.2 @Component
- @Repository
- @Service
- @Controller
- 2.5.3 @Value
- 2.5.4 @Autowired
- @Qualifier
- 2.5.5 @Resource
- 2.5.6 注解信息配置文件
先看这部分
- 使用Spring之前需要导入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.9</version>
</dependency>- 在Spring中,java基本数据类型和String类型都是简单类型
1. Spring简介
Spring框架有很多,各有各的功能特点,有spring、springmvc、springboot等等
Spring出现在2002年左右,解决企业开发的难度,减轻对项目模块之间的管理,类和类之间的管理,来帮助开发人员创建对象,管理对象之间的关系。核心技术是 ioc(控制反转) 、 aop(面向切面编程)。Spring能实现模块之间,类之间的解耦合。
- 一个框架,核心技术是ioc,aop,实现解耦合
- 一个容器,容器中存放的是java对象,需要做的是把对象放入到容器中
1.1 Spring框架优点
- 轻量
jar包很小,3M左右
- 针对接口编程,解耦合
- AOP编程的支持
- 方便集成各种优秀框架
可和其他框架一起使用,降低项目开发难度
1.2 Spring体系结构

2. 核心功能IOC
2.1 IOC简介
IOC(Inversion of Control):控制反转,这是一个理论,概念,思想
把对象的创建,赋值,管理工作都交给代码之外的容器实现,也就是对象的创建时有其他外部资源完成
IOC能够实现业务对象之间的解耦合,例如service和dao对象之间的解耦合。
控制
创建对象,对象的属性赋值,对象之间的关系管理
反转
将管理对象的控制权交给容器
容器
一个服务器软件,一个框架
为什么使用IOC?
减少对代码的改动,也能实现不同的功能,实现解耦合
IOC的体现
Servlet对象的创建和调用都是有web容器完成,我们开发人员并没有创建Servlet对象
IOC技术实现
DI(Dependency Injection):依赖注入,这个是IOC的技术实现
只需要在程序中提供要使用的对象名称即可,对象创建和调用等等交给容器实现
Spring是使用DI实现了IOC的功能,Spring底层创建对象,使用的是反射机制。
2.2 IOC创建对象
创建Spring配置文件
<!--
Spring的配置文件
1. beans: 根标签,Spring把java对象当做bean
2. spring-beans.xsd 是约束文件,和mybatis指定的dtd文件一样
-->
<?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">
<!--
Spring创建对象
声明bean,就是告诉Spring要创建某个类的对象
id: 对象的自定义名称,唯一值,Spring通过这个名称找到对象
class: 类的全限定名称(不能是接口,因为Spring是反射机制创建对象,必须使用类)
Spring相当于完成 Service myService = new ServiceImpl();
Spring是把创建好的对象放入到map中,Spring框架有一个map存放对象
springMap.put(id, 对象)
例如,springMap.put("myService", new ServiceImpl());
-->
<bean id="myService" class="com.company.impl.ServiceImpl" />
</beans>
创建并使用对象
@Test
public void testIoc() {
String config = "beans.xml";
// 创建Spring容器的对象,ApplicationContext
// ApplicationContext: Spring容器,通过容器获取对象
// ClassPathXmlApplicationContext: 从类路径中加载Spring的配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext(config);
// 从容器中获取对象
Service service = (Service) ac.getBean("myService");
// 使用容器创建好的对象
service.doSome();
}ApplicationContext ac = new ClassPathXmlApplicationContext(config);
在这阶段读取配置文件,遇到bean就会创建对象,将其以(id,对象)的Map形式存放
也就是创建所有的对象
Spring创建对象默认是调用无参数构造方法。
2.2.1 单例模式对象
<bean id="myService" class="com.company.impl.ServiceImpl" />这样的默认是单例模式,也就是说一个类中只有一个对象,该对象在创建容器的时候就会被创建
2.2.2 多例模式对象
<bean id="myService" class="com.company.impl.ServiceImpl" scope="prototype"/>这样是多例模式创建对象,该对象在执行 getBean() 时创建,并且是多个对象
2.3 获取容器信息
2.3.1 对象数量
// 获取容器内对象数量
int num = ac.getBeanDefinitionCount();
System.out.println("容器中有" + num + "个对象");
2.3.2 对象名称
// 获取容器内对象名称
String[] names = ac.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
2.4 基于XML的DI
注入就是属性赋值。
测试类
public class Student {
private int stuId;
private String stuName;
private ServiceImpl service;
public void setStuId(int stuId) {
System.out.println("setStuId执行");
this.stuId = stuId;
}
public void setStuName(String stuName) {
System.out.println("setStuName执行");
this.stuName = stuName;
}
public void setService(ServiceImpl service) {
this.service = service;
}
@Override
public String toString() {
return "Student{" +
"stuId=" + stuId +
", stuName='" + stuName + '\'' +
", service=" + service +
'}';
}
}
2.4.1 set注入
set注入的原理是调用类的setter方法,所以叫做set注入
name:对象属性名
value:对象简单类型属性值
ref:对象复杂类型引用
- 使用set注入一定要有setter方法
- set注入先是调用无参数构造,再调用setter方法
- 只是调用setter方法。
- set+属性首字母大写 组成方法名,通过反射机制调用
简单类型注入
<bean id="student" class="com.company.impl.Student">
<property name="stuId" value="10001" />
<property name="stuName" value="张三" />
</bean>
复杂类型注入
<bean id="student" class="com.company.impl.Student">
<property name="stuId" value="10001" />
<property name="stuName" value="张三" />
<property name="service" ref="myService1" />
</bean>
<bean id="myService1" class="com.company.impl.ServiceImpl" />
2.4.2 构造注入
构造注入的原理是调用类的有参数构造方法,创建对象的同时,在构造方法中给属性赋值
name:构造方法形参名
index:构造方法参数的位置,0,1, …
value:形参类型是简单类型的属性值
ref:形参类型是复杂类型的属性值
任意位置:
<bean id="student2" class="com.company.impl.Student">
<constructor-arg name="stuId" value="10002"/>
<constructor-arg name="stuName" value="李四"/>
<constructor-arg name="service" ref="myService1"/>
</bean>
<bean id="student4" class="com.company.impl.Student">
<constructor-arg index="0" value="10002"/>
<constructor-arg index="1" value="李四"/>
<constructor-arg index="2" ref="myService1"/>
</bean>
指定位置(0,1,2,…):
<bean id="student3" class="com.company.impl.Student">
<constructor-arg value="10002"/>
<constructor-arg value="李四"/>
<constructor-arg ref="myService1"/>
</bean>
2.4.3 引用类型自动注入
引用类型就是除简单类型之外的复杂类型
Spring框架根据某些规则可以给引用类型赋值,不用手动给引用类型赋值。
byName
java类中引用类型的属性名和Spring容器中的配置文件的id相同,且数据类型相同
语法
<bean id="xx" class="yyy" autowire="byName">
简单类型赋值
</bean>
实例:
public class Student {
private int stuId;
private String stuName;
private ServiceImpl service;
...
}<bean id="service" class="com.company.impl.ServiceImpl" />
<bean id="student" class="com.company.impl.Student" autowire="byName">
<property name="stuId" value="10001" />
<property name="stuName" value="张三" />
</bean>
byType
java类中引用属性的类型和的class值属于同源关系
同类关系
继承关系
实现关系
如果有多个同源关系的bean,则会报错。
语法
<bean id="xx" class="yyy" autowire="byType">
简单类型赋值
</bean>
实例:
public class Student {
private int stuId;
private String stuName;
private Service service;
...
}<bean id="myService1" class="com.company.impl.ServiceImpl" />
<bean id="student" class="com.company.impl.Student" autowire="byType">
<property name="stuId" value="10001" />
<property name="stuName" value="张三" />
</bean>
2.4.4 多个XML文件创建
在实际开发中,并不建议将多个bean写到同一个Spring配置文件当中。
可以按照模块功能分类等等方式,创建多个Spring配置文件。
其中还要创建一个主配置文件,其中导入了各个Spring配置文件。
主配置文件
<?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">
<import resource="classpath:spring-student.xml"/>
<import resource="classpath:spring-service.xml"/>
</beans>
2.5 基于注解的DI
使用注解的步骤:
- 需要加入Maven的依赖spring-context,这个在一开始就需要加入,实际上注解需要spring-aop依赖,只不过spring-context顺便将其导入了进来
- 在类中加入spring注解
- spring配置文件中,加入组件扫描器的标签,说明注解在项目中的位置。
2.5.1 组件扫描器
组件扫描器的声明时放在spring的主配置文件当中
- base-package:指定注解在项目中的包名
- component-scan
Spring会扫描遍历base-package指定的包,找出包中的相关注解,按照注解的功能创建对象,或赋值
<?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 https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.company.anno"/>
</beans>
2.5.2 @Component
创建对象,等同于的功能,声明在类的上面
- value
对象的名称,bean的id值
package com.company.anno;
import org.springframework.stereotype.Component;
@Component(value="myTeacher")
public class Teacher {
private int id;
private String name;
...
}
等同于:
<bean name="myTeacher" class="com.company.anno.Teacher"/>- 省略value,默认值是首字母小写的类名。
- 省略value,声明对象名称
@Component("myTeacher")Spring中和@Component基本功能一致,创建对象的注解还有:
@Repository
持久层类
dao实现类
表示创建dao对象,dao对象是能访问数据库的
@Service
业务层类
service的实现类
创建service对象,service对象是做业务处理的,还有事务等功能
@Controller
控制器类
控制器对象
接收用户提交的参数,显示请求的处理结果
以上三个注解的使用语法和@Component一样。都能创建对象,但是这三个注解还有额外的功能
@Repository、@Service、@Controller是给项目的对象分层的。
2.5.3 @Value
简单类型属性赋值
- value:String类型,表示简单类型的属性值
- 属性定义的上面,无需set方法,推荐使用
- set方法的上面
package com.company.anno;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("myTeacher")
public class Teacher {
// @Value(value="10001")
@Value("10001")
private int id;
@Value("张三")
private String name;
...
}
2.5.4 @Autowired
引用类型属性赋值
- 自动注入原理,支持byName、byType
- 默认是byType自动注入
- 属性定义的上面,无需set方法,推荐使用
- set方法的上面
- required=true
引用类型赋值失败,程序报错并终止执行
- required=false
引用类型赋值失败,程序正常执行,引用类型是null
- required默认是true
package com.company.anno;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("myTeacher")
public class Teacher {
@Value("10001")
private int id;
@Value("张三")
private String name;
@Autowired
private School school;
...
}package com.company.anno;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("mySchool")
public class School {
@Value("清华大学")
private String name;
@Value("北京市")
private String addr;
...
}
@Qualifier
与@Autowired搭配使用,相当于@Autowired的byName模式
其中是对象id
- @Qualifier与@Autowired顺序可不一致,但是必须两个一起用
package com.company.anno;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("myTeacher")
public class Teacher {
@Value("10001")
private int id;
@Value("张三")
private String name;
@Autowired
@Qualifier("mySchool")
private School school;
}package com.company.anno;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("mySchool")
public class School {
@Value("清华大学")
private String name;
@Value("北京市")
private String addr;
...
}
2.5.5 @Resource
来自jdk中的注解,Spring对其提供了支持
对引用类型属性进行赋值
- 自动注入原理,byName、byType,默认是byName
- 如果使用byName未找到,则使用byTye查找
- 属性定义的上面,无需set方法,推荐使用
- set方法的上面
若只使用byName方式,需要增加一个属性 name
name值是bean的id
package com.company.anno;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component("myTeacher")
public class Teacher {
@Value("10001")
private int id;
@Value("张三")
private String name;
@Resource
private School school;
...
}@Resource(name="mySchool")
private School school;package com.company.anno;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("mySchool")
public class School {
@Value("清华大学")
private String name;
@Value("北京市")
private String addr;
...
}
2.5.6 注解信息配置文件
创建配置文件:
teaId=10002
teaName=李四
在Spring主配置文件中添加文件路径:
<context:property-placeholder location="classpath:anno/teacher.properties" file-encoding="GBK"/>
使用配置文件信息:
package com.company.anno;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component("myTeacher")
public class Teacher {
@Value("${teaId}")
private int id;
@Value("${teaName}")
private String name;
@Resource(name="mySchool")
private School school;
...
}
















