Spring小总结

Spring简介

  • 概念
    在这里插入图片描述
  • 优势
    在这里插入图片描述

问题引入

编译器依赖&运行时依赖

在这里插入图片描述

工厂模式解耦

1
2
通过上面的JDBC驱动案例,下面我们来改造平时我们的案例。把`编译器依赖`改为`运行时依赖`
【如果AccountDaoImpl AccountServiceImpl两个类不存在,编译器也不会报错,运行时才会】

在这里插入图片描述

IOC概念

Inversion Of Control控制反转
原本我们要new创建对象的活,现在不需要我们创建了。创建对象的控制权交给了工厂。
在这里插入图片描述

IOC入门

改造工厂模式解耦

使用Spring来改造上面的工厂模式解耦示例
上面的BeanFactory.javabean.properties就可以删除了。

  1. 引入依赖
    1
    2
    3
    4
    5
    6
    7
    <dependencies>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.0.2.RELEASE</version>
    </dependency>
    </dependencies>
  2. 在resources目录下创建bean.xml文件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <?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 id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"></bean>

    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>
    </beans>
  3. 测试
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public static void main(String[] args) {
    //1.获取核心容器对象【加载类路径下的bean.xml】
    ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
    //2.根据id获取Bean对象【两种方式都可】
    IAccountDao accountDao = ac.getBean("accountDao", IAccountDao.class);
    IAccountService accountService = (IAccountService)ac.getBean("accountService");

    System.out.println(accountDao);// com.itheima.dao.impl.AccountDaoImpl@29774679
    System.out.println(accountService);// com.itheima.service.impl.AccountServiceImpl@3ffc5af1
    }

ApplicationContext三个常用的实现类

在这里插入图片描述

ApplicationContext与BeanFactory创建对象的时机

在这里插入图片描述

Bean的三种创建方式

这里是XML的三种创建方式。
还可以使用@Controller @Service @Repository指定类来创建@Bean指定方法返回值创建

在这里插入图片描述

Bean的作用范围

在这里插入图片描述

Bean的生命周期

在这里插入图片描述

依赖注入(DI)

简介

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
依赖注入:【它是spring框架核心ioc的具体实现。】
Dependency Injection(简称DI)
IOC的作用:
降低程序间的耦合(依赖关系)
依赖关系的管理:
以后都交给spring来维护
在当前类需要用到其他类的对象,由spring为我们提供,我们只需要在配置文件中说明
依赖关系的维护:
就称之为依赖注入。

依赖注入:
能注入的数据:有三类
基本类型和String
其他bean类型(在配置文件中或者注解配置过的bean)
复杂类型/集合类型
注入的方式:有三种
第一种:使用构造函数提供
第二种:使用set方法提供
第三种:使用注解提供

三种方式

  1. 构造函数注入
    在这里插入图片描述
  2. set方法注入
    简单类型
    在这里插入图片描述
    复杂类型
    在这里插入图片描述
  3. 注解注入,参考@Autowired @Qualifier @Resource @Value

XML方式改造JDBC

在这里插入图片描述

JdbcTemplate的CRUD

在这里插入图片描述

注解

配置

需要先配置bean.xml文件,才能使用注解

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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
http://www.springframework.org/schema/context/spring-context.xsd">

<!--告知spring在创建容器时要扫描的包,配置所需要的标签不是在beans的约束中,
而是一个名称为context名称空间和约束中-->
<context:component-scan base-package="com.itheima"></context:component-scan>
</beans>

创建对象的

相当于:<bean id="" class="">

1
2
3
4
5
6
7
8
9
10
11
@Component:
作用:用于把当前类对象存入spring容器中
属性:
value:用于指定bean的id。
【当我们不写时,它的默认值是当前类名,且首字母改小写。】
@Controller:一般用在表现层
@Service: 一般用在业务层
@Repository:一般用在持久层
以上三个注解他们的作用和属性与Component是一模一样。
他们三个是spring框架为我们提供明确的三层使用的注解,使我们的三层对象更加清晰。
不属于三层中的话,才用到Component。

在这里插入图片描述

注入数据的

【相当于:<property name="" ref=""> <property name="" value="">

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
Autowired:
作用:默认按照类型查找,若存在多个相同类型的Bean,再按照名称查找。
若不存在,报错,因为默认要求依赖对象必须存在。可以使用@Autowired(required = false)

出现位置:
可以是构造函数,成员变量,Setter方法
细节:
在使用注解注入时,set方法就不是必须的了。
Qualifier:
作用:在按照类中注入的基础之上再按照名称注入。
它在给类成员注入时不能单独使用(配合Autowired使用)。
但是在给方法参数注入时可以
属性:
value:用于指定注入bean的id。
Resource
作用:默认按照名称查找,若存在多个相同名称的Bean,再按照类型查找。与Autowired刚好相反
出现位置:
可以是类,成员变量,方法上
属性:
name:用于指定bean的id。
以上三个注入都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现。
另外,集合类型的注入只能通过XML来实现。

Value
作用:用于注入基本类型和String类型的数据
属性:
value:用于指定数据的值。它可以使用spring中SpEL(也就是spring的el表达式)
SpEL的写法:${表达式}
EL表达式的三个地方:JSP中(四大作用域中找),Mybatis中(字符串),Spring注解中()
  • Autowired的查找原理
    在这里插入图片描述
  • Qualifier作用于变量或方法参数。Resource的用法
    在这里插入图片描述

改变作用范围的

【相当于:<bean id="" class="" scope="">

1
2
3
4
5
6
7
Scope(不指定,默认单例)
作用:用于指定bean的作用范围
【只能作用方法或类上@Target({ElementType.TYPE, ElementType.METHOD})】
属性:
value:指定范围的取值。
取值:singleton prototype request session globalsession
常用:singleton prototype

在这里插入图片描述

生命周期相关的

【相当于:<bean id="" class="" init-method="" destroy-method="" />

1
2
3
4
PreDestroy
作用:用于指定销毁方法
PostConstruct
作用:用于指定初始化方法

在这里插入图片描述

其他注解

【用法可以参考下面的纯注解改造JDBC

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
Configuration
作用:指定当前类是一个配置类
细节:当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写。
ComponentScan
作用:用于通过注解指定spring在创建容器时要扫描的包
属性:
value:它和basePackages的作用是一样的,都是用于指定创建容器时要扫描的包。
我们使用此注解就等同于在xml中配置了:
<context:component-scan base-package="com.itheima"></context:component-scan>
Bean
作用:用于把当前方法的返回值作为bean对象存入spring的ioc容器中
属性:
name:用于指定bean的id。当不写时,默认值是当前方法的名称
细节:
当我们使用注解配置方法时,如果方法有参数,spring框架会去容器中查找有没有可用的bean对象。
查找的方式和Autowired注解的作用是一样的【先找类型,再找变量名】
Import
作用:用于导入其他的配置类
属性:
value:用于指定其他配置类的字节码。
当我们使用Import的注解之后,有Import注解的类就父配置类,而导入的都是子配置类
PropertySource
作用:用于指定properties文件的位置
属性:
value:指定文件的名称和路径。
关键字:classpath,表示类路径下
两个效果相同:
@PropertySource("classpath:jdbcConfig.properties")
@PropertySource("jdbcConfig.properties")

改造Junit

1
2
3
4
5
6
7
8
9
10
11
使用Junit单元测试:测试我们的配置
Spring整合junit的配置
1、导入spring整合junit的jar(坐标)
2、使用Junit提供的一个注解把原有的main方法替换了,替换成spring提供的
@RunWith(SpringJUnit4ClassRunner.class)
3、告知spring的运行器,spring和ioc创建是基于xml还是注解的,并且说明位置
@ContextConfiguration
locations:指定xml文件的位置,加上classpath关键字,表示在类路径下
classes:指定注解类所在地位置

当我们使用spring 5.x版本的时候,要求junit的jar必须是4.12及以上

在这里插入图片描述

纯注解改造JDBC

在这里插入图片描述

动态代理实现事务控制

动态代理可参考Java动态代理实现的两种方式

  • 错误分析(多个连接,多个事务)
    在这里插入图片描述
  • 代码实现
    在这里插入图片描述

AOP

全称是Aspect Oriented Programming 即:面向切面编程。

应用场景

场景一: 记录日志
场景二: 监控方法运行时间 (监控性能)
场景三: 权限控制
场景四: 缓存优化 (第一次调用查询数据库,将查询结果放入内存对象, 第二次调用, 直接从内存对象返回,不需要查询数据库 )
场景五: 事务管理 (调用方法前开启事务, 调用方法后提交关闭事务 )

相关术语

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
+ Joinpoint(连接点)【被invoke执行的方法】
所谓连接点是指那些被拦截到的点。
在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点。
+ Pointcut(切入点)【被增强的连接点】
所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义
+ Advice(通知/增强)【在切入点的哪里执行】
所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。
通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
+ Aspect(切面)【切入点和通知的一段代码】
是切入点和通知的结合。
+ Target(目标对象)【被代理的对象】
代理的目标对象。
+ Proxy(代理)【代理对象】
一个类被 AOP 织入增强后,就产生一个结果代理类。
+ Weaving(织入)【原对象变成代理对象的过程】
是指把增强应用到目标对象来创建新的代理对象的过程。
spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。

在这里插入图片描述

要明确的事

1
2
3
4
5
6
我们要做的:
把公共代码抽取出来,制作成通知。
声明切入点与通知的关系,即配置切面。

Spring框架:
监控切入点方法,一旦执行,则使用代理机制,动态创建代理对象,将通知的功能织入。

XML方式使用

1
2
3
4
5
6
7
8
9
10
1、通知类配置成Bean,交给spring来管理
2、使用aop:config标签表明开始AOP的配置
3、使用aop:aspect标签表明配置切面
id属性:是给切面提供一个唯一标识【随便起,一般起有意义的】
ref属性:是指定通知类bean的Id。
4、在aop:aspect标签的内部使用对应标签来配置通知的类型
我们现在示例是让printLog方法在切入点方法执行之前之前:所以是前置通知
aop:before:表示配置前置通知
method属性:用于指定Logger类中哪个方法是前置通知
pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强
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
切入点表达式的写法:
关键字:execution(表达式)
表达式:
访问修饰符 返回值 包名.包名.包名.类名.方法名(参数列表)
标准的表达式写法:
public void com.itheima.service.impl.AccountServiceImpl.saveAccount()
访问修饰符可以省略
void com.itheima.service.impl.AccountServiceImpl.saveAccount()
返回值可以使用通配符,表示任意返回值
* com.itheima.service.impl.AccountServiceImpl.saveAccount()
包名可以使用通配符,表示任意包。但是有几级包,就需要写几个*.
* *.*.*.*.AccountServiceImpl.saveAccount())
包名可以使用..表示当前包及其子包
* *..AccountServiceImpl.saveAccount()
类名和方法名都可以使用*来实现通配
* *..*.*()
参数列表:
可以直接写数据类型:
基本类型直接写名称 int
引用类型写包名.类名的方式 java.lang.String
可以使用通配符表示任意类型,但是必须有参数
可以使用..表示有无参数均可,有参数可以是任意类型
全通配写法:
* *..*.*(..)

实际开发中切入点表达式的通常写法:
切到业务层实现类下的所有方法
* com.itheima.service.impl.*.*(..)
  • 简单实现前置增强打印日志案例
    在这里插入图片描述
  • 提取切入点,演示环绕增强
    在这里插入图片描述

注解方式使用

  • 注解AOP,演示前置增强环绕增强同时使用。
    在这里插入图片描述
  • 改造纯注解实现AOP
    在这里插入图片描述
  • 注解AOP:注意:注解AOP的最终增强会在后置增强或异常增强前执行。
    在这里插入图片描述

AOP控制事务

XML实现

注解实现

事务控制

1
2
3
4
5
6
声明式事务也是基于AOP来实现的。
对于前置增强:开启事务,可以写在获取连接时设置手动提交。
对于后置增强:可以写在后置增强或异常增强里面。
对于后置增强或异常增强:可以用于判断,来简化为一条语句。

所以这四条通知,可以合并为一个事务通知。

XML方式

  • spring中基于XML的声明式事务控制配置步骤
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    1、配置事务管理器
    2、配置事务的通知
    此时我们需要导入事务的约束 tx名称空间和约束,同时也需要aop的
    使用tx:advice标签配置事务通知
    属性:
    id:给事务通知起一个唯一标识
    transaction-manager:给事务通知提供一个事务管理器引用
    3、配置AOP中的通用切入点表达式
    4、建立事务通知和切入点表达式的对应关系
    5、配置事务的属性
    是在事务的通知tx:advice标签的内部
    关于事务可参考事务
    在这里插入图片描述

注解方式

  • spring中基于注解 的声明式事务控制配置步骤
    1
    2
    3
    1、配置事务管理器
    2、开启spring对注解事务的支持
    3、在需要事务支持的地方使用@Transactional注解
    在这里插入图片描述

编程式(了解)

【为什么不用这种?就是因为每个Dao处理,都需要把逻辑写在重写的那个execute方法中】
在这里插入图片描述

Spring5

  1. Spring5的JDK版本>=1.8,Tomcat版本>=8.5【JDK1.8反射创建对象要比1.7快】
    在这里插入图片描述
  2. @NonNull 注解和@Nullable 注解的使用
    用 @Nullable(可空) 和 @NotNull(不可空) 注解来显示表明可为空的参数和以及返回值。
    这样就够在编译的时候处理空值而不是在运行时抛出 NullPointerExceptions。