> [TOC]
# 1、Spring
***
## 1.1、简介
- Spring:春天------>给软件行业带来了春天!
- 2002,首次推出了Spring框架的雏形:interface21框架!
- Spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日发布了1.0正式版。
- **Rod Johnson**,Spring Framework创始人,著名作者。很难想象Rod Johnson的学历,真的让好多人大吃一惊,他是悉尼大学的博士,然而他的专业不是计算机,而是音乐学。
- Spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架!
- SSH:Struct2 + Spring + Hibernate!
- SSM:SpringMVC + Spring + Mybatis!
官网:https://spring.io/projects/spring-framework#overview
官方下载地址:https://repo.spring.io/release/org/springframework/spring/
GitHub:https://github.com/spring-projects/spring-framework
```xml
org.springframework
spring-webmvc
5.3.8
org.springframework
spring-jdbc
5.3.8
```
## 1.2 优点
- Spring是一个开源的免费的框架(容器)!
- Spring是一个轻量级的、非入侵式的框架!
- 控制反转(IOC),面向切面编程(AOP)!
- 支持事务的处理,对框架整合的支持!
**总结一句话:Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架!**
## 1.3、组成

## 1.4 拓展
现代化的Java开发!说白了就是基于Spring的开发!
- Spring Boot
- 一个快速开发的脚手架
- 基于SpringBoot可以快速的开发单个微服务
- 约定大于配置
- Spring Cloud
- SpringCloud是基于SpringBoot实现的
因为现在大多数公司都在使用SpringBoot进行快速开发,学习SpringBoot的前提,需要完全掌握Spring以及SpringMVC!**承上启下的作用!**
**弊端:发展了太久之后,违背了原来的理念!配置十分繁琐,人称:“配置地狱”**
# 2、IOC理论推导
***
1. UserDao 接口
```java
public interface UserDao {
void getUser();
}
```
2. UserDaoImpl 实现类
```java
public class UserDaoImpl implements UserDao {
public void getUser() {
System.out.println("默认获取用户数据");
}
}
```
3. UserService 业务接口
```java
public interface UserService {
void getUser();
}
```
4. UserServiceImpl 业务实现类
```java
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImpl();
public void getUser() {
userDao.getUser();
}
}
```
5. 测试
```java
public class MyTest {
public static void main(String[] args) {
//用户实际调用的是业务层,dao层他们不需要接触!
UserService userService = new UserServiceImpl();
userService.getUser();
}
}
```
在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改原代码!如果程序代码量十分大,修改一次的成本代价十分昂贵!

我们使用一个Set接口实现,已经发生了革命性的变化!

```java
private UserDao userDao;
// 利用set进行动态实现值的注入!
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
```
- 之前,程序是主动创建对象!控制权在程序员手上!
- 使用了set注入后,程序不再具有主动性,而是变成了被动的接收对象!
这种思想,从本质上解决了问题,我们程序猿不用再去管理对象的创建了。系统的耦合性大大降低~,可以更加专注的在业务的实现上!这是IOC的原型!
**IOC本质**
**控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,**也有人认为DI只是IoC的另一种说法。没有IoC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
**控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。**
# 3、HelloSpring
***
1. 新建一个maven项目,编写实体类
```java
public class Hello {
private String str;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
@Override
public String toString() {
return "Hello{" +
"str='" + str + '\'' +
'}';
}
}
```
2. 编写xml配置文件
```xml
```
3. 测试
```java
public class MyTest {
public static void main(String[] args) {
//获取Spring的上下文对象!
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//我们的对象现在都在Spring中的管理了,我们需要使用,直接去里面取出来就可以!
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello.toString());
}
}
```
**思考问题?**
- Hello对象是谁创建的?
Hello对象是由Spring创建的。
- Hello对象的属性是怎么设置的?
Hello对象的属性是由Spring容器设置的。
这个过程就叫控制反转:
**控制**:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用Spring后,对象是由Spring来创建的。
**反转**:程序本身不创建对象,而变成被动的接收对象。
**依赖注入**:就是利用set方法来进行注入的。
IOC是一种编程思想,由主动的编程变成被动的接收。
可以通过new ClassPathXmlApplicationContext去浏览一下底层源码。
**OK,到了现在,我们彻底不用在程序中去改动了,要实现不同的操作,只需要在xml配置文件中进行修改,所谓的IOC,一句话搞定:对象由Spring来创建,管理,装配!**
# 4、IOC创建对象的方式
***
1. 使用无参构造创建对象,默认!
2. 假设我们要使用有参构造创建对象。
1. 下标赋值
```xml
```
2. 类型
```xml
```
3. 参数名
```xml
```
总结:在配置文件加载的时候,容器中管理的所有对象就已经初始化了!只有一份!!!
```java
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user = (User) context.getBean("user");
user.setName("123");
User user2 = (User) context.getBean("user");
System.out.println(user == user2); // true
System.out.println(user2.getName()); // 123
```
# 5、Spring配置
***
## 5.1 别名
```xml
```
## 5.2 Bean配置
```xml
```
## 5.3 import
这个import。一般用于团队开发使用,它可以将多个配置文件,导入合并为一个。
假设,现在项目中有多个人开发,这三个人负责不同的类开发,不同的类需要注册在不同的bean中,我们可以利用import将所有人的beans.xml合并为一个总的!
- 张三
- 李四
- 王五
- applicationContext.xml
```xml
```
使用的时候,直接使用总的配置就可以了。
# 6、依赖注入
***
## 6.1 、构造器注入
前面已经介绍过,参考**4、IOC创建对象的方式**
## 6.2 、Set方式注入【重点】
- 依赖注入:Set注入
- 依赖:bean对象的创建依赖于容器!
- 注入:bean对象中的所有属性,由容器来注入!
【环境搭建】
1. 复杂类型
```java
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
```
2. 真实测试对象
```java
public class Student {
private String name;
private Address address;
private String[] books;
private List hobbies;
private Map card;
private Set games;
private String wife;
private Properties info;
}
```
3. beans.xml
```xml
```
4. 测试类
```java
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = (Student) context.getBean("student");
System.out.println(student.getName());
}
}
```
5. 完善注入信息
```xml
红楼梦
西游记
水浒传
三国演义
打篮球
看电影
敲代码
LOL
COC
BOB
20191029
102.0913.524.4585
黑心白莲
123456
```
## 6.3 、拓展方式注入
我们可以使用p命名空间和c命名空间进行注入
官方解释:

使用:
```xml
```
测试:
```java
@Test
public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
User user = context.getBean("user",User.class);
System.out.println(user);
User user2 = context.getBean("user2",User.class);
System.out.println(user2);
}
```
注意点:p命名空间和c命名空间不能直接使用,需要导入xml约束
```xml
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
```
## 6.4 、bean的作用域

1. 单例模式(Spring默认机制)
```xml
```
2. 原型模式:每次从容器中get的时候,都会产生一个新对象!
```xml
```
3. 其余的request、session、application、这些只能在web开发中用到!
# 7、bean的自动装配
***
- 自动装配是Spring满足bean依赖的一种方式
- Spring会在上下文中自动寻找,并自动给bean装配属性
在Spring中有三种装配的方式:
1. 在xml中显式的配置;
2. 在java中显式配置;
3. 隐式的自动装配bean【重要】
## 7.1 、测试
环境搭建:创建项目,一个人有两个宠物!
```xml
```
## 7.2、 ByName自动装配
```xml
```
## 7.3 、ByType自动装配
```xml
```
小结:
- ByName的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致!
- ByType的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致!
## 7.4 、使用注解实现自动装配
jdk1.5支持的注解,Spring2.5就支持注解了!
要使用注解须知:
1. 导入约束
2. 配置注解的支持
```xml
```
**@Autowired**
直接在属性上使用即可!也可以在set方法上使用!
使用Autowried我们就可以不用编写set方法了,前提是你这个自动配置的属性在IOC(Spring)容器中存在,且符合名字ByName!
**科普:**
> @Nullable 字段标记了了这个注解,说明这个字段可以为null;
```java
public @interface Autowired {
boolean required() default true;
}
```
测试代码
```java
public class People {
//如果显式定义了Autowired的required属性为false,说明这个对象可以为null,否则不允许为空
@Autowired(required = false)
private Cat cat;
@Autowired
private Dog dog;
private String name;
}
```
如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候,我们可以使用@Qualifier(value = “xxx”)去配置@Autowired的使用,指定一个唯一的bean对象注入!
```java
public class People {
@Autowired
@Qualifier(value = "cat111")
private Cat cat;
@Autowired
@Qualifier(value = "dog222")
private Dog dog;
private String name;
}
```
**@Resource**
```java
public class People {
@Resource
private Cat cat;
@Resource
private Dog dog;
}
```
小结:
@Resource和@Autowired的区别:
- 都是用来自动装配的,都可以放在属性字段上
- @Autowired通过byType的方式实现,而且必须要求这个对象存在!【常用】
- @Resource默认通过byName的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错!【常用】
- 执行顺序不同:@Autowired通过byType的方式实现。@Resource默认通过byName的方式实现
# 8、使用注解开发
***
在Spring4之后,要使用注解开发,必须要保证aop的包导入了

使用注解需要导入约束,配置注解的支持!
```xml
```
> **Bean的实现**
我们之前都是使用 bean 的标签进行bean注入,但是实际开发中,我们一般都会使用注解!
1. 配置扫描那些包下的注解
```xml
```
2. 在指定包下编写类,增加注释
```java
@Component("user")
// 相当于配置文件中
public class User {
public String name = "秦疆";
}
```
3. 测试
```java
@Test
public void test(){
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("beans.xml");
User user = (User) applicationContext.getBean("user");
System.out.println(user.name);
}
```
> **属性注入**
使用注解注入属性
1. 可以不用提供set方法,直接在直接名上添加@value("值")
```java
@Component("user")
// 相当于配置文件中
public class User {
@Value("秦疆")
// 相当于配置文件中
public String name;
}
```
2. 如果提供了set方法,在set方法上添加@value("值")
```java
@Component("user")
public class User {
public String name;
@Value("秦疆")
public void setName(String name) {
this.name = name;
}
}
```
> **衍生注解**
我们这些注解,就是替代了在配置文件当中配置步骤而已!更加的方便快捷!
**@Component三个衍生注解**
为了更好的进行分层,Spring可以使用其它三个注解,功能一样,目前使用哪一个功能都一样。
- @Controller: web层
- @Service:service层
- @Repository:dao层
写上这些注释,就相当于将这个类交给Spring管理装配了!
> **自动装配注解**
在Bean的自动装配已经讲过了,可以回顾!
- @Autowired:自动装配通过类型,名字。如果Autowired不能唯一自动装配上属性,则需要通过@Qualifier(value = "xxx")去配置。
- @Nullable 字段标记了了这个注解,说明这个字段可以为null;
- @Resource:自动装配通过名字,类型。
> **作用域**
@scope
- singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。
- prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收
```java
@Component
@Scope("singleton")
public class User {
//相当于
@Value("白莲")
public String name;
}
```
> **小结**
**xml与注解:**
- xml更加万能,适用于任何场合!维护简单方便
- 注解不是自己类使用不了,维护相队复杂!
**xml与注解最佳实践:**
- xml用来管理bean;
- 注解只负责完成属性的注入;
- 我们在使用的过程中,只需要注意一个问题:必须让注解生效,就需要开启注解的支持
```xml
```
作用:
- 进行注解驱动注册,从而使注解生效
- 用于激活那些已经在spring容器里注册过的bean上面的注解,也就是显示的向Spring注册
- 如果不扫描包,就需要手动配置bean
- 如果不加注解驱动,则注入的值为null!
# 9、使用Java的方式配置Spring
***
JavaConfig 原来是 Spring 的一个子项目,它通过 Java 类的方式提供 Bean 的定义信息,在 Spring4 的版本, JavaConfig 已正式成为 Spring4 的核心功能 。
实体类
```java
//这里这个注解的意思,就是说明这个类被Spring接管了,注册到了容器中
@Component
public class User {
private String name;
public String getName() {
return name;
}
@Value("黑心白莲") //属性注入值
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
```
配置文件
```java
// 这个也会Spring容器托管,注册到容器中,因为它本来就是一个@Component
// @Configuration代表这是一个配置类,就和我们之前看的beans.xml
@Configuration
@ComponentScan("com.kuang.pojo")
// 引入多个配置类,合并
@Import(KuangConfig2.class)
public class KuangConfig {
// 注册一个bean,就相当于我们之前写的一个bean标签
// 这个方法的名字,就相当于bean标签中id属性
// 这个方法的返回值,就相当于bean标签中的class属性
@Bean
public User user(){
return new User(); // 就是返回要注入到bean的对象!
}
}
```
测试类
```java
public class MyTest {
public static void main(String[] args) {
//如果完全使用了配置类方式去做,我们就只能通过 AnnotationConfig 上下文来获取容器,通过配置类的class对象加载!
ApplicationContext context = new AnnotationConfigApplicationContext(KuangConfig.class);
User user = context.getBean("user", User.class);
System.out.println(user.getName());
}
}
```
这种纯Java的配置方式,在SpringBoot中随处可见!