spring 笔记

Spring能帮我们做什么:

    1. Spring 能帮我们根据配置文件创建及组装对象之间的依赖关系,管理对象,解耦。IOC控制反转,DC依赖注入。
    2. Spring 面向切面编程能帮助我们无耦合的实现日志记录,性能统计,安全控制。AOP。
    3. Spring 能非常简单的帮我们管理数据库事务。
    4. 简化与第三方技术框架的集成。
    5. Spring MVC框架。

Spring概念:

IOC:控制反转,对象的创建由IOC容器来完成,容器管理Bean和Bean对象之间的依赖关系。
DC:依赖注入,IOC容器管理对象依赖于IoC容器,需要IOC容器提供对象需要的外部资源。IoC容器注入某个对象所需要的外部资源(包括对象、资源、常量数据)。 
Bean:由IoC容器管理对象我们就叫它Bean,Spring实例化Bean主要是基于注解,java文件,xml配置文件配置元数据。
Bean的作用域(scope):在Spring容器中是指其创建的Bean对象相对于其他Bean对象的请求可见范围。Spring提供5种作用域:
    singleton单例:是spring默认缺省的,全局只有一个对象。
    prototype原型:每次都是新的Bean实例,有状态的Bean建议用此类型。
    request:一次Http请求中,容器返回同一实例Bean,仅在当前Http Request内有效
    session:一次Http Session中,容器返回同一实例Bean,仅在当前Session内有效。
    global session:一个全局的Http Session中,容器返回同一个实例Bean。
IoC容器注入依赖资源:构造器注入,setter注入,方法注入。
循环依赖:
    1. 构造器循环依赖,表示通过构造器注入构成的循环依赖,此依赖是无法解决的,只能抛出BeanCurrentlyInCreationException异常表示循环依赖。
    2. setter循环依赖,表示通过setter注入方式构成的循环依赖。对于setter注入造成的依赖是通过Spring容器提前暴露刚完成构造器注入但未完成其他步骤(如setter注入)的Bean来完成的,而且只能解决单例作用域的Bean循环依赖。Spring容器创建单例Bean,首先根据无参构造器创建Bean,并暴露一个“ObjectFactory ”用于返回一个提前暴露一个创建中的Bean。对于“prototype”作用域Bean,Spring容器无法完成依赖注入,因为“prototype”作用域的Bean,Spring容器不进行缓存,因此无法提前暴露一个创建中的Bean。
延迟初始化Bean:惰性初始化,指不提前初始化Bean,而是只有在真正使用时才创建及初始化Bean。@Lazy
自动装配:@Autowired
依赖检查:@Required
Resource接口:Spring 提供一个Resource接口来统一底层资源一致的访问。

Spring IOC:

    在Spring Ioc容器的代表就是org.springframework.beans包中的BeanFactory接口,BeanFactory接口提供了IoC容器最基本功能;而org.springframework.context包下的ApplicationContext接口扩展了BeanFactory,还提供了与Spring AOP集成、国际化处理、事件传播及提供不同层次的context实现 (如针对web应用的WebApplicationContext)。简单说, BeanFactory提供了IoC容器最基本功能,而 ApplicationContext 则增加了更多支持企业级功能支持。ApplicationContext完全继承BeanFactory,因而BeanFactory所具有的语义也适用于ApplicationContext。 ### Spring AOP:

    连接点(Jointpoint):表示需要在程序中插入横切关注点的扩展点,连接点可能是类初始化、方法执行、方法调用、字段调用或处理异常等等,Spring只支持方法执行连接点,在AOP中表示为“在哪里干”;
    切入点(Pointcut):选择一组相关连接点的模式,即可以认为连接点的集合,Spring支持perl5正则表达式和AspectJ切入点模式,Spring默认使用AspectJ语法,在AOP中表示为“在哪里干的集合”;
    通知(Advice):在连接点上执行的行为,通知提供了在AOP中需要在切入点所选择的连接点处进行扩展现有行为的手段;包括前置通知(before advice)、后置通知(after advice)、环绕通知(around advice),在Spring中通过代理模式实现AOP,并通过拦截器模式以环绕连接点的拦截器链织入通知;在AOP中表示为“干什么”;
    方面/切面(Aspect):横切关注点的模块化,比如上边提到的日志组件。可以认为是通知、引入和切入点的组合;在Spring中可以使用Schema和@AspectJ方式进行组织实现;在AOP中表示为“在哪干和干什么集合”;
    引入(inter-type declaration):也称为内部类型声明,为已有的类添加额外新的字段或方法,Spring允许引入新的接口(必须对应一个实现)到所有被代理对象(目标对象), 在AOP中表示为“干什么(引入什么)”;
    目标对象(Target Object):需要被织入横切关注点的对象,即该对象是切入点选择的对象,需要被通知的对象,从而也可称为“被通知对象”;由于Spring AOP 通过代理模式实现,从而这个对象永远是被代理对象,在AOP中表示为“对谁干”;
    AOP代理(AOP Proxy):AOP框架使用代理模式创建的对象,从而实现在连接点处插入通知(即应用切面),就是通过代理来对目标对象应用切面。在Spring中,AOP代理可以用JDK动态代理或CGLIB代理实现,而通过拦截器模型应用切面。
    织入(Weaving):织入是一个过程,是将切面应用到目标对象从而创建出AOP代理对象的过程,织入可以在编译期、类装载期、运行期进行。
    通知类型:前置通知,后置通知,环绕通知。

Spring 事务:

事务必需满足ACID(原子性、一致性、隔离性和持久性)特性,缺一不可:
原子性(Atomicity):即事务是不可分割的最小工作单元,事务内的操作要么全做,要么全不做;
一致性(Consistency):在事务执行前数据库的数据处于正确的状态,而事务执行完成后数据库的数据还是处于正确的状态,即数据完整性约束没有被破坏;如银行转帐,A转帐给B,必须保证A的钱一定转给B,一定不会出现A的钱转了但B没收到,否则数据库的数据就处于不一致(不正确)的状态。
隔离性(Isolation):并发事务执行之间无影响,在一个事务内部的操作对其他事务是不产生影响,这需要事务隔离级别来指定隔离性;
持久性(Durability):事务一旦执行成功,它对数据库的数据的改变必须是永久的,不会因比如遇到系统故障或断电造成数据不一致或丢失。
在实际项目开发中数据库操作一般都是并发执行的,即有多个事务并发执行,并发执行就可能遇到问题,目前常见的问题如下:
丢失更新:两个事务同时更新一行数据,最后一个事务的更新会覆盖掉第一个事务的更新,从而导致第一个事务更新的数据丢失,这是由于没有加锁造成的;
脏读:一个事务看到了另一个事务未提交的更新数据;
不可重复读:在同一事务中,多次读取同一数据却返回不同的结果;也就是有其他事务更改了这些数据;
幻读:一个事务在执行过程中读取到了另一个事务已提交的插入数据;即在第一个事务开始时读取到一批数据,但此后另一个事务又插入了新数据并提交,此时第一个事务又读取这批数据但发现多了一条,即好像发生幻觉一样。
为了解决这些并发问题,需要通过数据库隔离级别来解决,在标准SQL规范中定义了四种隔离级别:
未提交读(Read Uncommitted):最低隔离级别,一个事务能读取到别的事务未提交的更新数据,很不安全,可能出现丢失更新、脏读、不可重复读、幻读;
提交读(Read Committed):一个事务能读取到别的事务提交的更新数据,不能看到未提交的更新数据,不可能可能出现丢失更新、脏读,但可能出现不可重复读、幻读;
可重复读(Repeatable Read):保证同一事务中先后执行的多次查询将返回同一结果,不受其他事务影响,可能可能出现丢失更新、脏读、不可重复读,但可能出现幻读;
序列化(Serializable):最高隔离级别,不允许事务并发执行,而必须串行化执行,最安全,不可能出现更新、脏读、不可重复读、幻读。
隔离级别越高,数据库事务并发执行性能越差,能处理的操作越少。因此在实际项目开发中为了考虑并发性能一般使用提交读隔离级别,它能避免丢失更新和脏读,尽管不可重复读和幻读不能避免,但可以在可能出现的场合使用悲观锁或乐观锁来解决这些问题。

事务类型:Spring支持声明式事务(通过注解或XML配置文件指定事务信息)和编程式事务(通过编写代码实现事务)事务类型。
声明式事务:Spring提供基于@Transactional注解方式来实现。
@Transactional配置详解:
    value:指定事务管理器名字,默认使用<tx:annotation-driven/>指定的事务管理器,用于支持多事务管理器环境;
    propagation:指定事务传播行为,默认为Required,使用Propagation.REQUIRED指定;
    isolation:指定事务隔离级别,默认为“DEFAULT”,使用Isolation.DEFAULT指定;
    readOnly:指定事务是否只读,默认false表示事务非只读;
    timeout:指定事务超时时间,以秒为单位,默认-1表示事务超时将依赖于底层事务系统;
    rollbackFor:指定一组异常类,遇到该类异常将回滚事务;
    rollbackForClassname:指定一组异常类名字,其含义与<tx:method>中的rollback-for属性语义完全一样;
    noRollbackFor:指定一组异常类,即使遇到该类异常也将提交事务,即不回滚事务;
    noRollbackForClassname:指定一组异常类名字,其含义与<tx:method>中的no-rollback-for属性语义完全一样;
Spring事务隔离级别:
    Spring在TransactionDefinition接口中定义了五个不同的事务隔离级别
    ISOLATION_DEFAULT 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.另外四个与JDBC的隔离级别相对应 
    ISOLATION_READ_UNCOMMITTED 这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读
    ISOLATION_READ_COMMITTED 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。
    ISOLATION_REPEATABLE_READ 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
    ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读
Spring事务传播行为:
    Spring在TransactionDefinition接口中定义了七个事务传播行为。
    PROPAGATION_REQUIRED 如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。
    PROPAGATION_SUPPORTS 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。
    PROPAGATION_MANDATORY 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
    PROPAGATION_REQUIRES_NEW 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
    PROPAGATION_NOT_SUPPORTED 总是非事务地执行,并挂起任何存在的事务。
    PROPAGATION_NEVER 总是非事务地执行,如果存在一个活动事务,则抛出异常
    PROPAGATION_NESTED 如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行  

    1.  PROPAGATION_REQUIRED ,默认的spring事务传播级别,使用该级别的特点是,如果上下文中已经存在事务,那么就加入到事务中执行,如果当前上下文中不存在事务,则新建事务执行。所以这个级别通常能满足处理大多数的业务场景。
    2. PROPAGATION_SUPPORTS ,从字面意思就知道,supports,支持,该传播级别的特点是,如果上下文存在事务,则支持事务加入事务,如果没有事务,则使用非事务的方式执行。所以说,并非所有的包在transactionTemplate.execute中的代码都会有事务支持。这个通常是用来处理那些并非原子性的非核心业务逻辑操作。应用场景较少。
    3. PROPAGATION_MANDATORY , 该级别的事务要求上下文中必须要存在事务,否则就会抛出异常!配置该方式的传播级别是有效的控制上下文调用代码遗漏添加事务控制的保证手段。比如一段代码不能单独被调用执行,但是一旦被调用,就必须有事务包含的情况,就可以使用这个传播级别。
    4. PROPAGATION_REQUIRES_NEW ,从字面即可知道,new,每次都要一个新事务,该传播级别的特点是,每次都会新建一个事务,并且同时将上下文中的事务挂起,执行当前新建事务完成以后,上下文事务恢复再执行。这是一个很有用的传播级别,举一个应用场景:现在有一个发送100个红包的操作,在发送之前,要做一些系统的初始化、验证、数据记录操作,然后发送100封红包,然后再记录发送日志,发送日志要求100%的准确,如果日志不准确,那么整个父事务逻辑需要回滚。怎么处理整个业务需求呢?就是通过这个PROPAGATION_REQUIRES_NEW 级别的事务传播控制就可以完成。发送红包的子事务不会直接影响到父事务的提交和回滚。
    5. PROPAGATION_NOT_SUPPORTED ,这个也可以从字面得知,not supported ,不支持,当前级别的特点就是上下文中存在事务,则挂起事务,执行当前逻辑,结束后恢复上下文的事务。这个级别有什么好处?可以帮助你将事务极可能的缩小。我们知道一个事务越大,它存在的风险也就越多。所以在处理事务的过程中,要保证尽可能的缩小范围。比如一段代码,是每次逻辑操作都必须调用的,比如循环1000次的某个非核心业务逻辑操作。这样的代码如果包在事务中,势必造成事务太大,导致出现一些难以考虑周全的异常情况。所以这个事务这个级别的传播级别就派上用场了。用当前级别的事务模板抱起来就可以了。
    6. PROPAGATION_NEVER ,该事务更严格,上面一个事务传播级别只是不支持而已,有事务就挂起,而PROPAGATION_NEVER传播级别要求上下文中不能存在事务,一旦有事务,就抛出runtime异常,强制停止执行!这个级别上辈子跟事务有仇。
    7. PROPAGATION_NESTED ,字面也可知道,nested,嵌套级别事务。该传播级别特征是,如果上下文中存在事务,则嵌套事务执行,如果不存在事务,则新建事务。

    * 脏读: 所谓的脏读,其实就是读到了别的事务回滚前的脏数据。比如事务B执行过程中修改了数据X,在未提交前,事务A读取了X,而事务B却回滚了,这样事务A就形成了脏读。
    
    * 不可重复读:不可重复读字面含义已经很明了了,比如事务A首先读取了一条数据,然后执行逻辑的时候,事务B将这条数据改变了,然后事务A再次读取的时候,发现数据不匹配了,就是所谓的不可重复读了。
    
    * 幻读:小的时候数手指,第一次数十10个,第二次数是11个,怎么回事?产生幻觉了?幻读也是这样子,事务A首先根据条件索引得到10条数据,然后事务B改变了数据库一条数据,导致也符合事务A当时的搜索条件,这样事务A再次搜索发现有11条数据了,就产生了幻读。

SpringMVC流程:

(1)用户发送请求至前端控制器DispatcherServlet;
(2) DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle;
(3)处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet;
(4)DispatcherServlet 调用 HandlerAdapter处理器适配器;
(5)HandlerAdapter 经过适配调用 具体处理器(Handler,也叫后端控制器);
(6)Handler执行完成返回ModelAndView;
(7)HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;
(8)DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;
(9)ViewResolver解析后返回具体View;
(10)DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
(11)DispatcherServlet响应用户。

其他:

  1. servlet:

     创建并返回一个包含基于客户请求性质的动态内容的完整的html页面;
     创建可嵌入到现有的html页面中的一部分html页面(html片段);
     读取客户端发来的隐藏数据;
     读取客户端发来的显示数据;
     与其他服务器资源(包括数据库和java的应用程序)进行通信;
     通过状态代码和响应头向客户端发送隐藏数据。
    
  2. filter:

     filter能够在一个请求到达servlet之前预处理用户请求,也可以在离开servlet时处理http响应:
     在执行servlet之前,首先执行filter程序,并为之做一些预处理工作;
     根据程序需要修改请求和响应;
     在servlet被调用之后截获servlet的执行
    
  3. listener:职责如概念。

     servlet2.4规范中提供了8个listener接口,可以将其分为三类,分别如下:
     第一类:与servletContext有关的listner接口。包括:ServletContextListener、ServletContextAttributeListener
     第二类:与HttpSession有关的Listner接口。包括:HttpSessionListner、HttpSessionAttributeListener、HttpSessionBindingListener、                    HttpSessionActivationListener;
     第三类:与ServletRequest有关的Listener接口,包括:ServletRequestListner、ServletRequestAttributeListener
    
  4. interceptor:与过滤器十分相似,通过层层拦截,处理用户的请求和响应。

  5. spring Bean 的生命周期(简化9步):

    1. 实例化bean对象(通过构造方法或者工厂方法)
    2. 设置对象属性(setter等)(依赖注入)
    3. 如果Bean实现了BeanNameAware接口,工厂调用Bean的setBeanName()方法传递Bean的ID。(和下面的一条均属于检查Aware接口)
    4. 如果Bean实现了BeanFactoryAware接口,工厂调用setBeanFactory()方法传入工厂自身
    5. 将Bean实例传递给Bean的前置处理器的postProcessBeforeInitialization(Object bean, String beanname)方法
    6. 调用Bean的初始化方法
    7. 将Bean实例传递给Bean的后置处理器的postProcessAfterInitialization(Object bean, String beanname)方法
    8. 使用Bean
    9. 容器关闭之前,调用Bean的销毁方法