对于spring的理解
Spring
什么是spring?
spring是一个开源的轻量级的应用开发框架,目的就是简化企业级应用程序的开发,降低开发者的开发难度。
spring的核心是对IOC和AOP的应用,可以起到解耦的作用。
spring的优势:
- 方便解耦,简化开发(通过spring提供的IOC容器,可以将对象之间的依赖关系交给spring控制,避免造成过度程序耦合)
- AOP的支持(通过spring提供的AOP功能,方便进行面向切面编程,例如:性能检测、事物管理、日志记录)
- 声明式事物支持
- 方便集成各种可利用的框架(如:spring、mybatis、Struts2.0)
- 降低了程序员编程的难度,对JDBC等进行封装。
*Spring的本质是管理软件中的对象,即创建对象和维护对象之间的关系。
spring的组成模块
spring最初的目标就是要整合一切优秀的资源,然后对外提供与一个统一的服务,Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式,如下图所示:
- Spring Core :核心容器,提供spring框架的基本功能,核心容器的主要组件是BeanFactory,他是工厂模式的体现,BeanFactory使用IOC模式
- Spring Context:Spring上下文,是一个配置文件
- Spring Aop:
- Spring Dao:对JDBC的抽象,简化了数据访问异常的处理
- Spring ORM:对现有的ORM框架的支持
- Spring web:提供了基本的面向Web的综合特性,例如多方文件上传
- Spring MVC框架:提供面向Web应用的Model-View-Controller实现。
核心组件:
模块 | 说明 |
---|---|
BeanFactory | 创建Bean工厂 |
ApplicationContext | 外部程序调用,也称为Spring容器的上下文 |
IOC(Inversion of Control) | 无需自己new对象,也无需关心对象的创建过程User user = new User(); 手动创建对象User user = context.getBean(user); 容器创建对象 |
DI依赖注入 | 松耦合方式实现对象的直接依赖 |
AOP | 补充java方面面向对像的不足 |
Spring AOP 的理解:
AOP面向切面编程,是一种不同与OOP的设计思想,
OOP(面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分;
AOP是则是针对业务过程中的切面进行提取,他面对的是处理过程中的某个步骤或者阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。
AOP用于将那些与业务无关的,但却对多个对象产生影响的公共行为和逻辑,装为一个可重用的模块,这个模块称之为”切面“。
springAOP可以减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性
springAOP的实现:
SpringAOP的实现的关键在于代理模式。AOP代理分为动态代理和静态代理。静态代理的代表是AspectJ,动态代理的代表是SpringAOP…
静态代理就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强,他会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。
动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。
动态代理主要有两种方式,分别是JDK动态代理和CGLIB动态代理:
Spring IOC 控制反转
- IOC是控制反转就是将创建对象的权力转移到Spring容器中,并且由容器根据配置文件去创建实例和管理各个实例之间的依赖关系。
- DI依赖注入和控制反转是同一个概念的不同角度的描述,即应用程序在运行时依赖 IoC容器来动态注入对象需要的外部资源。
- IOC让对象的创建不需要去new了,可以Spring自动产生,使用java的反射机制,根据配置文件在运行时动态的去创建对象和管理对象,并调用对象的方法。
- IOC由三种注入方式:构造器注入、set注入、注解注入。
IoC是设计思想,IoC有三个核心:BeanFactory、反射、DI。BeanFactory利用反射实现对象的创建,DI实现对象关系管理。
Bean的对象
<beans…/>元素是Spring配置文件的根元素,<beans…/>元素可以包含多个<bean…/>子元素,每个<bean…/>元素可以定义一个Bean实例,每一个Bean对应Spring容器里的一个Java实例定义Bean时通常需要指定两个属性。
Id:确定该Bean的唯一标识符,容器对Bean管理、访问、以及该Bean的依赖关系,都通过该属性完成。Bean的id属性在Spring容器中是唯一的。
Class:指定该Bean的具体实现类。注意这里不能使接口。通常情况下,Spring会直接使用new关键字创建该Bean的实例
Spring容器集中管理Bean对象的实例化,Bean的实例化可以通过BeanFactory的getBen(String beanid)方法获得。
当我们在配置文件中通过方法配置一个Bean时,这样就需要该Bean实现类中必须有一个无参构造器
Spring Bean的生命周期
1、实例化一个Bean--也就是我们常说的new;
2、按照Spring上下文对实例化的Bean进行配置--也就是IOC注入;
3、如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String)方法,此处传递的就是Spring配置文件中Bean的id值
4、如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory(setBeanFactory(BeanFactory)传递的是Spring工厂自身(可以用这个方式来获取其它Bean,只需在Spring配置文件中配置一个普通的Bean就可以);
5、如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文(同样这个方式也可以实现步骤4的内容,但比4更好,因为ApplicationContext是BeanFactory的子接口,有更多的实现方法);
6、如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用那个的方法,也可以被应用于内存或缓存技术;
7、如果Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法
8、如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法、;
注:以上工作完成以后就可以应用这个Bean了
9、当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用那个其实现的destroy()方法;
10、最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。
Bean对象的作用域
Bean对象的作用可以通过scope属性或相关注解指定其作用域。常用的由singleton、prototype。
- singleton:单例,默认值,这个作用域标识的对像具备全局唯一
- prototype:多例,这个作用域标识每次获取都会创建新的对像(给每一个Bean提供一个实例)
- request:为每一个网络请求创建一个实例,请求完成后,Bean会被垃圾回收站回收。
- session:为每一个session创建一个实例,会话完成后,Bean消失。
- global-session:全局作用域,
Spring框架中单例Bean
Spring框架中并没有对单例Bean进行任何多线程的封装处理, 但是大部分Spring Bean并不存可变状态,所以一般来说Spring中单例Bean是线程安全的。如果你的Bean由多种状态的话(View Model 对象),就可以将Bean的作用域由”singleton改为prototype“来实现线程安全。
问题
Spring中怎么管理多线程?
解决并发问题的最简单的方法就是使用线程同步机制(就是用关键字synchronized),但是这种方式因为限制了并发的访问,会导致性能方面会由很大的损失。
所以在Spring中用ThreadLocal来解决线程的并发问题。
为什么要使用单例和多例,何时使用?
之所以用单例,是因为没必要每个请求都新建一个对象,这样子既浪费CPU又浪费内存;
之所以用多例,是为了防止并发问题;即一个请求改变了对象的状态,此时对象又处理另一个请求,而之前请求对对象状态的改变导致了对象对另一个请求做了错误的处理;
当对象含有可改变的状态时(更精确的说就是在实际应用中该状态会改变),则多例,否则单例;
BeanFactory和ApplicationContext有什么区别?
BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当作Spring的容器。AppliationContext接口继承BeanFactory接口。
- BeanFactory是Spring里面最底层的接口,包含了各种Bean的定义,读取Bean配置文档,管理Bean的加载、实例化、控制Bean的生命周期、维护Bean之间的依赖。
- ApplicationContext是 应用上下文,它是Spring的一个更高级的容器。提供了更多有用的功能。
1>. 国际化(继承MessageSource)
2>.统一的访问资源,如URL和文件(ResourceLoader)
3) 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
4>.消息发送、响应机制(ApplicationEventPublisher)
5>.AOP(拦截器) - BeanFactory在启动的时候不会实例化Bean,只有在使用Bean的时候才会去实例化Bean,这样我们不能发现一些存在的Spring配置问题;ApplicationContext在启动的时候一次性实例化了所有的Bean。这样在容器启动时,我们就可以发现Spring存在的问题。
- BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册
DI依赖注入
DI(Dependency Injection)依赖注入 。相对于IOC来说,DI更加完美的描述了IOC的设计理念。
所谓依赖注入,即组件之间的依赖关系由容器在应用运行期间决定的,也就是容器动态地将某种依赖关系的目标对象的实例注入到应用系统各个关系组件之中。
属性的注入方式
对象由Spring创建,Spring也提供了两种方式设置属性值:
- Set注入:
- 构造方法注入:
IOC和DI
我们在完成某一个业务逻辑时,可能需要多个对象来协助完成,每个对象在需要使用它的合作对象的适合,就要自己去创建这样一个对象出来,像这样创建合作者对象和创建时机都有自己把控的话,这样的话对象之间的耦合度就会非常高。
假设两个对象A和B,使用了Spring之后,创建合作者B对象的工作就交给Spring来做,Spring创建好B之后,就存储到一个容器之中,当A需要使用B对象的时候,Spring就直接从容器中取出B对象给A使用。至于Spring对与B的操作,A对象不需要关心这些细节问题。
所以控制反转IoC(Inversion of Control)是说创建对象的控制权进行转移,以前创建对象的主动权和创建时机是由自己把控的,而现在这种权力转移到第三方,比如转移交给了IoC容器,它就是一个专门用来创建对象的工厂,你要什么对象,它就给你什么对象,有了 IoC容器,依赖关系就变了,原先的依赖关系就没了,它们都依赖IoC容器了,通过IoC容器来建立它们之间的关系
DI(依赖注入)其实就是IOC的另外一种说法,DI是由Martin Fowler 在2004年初的一篇论文中首次提出的。他总结:控制的什么被反转了?就是:获得依赖对象的方式反转了。
IoC是设计思想,IoC有三个核心:BeanFactory、反射、DI。BeanFactory利用反射实现对象的创建,DI实现对象关系管理。
Spring事务
Spring事物的本质其实就是数据库对事务的支持,没有数据库的事物支持,Spring是无法提供事物功能的,真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。
Spring事务的种类:
- 1>.编程式事务管理使用TransactionTemplate
- 2>.声明式事务管理(优点就是不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明或通过@Transactional注解的方式,便可以将事务规则应用到业务逻辑中)
声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式,使业务代码不受污染,只要加上注解就可以获得完全的事务支持。唯一不足地方是,最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。
Spring事务传播行为
spring事务的传播行为说的是,当多个事务同时存在的时候,spring如何处理这些事务的行为。
事务行为 | 说明 |
---|---|
PROPAGATION_REQUIRED | 如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行 |
PROPAGATION_MANDATORY | 支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常 |
PROPAGATION_REQUIRES_NEW | 创建新事务,无论当前存不存在事务,都创建新事务 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起 |
PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常 |
PROPAGATION_NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行 |
Spring中的隔离级别
隔离级别 | 说明 |
---|---|
ISOLATION_DEFAULT | 这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别 |
ISOLATION_READ_UNCOMMITTED | 读未提交,允许另外一个事务可以看到这个事务未提交的数据 |
ISOLATION_READ_COMMITTED | 读已提交,保证一个事务修改的数据提交后才能被另一事务读取,而且能看到该事务对已有记录的更新 |
ISOLATION_REPEATABLE_READ | 可重复读,保证一个事务修改的数据提交后才能被另一事务读取,但是不能看到该事务对已有记录的更新 |
ISOLATION_SERIALIZABLE | 一个事务在执行的过程中完全看不到其他事务对数据库所做的更新 |
推荐阅读
-
对于ConvLSTM的理解
-
React+Spring实现跨域问题的完美解决方法
-
对于ConvLSTM的理解
-
详解Spring Kafka中关于Kafka的配置参数
-
对于spring的理解
-
spring cloud升级到spring boot 2.x/Finchley.RELEASE遇到的坑
-
Spring MVC的优点与核心接口_动力节点Java学院整理
-
老生常谈Java中instanceof关键字的理解
-
源代码解读基于Spring的声明性缓存实现原理 SpringCache应用服务器框架memcached
-
SpringCloud Finchley+Spring Boot 2.0 集成Consul的方法示例(1.2版本)