代码地址: https://github.com/Zhuyaqiang/spring-study
目录
1 Spring
1.1 简介
- Spring框架的目的是解决企业应用开发的复杂性, 使现有的技术更加容易使用, 整合了现有的技术框架
- SSM: SpringMVC + Spring + Mybatis
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
1.2 优点
- Spring是一个开源的免费的框架(容器)
- Spring是一个轻量级的、非入侵式的框架
- 控制反转(IOC), 面向切面编程(AOP)
- 支持事务的处理, 对框架整合的支持
1.3 组成
1.4 扩展
- SpringBoot
- 一个快速开发的脚手架
- 快速开发单个微服务
- 约定大于配置
- SpringCloud
- 基于SpringBoot实现
2 IoC理论推导
2.1 示例
- UserDao接口
- UserDaoImpl实现类
- UserService业务接口
- UserServiceImpl业务实现
原业务中, 用户的需求可能会影响原来的代码, 需要根据用户的需求去修改原代码
使用Set接口实现, 发生了革命性的变化
private UserDao userDao;
// 利用set动态实现值的注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
- 之前程序是主动创建对象, 控制权在程序员手上.
- 使用set注入后, 程序不再具有主动性, 而是变成了被动地接收对象
从本质上解决了问题, 程序员不用管理对象的创建, 系统的耦合性大大降低, 可以专注业务实现. 是IoC的原型
2.2 IoC本质
- 控制反转IoC是一种设计思想, 依赖注入DI是实现IoC的一种方法, 所谓控制反转就是获得以来对象的方式反转了
- 控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式. 在Spring实现控制反转的是IoC容器, 其实现方法是依赖注入
3 HelloSpring
3.1 控制反转
- 传统应用程序的的对象是由程序本身控制创建的, 使用Spring后, 对象是由Spring来创建的
- 程序本身不创建对象, 而变成被动地接收对象
- 依赖注入是使用set进行注入
- IoC: 对象由Spring来创建, 管理, 装配
4 IoC创建对象的方式
-
默认使用无参构造创建对象
-
使用有参构造创建独享
-
下标赋值
<bean id="user" class="com.zyq.pojo.User"> <constructor-arg index="0" value="zyq"></constructor-arg> </bean>
-
类型赋值(不建议使用)
<bean id="user" class="com.zyq.pojo.User"> <constructor-arg type="java.lang.String" value="zzz"></constructor-arg> </bean>
-
参数名赋值
<bean id="user" class="com.zyq.pojo.User"> <constructor-arg name="name" value="yqq"></constructor-arg> </bean>
-
-
总结: 配置文件加载的时候, 容器中管理的对象就已经初始化了, 且只有一份
5 Spring配置
5.1 别名
<!-- 别名, 可以通过别名获得对象-->
<alias name="user" alias="dfsfdsfsd"></alias>
5.2 Bean的配置
<!--
id: bean的唯一标识符, 相当于对象名
class: bean对象所对应的全限定名: 包名 + 类名
name: 也是别名, 而且name可以同时取多个别名
-->
<bean id="userT" class="com.zyq.pojo.UserT" name="user2 u2, u3; u4">
<property name="name" value="啦啦啦"></property>
</bean>
5.3 import
一般用于团队开发使用, 可以将多个配置文件, 导入合并为一个
假设项目中有多人开发, 负责不同的类开发, 不同的类需要注册在不同的bean中, 可以利用import将所有人的beans.xml合并为一个总的配置文件
<import resource="beans.xml"></import>
<import resource="beans2.xml"></import>
6 依赖注入
6.1 构造器注入
6.2 Set方式注入(重点)
- 依赖注入: Set注入
- 依赖: bean对象的创建依赖于容器
- 注入: bean对象中的所有属性, 由容器来注入
【环境搭建】
对应spring-04-di
-
复杂类型
public class Address { private String address; public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } }
-
真实测试环境
public class Student { private String name; private Address address; private String[] books; private List<String> hobbys; private Map<String, String> card; private Set<String> games; private Properties info; private String wife; }
-
beans.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" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="student" class="com.zyq.pojo.Student"> <!-- 第一种, 普通值注入, value--> <property name="name" value="zyq"></property> </bean> </beans>
-
测试类
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.getAddress()); } }
6.3 拓展方式注入
可以使用p命名空间和c命名空间进行注入
<!-- p命名空间注入, set注入 可以直接注入属性的值 properties-->
<bean id="user" class="com.zyq.pojo.User" p:name="zyq" p:age="18"></bean>
<!--c命名空间注入, 通过构造器注入constructs-args-->
<bean id="user2" class="com.zyq.pojo.User" c:age="18" c:name="qqq"></bean>
注意点: p命名和c命名空间, 需要导入xml约束
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
6.4 bean的作用域
-
单例模式(Spring默认机制):
<bean id="user2" class="com.zyq.pojo.User" c:age="18" c:name="qqq" scope="singleton"></bean>
-
原型模式: 每次从容器中get的时候, 都会产生一个新对象
<bean id="user2" class="com.zyq.pojo.User" c:age="18" c:name="qqq" scope="prototype"></bean>
-
其余的和request, session, application. 只能在web开发中使用到
7 Bean的自动装配
- 自动装配是Spring满足bean依赖的一种方式
- Spring会在上下文中自动寻找, 并自动给bean装配属性
在Spring中有三种装配方式
- xml中显式配置
- java中显式配置
- 隐式的自动装配bean(重要)
7.1 测试
对应spring-05-Autowired
7.2 ByName自动装配
<!--
byName: 会自动在容器上下文中查找, 和自己对象set方法后面值对应的beanid
-->
<bean id="people" class="com.zyq.pojo.People" autowire="byName">
<property name="name" value="zyq"></property>
</bean>
7.3 ByType自动装配
和ByName类似, 会自动在容器上下文中查找, 和自己对象属性类型相同的bean, 必须保证类型全局唯一
小结:
- byName的时候, 需要保证所有bean的id唯一, 并且这个bean需要和自动注入的属性的set方法的值一致
- byType的时候, 需要保证所有bean的class唯一, 并且这个bean需要和自动注入的属性的类型一致
7.4 使用注解自动装配
使用注解须知:
-
导入约束, context约束
-
配置注解的支持,
<context:annotation-config/>**
(重要)**<?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 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config/> </beans>
@Autowired可以直接在属性上使用, 也可以在set方法上使用
Autowired使用反射机制, 因此可以不用编写set方法, 前提是自动装配的属性在IoC(Spring)容器中存在, 且符合名字byName
补充:
1. `@Nullable`字段标注了这个注解说明这个字段可以为null
@Autowired(required = false)
默认为true, 如果显式定义了属性为false, 说明这个对象可以为null 否则不允许为null- 若@Autowired自动装配环境比较复杂(bean中多个同类对象), 自动装配无法通过一个注解
@Autowired
完成的时候, 可以使用@Qualifier(value="xxx")
来指定
@Resource注解也有自动装配的功能
7.4.1 小结
@Resource
和@Autowired
的异同:
- 都是用来自动装配的, 都可以放在属性字段上
@Autowired
默认通过byType方式实现, 而且必须要求这个对象存在@Resource
默认通过byName的方式实现, 如果找不到名字, 则通过byType实现, 如果两个方式都找不到就报错
8 使用注解开发
在Spring4之后, 要使用注解开发, 必须要保证aop的包导入了
8.1 bean
@Component
放在类上说明类被Spring管理了
8.2 属性如何注入
@Component
public class User {
public String name;
@Value("zzz")
public void setName(String name) {
this.name = name
}
}
8.3 衍生注解
@Component
有几个衍生注解, 在web开发中, 会按照mvc三层架构分层
- dao:
@Repository
- service:
@Service
- controller:
@Controller
功能都代表将某个类注册到Spring容器中, 装配Bean
8.4 自动装配
- @AutoWired: 通过类型自动装配. 如果Autowired不能通过名字唯一自动装配上属性, 则需要通过@Qualifier(value="xxx")
- @Nullable: 字段标记了这个注解说明这个字段可以为null
- @Resource: 通过名字, 类型自动装配
8.5 作用域
@Scope("prototype")
8.6 小结
xml与注解
- xml更加万能, 适用于各种场合, 维护简单方便
- 注解 不是自己的类使用不了, 维护相对复杂
xml与注解最佳实践:
-
xml用来管理bean
-
注解用来进行属性注入
-
使用过程中, 只需要注意一个问题: 想让注解生效, 就要开启注解支持
<!-- 指定要扫描的包, 这个包下的注解就会生效--> <context:component-scan base-package="com.zyq.pojo"></context:component-scan> <!-- 开启注解支持--> <context:annotation-config></context:annotation-config>
9.使用Java的方式配置Spring
完全不使用Spring的xml配置
实体类:
@Component
public class User {
// 属性注入值
@Value("zyq")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
配置文件类:
@Configuration // 也会被Spring容器托管, 注册到容器中, 因为这个注解本来就是一个@Component, @Configuration代表这是一个配置类, 相当于beans.xml
@ComponentScan("com.zyq.pojo")
@Import(MyConfig2.class)
public class MyConfig {
// 注册一个bean, 相当于配置文件xml中的bean标签
// 方法名相当于bean标签中的id属性
// 方法的返回值, 相当于bean标签中的class属性
@Bean
public User getUser() {
return new User(); // 就是返回要注入到bean的对象
}
}
测试类:
public class MyTest {
public static void main(String[] args) {
// 如果完全使用类配置类方式, 就只能通过AnnotationConfig上下文来获取容器, 通过配置类的class对象加载
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
User user = (User) context.getBean("getUser");
System.out.println(user.getName());
}
}
纯Java的配置方式, 在SpringBoot中随处可见