第一章 初识Spring
1.1 Spring简介
-
Spring是一个为简化企业级开发而生的开源框架。
-
Spring是一个IOC(DI)和AOP容器框架。
-
IOC全称:Inversion Of Control【控制反转】
- 控制反转:将对象控制权由程序员自己管理反转给Spring框架管理
-
DI全称:Dependency Injection【依赖注入】
- 依赖注入:Spring管理对象与对象之间的依赖关系
-
AOP全称:Aspect-Oriented Programming【面向切面编程设计】
- OOP:Object-Oriented Programming【面向对象编程设计】
-
Spring官网:https://spring.io
1.2 搭建Spring框架
-
导入jar包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
-
创建POJO public class Employee {
private Integer id;
private String lastName;
private String email;
private Double salary;
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", lastName='" + lastName + '\'' +
", email='" + email + '\'' +
", salary=" + salary +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
public Employee() {
}
public Employee(Integer id, String lastName, String email, Double salary) {
this.id = id;
this.lastName = lastName;
this.email = email;
this.salary = salary;
}
}
-
编写配置文件
-
名称:applicationContext.xml【beans.xml或spring.xml】 -
位置:src/main/resouces -
示例代码 <?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">
<bean id="empChai" class="com.atguigu.pojo.Employee">
<property name="id" value="1001"></property>
<property name="lastName" value="chails"></property>
<property name="email" value="chails@163.com"></property>
<property name="salary" value="1000.5"></property>
</bean>
</beans>
-
使用核心类库【容器对象:ApplicationContext】 @Test
public void testSpring(){
ApplicationContext ioc =
new ClassPathXmlApplicationContext("applicationContext.xml");
Employee empChai = (Employee) ioc.getBean("empChai");
System.out.println("empChai = " + empChai);
}
1.3 Spring基本特性
- 非侵入式:基于Spring开发的应用中的对象可以不依赖于Spring的API。
- 容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期。
- 组件化:Spring实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用XML和Java注解组合这些对象。
- 一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上Spring 自身也提供了表述层的SpringMVC和持久层的JDBCTemplate)。
第二章 Spring中getBean()三种方式
-
getBean(String beanId):通过beanId获取对象
-
getBean(Class clazz):通过Class获取对象
-
getBean(String beanId,Class clazz):通过beanId&Class获取对象
第三章 Spring中IOC底层实现
- Spring底层就是一个对象工厂【BeanFactory】
- BeanFactory结构
- BeanFactory【面向Spring框架】
- …
- ApplicationContext【面向程序员】
- ConfigurableApplicationContext【是ApplicationContext的扩展对象,提供关闭&刷新容器对象的方法】
- …
- ClassPathXmlApplicationContext:基于类路径检索xml文件
- FileSystemXmlApplicationContext:基于系统路径检索xml文件
第四章 Spring中DI【依赖注入】三种方式
JavaSE为属性赋值
- 通过setXXX()方法,为属性赋值
- 通过构造器,为属性赋值
- 反射,为属性赋值
4.1 setter注入
4.2 构造注入
4.3 p名称注入
第五章 Spring中依赖注入【数值问题】
5.1 字面量数值
-
字面量
- 数据类型:基本类型&包装类型&String
- 语法结构:value属性或value标签
-
CDATA区
-
语法:<![CDATA[]]> -
作用:解决xml中特殊字符 -
示例代码
<select id="selectEmpAndDeptByEmpIdAssociationStep" resultMap="empAndDeptAssociationStepRm">
<![CDATA[
select
id,
last_name,
email,
salary,
dept_id
from
tbl_employee
where
id = #{empId}
]]>
</select>
<bean id="empChai" class="com.dudu.pojo.Employee">
<property name="id" value="1001"></property>
<property name="lastName">
<value><![CDATA[<chailaoshi>]]></value>
</property>
<property name="salary" value="10000.5"></property>
<property name="email">
<value>chailaoshi@163.com</value>
</property>
</bean>
5.2 外部bean
-
注意:使用外部bean支持级联属性赋值,如级联属性数值更改,也会影响外部bean属性数值 -
示例代码
<bean id="dept1" class="com.dudu.pojo.Dept">
<property name="deptId" value="101"></property>
<property name="deptName" value="研发部门"></property>
</bean>
<bean id="empJing" class="com.dudu.pojo.Employee">
<property name="id" value="1004"></property>
<property name="lastName" value="jingjign"></property>
<property name="email" value="jingjing@163.com"></property>
<property name="salary" value="10000.5"></property>
<property name="dept" ref="dept1"></property>
<property name="dept.deptName" value="教学部门"></property>
</bean>
5.3 内部bean
-
内部Bean:在一个bean中完整的定义另一个bean -
注意:内部bean不会直接装配到IOC容器中 -
示例代码
<bean id="empLi" class="com.dudu.pojo.Employee">
<property name="id" value="1005"></property>
<property name="lastName" value="jinlong"></property>
<property name="email" value="longge@163.com"></property>
<property name="salary" value="10000.5"></property>
<property name="dept">
<bean class="com.dudu.pojo.Dept">
<property name="deptId" value="102"></property>
<property name="deptName" value="教务部门"></property>
</bean>
</property>
</bean>
5.4 装配list
<bean id="dept1" class="com.dudu.pojo.Dept">
<property name="deptId" value="1"></property>
<property name="deptName" value="教学部"></property>
<property name="empList">
<list>
<ref bean="empId"></ref>
<ref bean="empId1"></ref>
</list>
</property>
</bean>
<util:list id="empList">
<ref bean="empId"></ref>
<ref bean="empId1"></ref>
</util:list>
<bean id="dept11" class="com.dudu.pojo.Dept">
<property name="deptId" value="1"></property>
<property name="deptName" value="教学部"></property>
<property name="empList" ref="empList"></property>
</bean>
5.5 装配map
<bean id="dept2" class="com.dudu.pojo.Dept">
<property name="deptId" value="1"></property>
<property name="deptName" value="教学部"></property>
<property name="empMap">
<map>
<entry>
<key>
<value>111</value>
</key>
<ref bean="empId"></ref>
</entry>
<entry>
<key>
<value>222</value>
</key>
<ref bean="empId1"></ref>
</entry>
</map>
</property>
</bean>
<util:map id="empMap">
<entry>
<key>
<value>111</value>
</key>
<ref bean="empId"></ref>
</entry>
<entry>
<key>
<value>222</value>
</key>
<ref bean="empId1"></ref>
</entry>
</util:map>
<bean id="dept22" class="com.dudu.pojo.Dept">
<property name="deptId" value="1"></property>
<property name="deptName" value="教学部"></property>
<property name="empMap" ref="empMap"></property>
</bean>
Test
public void testSpringGetBean(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Employee empId3 = context.getBean("empId3", Employee.class);
System.out.println(empId3);
System.out.println("======================");
Dept dept1 = context.getBean("dept11", Dept.class);
System.out.println(dept1);
System.out.println("========================");
Dept dept2 = context.getBean("dept22", Dept.class);
System.out.println(dept2);
}
导入Maven工程
第六章 Spring管理第三方Bean【DruidDataSource】
6.1 使用Spring管理DruidDataSource步骤
-
导jar包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
-
编写外部属性文件:db.properties db.driverClassName=com.mysql.cj.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/db220227?serverTimeZone=UTC
db.username=root
db.password=12356
-
编写spring配置文件
- 加载外部属性文件
- 装配DruidDataSource
<?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:property-placeholder location="classpath:db.properties"></context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${db.driverClassName}"></property>
<property name="url" value="${db.url}"></property>
<property name="username" value="${db.username}"></property>
<property name="password" value="${db.password}"></property>
</bean>
</beans>
测试
public void testDruid() throws SQLException {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext_druid.xml");
DruidDataSource dataSource = context.getBean("dataSource", DruidDataSource.class);
DruidPooledConnection connection = dataSource.getConnection();
System.out.println(connection);
}
第七章 Spring中FactoryBean【工厂bean】
7.1 FactoryBean的概述
- Spring中有两种类型的bean
- 一种是普通bean
- 另一种是工厂bean【可参与对象的创建过程中】
7.2 FactoryBean使用
public class MyFactoryBean implements FactoryBean<Dept> {
@Override
public Dept getObject() throws Exception {
Dept dept = new Dept(101,"研发部门");
return dept;
}
@Override
public Class<?> getObjectType() {
return Dept.class;
}
}
<?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">
<bean id="dept" class="com.dudu.factory.MyFactoryBean"></bean>
</beans>
@Test
public void testFactoryBean(){
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext_factoryBean.xml");
Dept dept = context.getBean("dept", Dept.class);
System.out.println("dept = " + dept);
}
第八章 Spring中bean的作用域【重点】
8.1 语法
- 在bean标签中,添加scope属性,设置bean的作用域
- 作用:决定这个bean是单实例的还是多实例的。
8.2 bean的四个作用域
类别 | 说明 |
---|
singleton | 在Spring的IOC容器中仅存在一个Bean实例 | prototype | 每次调用getBean方法都返回一个新的Bean实例 | request | 每次HTTP请求都会创建一个新的Bean实例,该作用域仅适用于WebApplicationContext环境 | session | 同一个Session会话共享一个Bean实例,该作用域仅适用于WebApplicationContext环境 |
- singleton:单例
- prototype:多例
- 调用getBean()方法时,spring创建Dept对象
- request作用域
- 表示bean在当前请求中有效,离开当前请求失效
- 如何高效区分是否为当前请求:看浏览器地址栏
- 地址栏无变化:表示当前请求
- 地址栏有变化:表示不在当前请求
- session作用域
- 表示bean在当前会话中有效,离开当前会话失效
- 如何高效区分是否在当前会话:看浏览器
- 如浏览器未关闭&未更换,默认即为当前会话
- 如浏览器关闭或更换,不为当前会话
<?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">
<bean id="dept" class="com.dudu.pojo.Dept" scope="prototype">
<property name="deptId" value="101"></property>
<property name="deptName" value="研发部门"></property>
</bean>
</beans>
第九章 Spring中bean的生命周期&后置处理器
9.1 Spring中bean的生命周期
① 通过构造器或工厂方法创建bean实例
② 为bean的属性设置值和对其他bean的引用
③ 调用bean的初始化方法
④ bean可以使用了
⑤ 当容器关闭时,调用bean的销毁方法
Dept.java
省略了其他方法
public class Dept {
private Integer deptId;
private String deptName;
private List<Employee> empList;
private Map<Integer,Employee> empMap;
public void init() {
System.out.println("3、初始化");
}
public void destroy(){
System.out.println("5、销毁");
}
public void setDeptId(Integer deptId) {
System.out.println("2、设置bean");
this.deptId = deptId;
}
public Dept() {
System.out.println("1.无参构造");
}
}
applicationContext.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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="lifeCycle" class="com.dudu.pojo.Dept" init-method="init" destroy-method="destroy">
<property name="deptId" value="001"></property>
<property name="deptName" value="教育部"></property>
</bean>
<bean class="com.dudu.processor.MyBeanPostProcessor"></bean>
</beans>
Test
public void testLifeCycle(){
ConfigurableApplicationContext context=new ClassPathXmlApplicationContext("applicationContext_lifecycle.xml");
Dept lifeCycle = context.getBean("lifeCycle", Dept.class);
System.out.println("4.使用 "+lifeCycle);
context.close();
}
9.2 设置生命周期的初始化&销毁bean对象语法
- 在bean标签中添加以下两个属性即可
- init-method:设置初始化方法
- destroy-method:设置销毁方法
9.3 后置处理器【BeanPostProcessor】
public class MyBeanPostProcessor implements BeanPostProcessor {
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("bean 初始化之前!!!");
return bean;
}
@Nullable
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("bean 初始化之后!!!");
return bean;
}
}
<bean class="com.dudu.processor.MyBeanPostProcessor"></bean>
第十章 Spring中基于xml方式自动&手动装配
10.1 手动装配
- 手动装配:以value或ref的方式明确指定属性值都是手动装配。
10.2 自动装配
第十一章 Spring中基于注解管理bean【非常重要】
约束>【注解>配置】>代码
Spring中使用注解步骤
- 导入aop的jar包
- 开启组件扫描
11.1 使用注解管理【装配】bean
- 常用注解
- @Component:标识一个普通组件
- @Repository:标识一个持久化层组件
- @Service:标识一个业务逻辑层组件
- @Controller:标识一个【表示层、表述层、控制层】组件
- 注意
- Spring本质上无法区分不同层使用的注解,本质上:四个注解都是被@Component标识的,之所以拆分为四个注解的原因:提高代码可读性。
- 默认类名首字母小写,作为bean的id
- 使用注解的value属性可以定义bean的id,如只使用value属性时,value关键字可省略
11.2 使用注解管理【装配】bean中属性
-
@Autowired注解【重要】
-
位置:
- 属性上【装配方式:反射注入】
- setXXX()方法上【装配方式:set注入】
- 构造器上【装配方式:构造注入】
-
作用:为对象中属性【非字面量】自动装配 -
@Autowired装配规则【原理】【面试题】:
-
先按照byType匹配:
-
如唯一匹配则,装配成功 -
如匹配多个:再通过byName进行唯一筛选
-
筛选成功【属性名=beanId】,则装配成功 -
筛选失败【属性名!=beanId】,按照byType风格报错 available: expected single matching bean but found 2: employeeDao,employeeDao2 -
如匹配0个:
- 注意required属性值问题
- true:报如下错误
- available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
- false:不会报错,不会装配,默认值为:null【继续使用当前属性,会出现空指针异常】
-
属性:required
- 作用:表示当前注解标识的属性是否必须自动装配
- true【默认值】:表示被@Autowired注解标识的属性,必须自动装配,如未装配数值,会报错
- false:标识被@Autowired注解标识的属性,不必须自动装配,如未装配数值,不会报错,不会装配,默认值为:null【继续使用当前属性,会出现空指针异常】
-
@Qualifier注解
- 作用:配合@Autowired注解使用,主要用于将容器中指定bean的Id设置到当前属性中
- 注意:@Qualifier注解不能单独使用,需要配合@Autowired使用
-
@Value注解
第十二章 组件扫描
使用注解必须,开启组件扫描
12.1 包含扫描
<context:component-scan base-package="com.dudu.annotation"
use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
<context:include-filter type="assignable" expression="com.atguigu.annotation.controller.EmployeeController"/>
</context:component-scan>
12.2 排除扫描
<context:component-scan base-package="com.dudu.annotation">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
12.3 常用使用场景
<context:component-scan base-package="com.dudu.annotation"></context:component-scan>
第十三章 完全注解开发【0xml配置文件】
完全注解开发:指的是使用配置类代替配置文件
-
完全注解开发使用步骤
- 新建配置类
- 使用@Configuration注解标识当前类,是一个配置类
- 使用@ComponentScan标识组件扫描包
- 使用AnnotationConfigApplicationContext实现类代替【ClassPathXmlApplicationContext】
-
示例代码
@Configuration
@ComponentScan(basePackages = "com.dudu.annotation")
public class SpringConfig {
}
@Test
public void test0Xml(){
ApplicationContext context =
new AnnotationConfigApplicationContext(SpringConfig.class);
Employee employee = context.getBean("employee", Employee.class);
System.out.println("employee = " + employee);
EmployeeDaoImpl employeeDao = context.getBean("employeeDao", EmployeeDaoImpl.class);
System.out.println("employeeDao = " + employeeDao);
EmployeeServiceImpl employeeService = context.getBean("employeeService", EmployeeServiceImpl.class);
System.out.println("employeeService = " + employeeService);
EmployeeController employeeController = context.getBean("employeeController", EmployeeController.class);
System.out.println("employeeController = " + employeeController);
}
第十四章 Spring整合Junit4
14.1 为什么需要整合?
14.2 Spring整合Junit4步骤
-
添加jar包支持【spring-test-5.3.1.jar】 <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.1</version>
</dependency>
-
指定Spring的配置文件的路径【Spring会为测试类自动底层创建容器对象】 -
指定Spring环境下运行Junit4的运行器
@ContextConfiguration(classes = SpringConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class TestSpringAndJunit4 {
@Autowired
private EmployeeService employeeService;
@Test
public void testSpringAndJunit(){
System.out.println(employeeService);
employeeService.deleteEmployee(1);
}
第十五章 代理模式
15.1 代理模式概述
-
生活中
-
程序中代理
-
实现思路
- 实现Calc类基本方法【add()、sub()、mul()、div()】
- 添加日志功能
-
发现问题
-
日志功能代码比较分散
- 解决方案:将日志功能提取到工具类中【MyLogging】
-
日志功能代码比较混乱
-
解决方案
|