spring 是什么 ?
spring 是一个轻量级的资源整合框架,就是将很多的资源(自己的对象,第三方整合的对象,连接池等)整合在一起,进行科学的应用,主要目的是解决在开发时业务逻辑层和DAO(持久层)或其他层的耦合问题。同时Spring框架还可以基于用户设计管理对象与对象的依赖关系,以降低对象与对象之间的直接耦合,提高程序的可维护性和可扩展性。
Spring设计理念:Spring是基于OOP(面向对象)通过IOC(控制反转) 来管理对象,实现对象之间降低耦合。同时也提供了AOP(面向切面)以动态非侵入的方式增强目标方法的功能。
Spring的核心:从上面Spring的设计理念来看,Spring的核心就是IOC,AOP。Spring的组建如下图:
Spring Core 提供了核心容器的基本组成部分,提供了控制反转(Inversion of Control,IOC),和依赖注入Dependency Injection,DI)的功能。
Spring Beans 提供了BeanFactory , 也是简单工厂模式的一个实现,被Spring管理的对象就是Bean。
Spring Context 是对Core的一层封装,提供了一种以框架访问对象的方法。
Spring AOP 提供了面向切面的编程。可以降低代码之间的耦合度,也可以以面向切面实现拦截器等功能。
Spring JDBC 提供了JDBC抽象层,主要是用来简化JDBC。
Spring Test 主要是为了测试使用 支持Junit 对Spring中的组件进行单元测试
IOC简绍:IOC (控制反转) 就是将创建对象的权利交给框架,让框架创建对象和管理对象,概念就是将对象的控制权交给框架,从代码本身交给了外部容器。(如下图)
IOC 的实现原理就是基于工厂模式通过反射机制来创建对象 和 管理对象
对于IOC来说最重要的就是容器,容器管理着Bean的生命周期,控制着Bean的依赖注入。
在Spring中BeanFactory和ApplicationContext是Spring两大核心接口,都可以当做Spring的容器,其中ApplicationContext是BeanFactory的子接口。
BeanFactory和ApplicationContext的区别:
加载方式不同 :
BeanFactory是使用延迟加载,就是需要对象时实例化对象。
ApplicationContext而是在容器启动时就创建好所有的对象,这样做的好处就是便于检查依赖是否注入的问题,让问题出现在容器启动时,当你用到对象时对象已经创建好了,同时也提高了性能。但是提高性能的同时也消耗了内存空间,使程序启动较慢。
依赖关系:BeanFactory是Spring的最底层的接口,包含了Bean的定义,Bean的加载,Bean的实例化,Bean的生命周期等。
ApplicationContext是BeanFactory的一个实现,除了有BeanFactory的功能时,还提供了额为的功能,比如说继承了MessageSource,因此支持国际化。载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。
提供在监听器中注册bean的事件。
简单来说:
BeanFactory可以理解为是一个HashMap Key来存储Bean的名字,Value来存储这个Bean的实例化,通常只提供了注册和获取两个方法,就是想当与Map中的Put和Get功能。我们叫他为“低级容器”
ApplicationContext 是一个“高级容器”,他依赖于BeanFactory,同时还继承了许多其他的接口,所以功能比较丰富,比如说在抽象类AbstractApplicationContext中就提供了refresh方法 , 也是我们常用的一个方法 ,就是用来重新加载所有的Bean。
Spring AOP 简绍:
AOP 是什么 ?
AOP是一种设计思想 ,它是对OOP(面向对象) 的一种补充和完善,它是通过预编译方式和运行时动态代理方式,在不修改源码的状态下对原有代码的一种加强和扩展的技术。
AOP与OOP字面意思相近,但其实两者完全是面向不同领域的设计思想。实际项目中我们通常将面向对象理解为一个静态过程(例如一个系统有多少个模块,一个模块有哪些对象,对象有哪些属性),面向切面的运行期代理方式,理解为一个动态过程,可以在对象运行时动态织入一些扩展功能或控制对象执行。
AOP就是要基于OCP(开闭原则),在不改变原有系统核心业务代码的基础上动态添加一些扩展功能并可以"控制"对象的执行。例如AOP应用于项目中的日志处理,事务处理,权限处理,缓存处理等等。
Spring AOP底层基于代理机制实现功能扩展:
- 假如目标对象(被代理对象)实现接口,则底层可以采用JDK动态代理机制为目标对象创建代理对象(目标类和代理类会实现共同接口)。
- 假如目标对象(被代理对象)没有实现接口,则底层可以采用CGLIB代理机制为目标对象创建代理对象(默认创建的代理类会继承目标对象类型)。
JDK代理代码
//提供一个接口
public interface TestAJ {
void dofind();
}
//实现类
public class TestAJImpl implements TestAJ{
@Override
public void dofind() {
System.out.println("测试JDK动态代理");
}
}
//实现类
public class TestAJImplp implements TestAJ{
private TestAJImpl testAJ;
public TestAJImplp(TestAJImpl testAJ){
this.testAJ = testAJ;
}
@Override
public void dofind() {
System.out.println("开始时间"+System.currentTimeMillis());
testAJ.dofind();
System.out.println("结束时间"+ System.currentTimeMillis());
}
}
//测试类
public static void main(String[] args) {
TestAJImplp testAJImplp = new TestAJImplp(new TestAJImpl());
testAJImplp.dofind();
}
}
//测试结果
开始时间1594649266876
测试JDK动态代理
结束时间1594649266876
CGLIB代理代码
//接口
public interface TestAJ {
void dofind();
}
//实现类
public class TestAJImpl implements TestAJ{
@Override
public void dofind() {
System.out.println("测试JDK动态代理");
}
}
//子类
public class TestAJImplp extends TestAJImpl{
@Override
public void dofind(){
System.out.println("开始时间:" +System.currentTimeMillis());
super.dofind();
System.out.println("结束时间:" + System.currentTimeMillis());
}
}
测试结果
开始时间:1594650127684
测试JDK动态代理
结束时间:1594650127684
Spring boot2.x 中AOP现在默认使用的CGLIB代理,假如需要使用JDK动态代理可以在配置文件(applicatiion.properties)中进行如下配置:
spring.aop.proxy-target-class=false
AOP 相关术语:
- 切面(aspect): 横切面对象,一般为一个具体类对象(可以借助@Aspect声明)。
- 通知(Advice):在切面的某个特定连接点上执行的动作(扩展功能),例如around,before,after等。
- 连接点(joinpoint):程序执行过程中某个特定的点,一般指被拦截到的的方法。
- 切入点(pointcut):对多个连接点(Joinpoint)一种定义,一般可以理解为多个连接点的集合。
spring可以整合AspectJ框架快速完成AOP的基本实现。AspectJ 是一个面向切面的框架,他定义了AOP的一些语法,有一个专门的字节码生成器来生成遵守java规范的class文件。
- @Aspect 注解用于标识或者描述AOP中的切面类型,基于切面类型构建的对象用于为目标对象进行功能扩展或控制目标对象的执行。
- @Pointcut注解用于描述切面中的方法,并定义切面中的切入点(基于特定表达式的方式进行描述),在本案例中切入点表达式用的是bean表达式,这个表达式以bean开头,bean括号中的内容为一个spring管理的某个bean对象的名字。
- @Around注解用于描述切面中方法,这样的方法会被认为是一个环绕通知(核心业务方法执行之前和之后要执行的一个动作),@Aournd注解内部value属性的值为一个切入点表达式或者是切入点表达式的一个引用(这个引用为一个@PointCut注解描述的方法的方法名)。
- ProceedingJoinPoint类为一个连接点类型,此类型的对象用于封装要执行的目标方法相关的一些信息。一般用于@Around注解描述的方法参数。
在基于Spring AOP编程的过程中,基于AspectJ框架标准,spring中定义了五种类型的通知(通知描述的是一种扩展业务),它们分别是:
- @Before。 前置通知
- @AfterReturning。 最终通知
- @AfterThrowing。 异常通知
- @After。 后置通知
- @Around.(优先级最高) 环绕通知
执行顺序:
Spring的切入点表达式:
bean表达式
bean表达式一般应用于类级别,实现粗粒度的切入点定义,案例分析:
- bean("类名")指定一个userServiceImpl类中所有方法。
- bean("*类名后缀")指定所有后缀为ServiceImpl的类中所有方法。
说明:bean表达式内部的对象是由spring容器管理的一个bean对象,表达式内部的名字应该是spring容器中某个bean的name。
within表达式
within表达式应用于类级别,实现粗粒度的切入点表达式定义,案例分析:
- within("包名+类名")指定当前包中这个类内部的所有方法。
- within("包名.*") 指定当前目录下的所有类的所有方法。
- within("包名..*") 指定当前目录以及子目录中类的所有方法。
execution表达式
execution表达式应用于方法级别,实现细粒度的切入点表达式定义,案例分析:
语法:execution(返回值类型 包名.类名.方法名(参数列表))。
- execution(包名+类名.方法名())匹配addUser方法。
- execution(包名+类名.方法名(参数列表)) 方法参数必须为String的addUser方法。
- execution(* 包名..*.*(..)) 万能配置。
@annotation表达式
@annotaion表达式应用于方法级别,实现细粒度的切入点表达式定义,案例分析
- @annotation(自定义注解的全限定类名) 匹配有此注解描述的方法。
Spring中的事务处理:
事务的定义:
事务(Transaction)是一个业务,是一个不可分割的逻辑工作单元,基于事务可以更好的保证业务的正确性。
(可以理解为就是一组多条SQL的执行就是一个事务)
事务具备ACID特性,分别是:
- 原子性(Atomicity):一个事务中的多个操作要么都成功要么都失败。
- 一致性(Consistency): 例如存钱操作,存之前和存之后的总钱数应该是一致的。
- 隔离性(Isolation):事务与事务应该是相互隔离的。
- 持久性(Durability):事务一旦提交,数据要持久保存。
Spring框架中提供了一种声明式事务的处理方式,此方式基于AOP代理,可以将具体业务逻辑与事务处理进行解耦。也就是让我们的业务代码逻辑不受污染或少量污染,就可以实现事务控制。
DataSourceTransactionManager对象。
@Transactional(timeout = 30,
readOnly = false,
isolation = Isolation.READ_COMMITTED,
rollbackFor = Throwable.class,
propagation = Propagation.REQUIRED)
/**
* 当@Transactional注解应用在类上时表示类中所有方法启动事务管理,并且一般用于事务共性的定义。
* 当@Transactional描述方法时表示此方法要进行事务管理,假如类和方法上都有@Transactional注解,则
* 方法上的注解一般用于事务特性的定义。
* @Transactional 常用属性应用说明:
* timeout:事务的超时时间,默认值为-1,表示没有超时显示。如果配置了具体时间,则超过该时间限制但事**务还没有完成,则自动回滚事务。
* read-only:指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数*据,可以设置 read-only 为 true。
* rollback-for:用于指定能够触发事务回滚的异常类型,如果有多个异常类型需要指定,各类型之间可以通过逗号分隔。
* no-rollback- for 抛出 no-rollback-for 指定的异常类型,不回滚事务。
* isolation事务的隔离级别,默认值采用 DEFAULT。
*/
Spring 管理事务的流程
Spring事务管理是基于接口代理(JDK)或动态字节码(CGLIB)技术,然后通过AOP实施事务增强的。当我们执行添加了事务特性的目标方式时,系统会通过目标对象的代理对象调用DataSourceTransactionManager对象,在事务开始的时,执行doBegin方法,事务结束时执行doCommit或doRollback方法。