Spring 问题笔记

Spring中的设计模式

个人了解:
单例模式;工厂方法模式;代理模式;观察者模式;模板方法模式…

Spring具体模式应用

Spring模块

在这里插入图片描述

  • 核心容器(Spring Core)
    核心容器提供Spring框架的基本功能。Spring以bean的方式组织和管理Java应用中的各个组件及其关系。Spring使用BeanFactory来产生和管理Bean,它是工厂模式的实现。BeanFactory使用控制反转(IoC)模式将应用的配置和依赖性规范与实际的应用程序代码分开。

  • 应用上下文(Spring Context)
    Spring上下文是一个配置文件,向Spring框架提供上下文信息。Spring上下文包括企业服务,如JNDI、EJB、电子邮件、国际化、校验和调度功能。

  • 面向切面编程(Spring AOP)
    AOP(Aspect Oriented Programming)
    通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring框架中。所以,可以很容易地使 Spring框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。

  • JDBC和DAO模块(Spring DAO)
    JDBC、DAO的抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理,和不同数据库供应商所抛出的错误信息。异常层次结构简化了错误处理,并且极大的降低了需要编写的代码数量,比如打开和关闭链接。

  • 对象实体映射(Spring ORM)
    ORM(Object Relational Mapping)
    Spring框架插入了若干个ORM框架,从而提供了ORM对象的关系工具,其中包括了Hibernate、JDO和 IBatis SQL Map等,所有这些都遵从Spring的通用事物和DAO异常层次结构。

  • Web模块(Spring Web)
    Web上下文模块建立在应用程序上下文模块之上,为基于web的应用程序提供了上下文。所以Spring框架支持与Struts集成,web模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。

  • MVC模块(Spring Web MVC)
    MVC(Model View Controller)
    MVC框架是一个全功能的构建Web应用程序的MVC实现。通过策略接口,MVC框架变成为高度可配置的。MVC容纳了大量视图技术,其中包括JSP、POI等,模型来有JavaBean来构成,存放于m当中,而视图是一个街口,负责实现模型,控制器表示逻辑代码,由c的事情。Spring框架的功能可以用在任何J2EE服务器当中,大多数功能也适用于不受管理的环境。Spring的核心要点就是支持不绑定到特定J2EE服务的可重用业务和数据的访问的对象,毫无疑问这样的对象可以在不同的J2EE环境,独立应用程序和测试环境之间重用。

Spring 事务

Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。

  • JDBC操作数据库,想要用到事务,可以按照以下步骤进行:
  1. 连接 Connection con = DriverManager.getConnection()
  2. 开启事务con.setAutoCommit(true/false);
  3. 执行CRUD
  4. 提交事务/回滚事务 con.commit() / con.rollback();
  5. 关闭连接 conn.close()
  • 使用Spring的事务管理功能后,我们可以不再写步骤 2 和 4 的代码,而是由Spirng 自动完成
  1. 配置文件开启注解驱动,在相关的类和方法上通过注解 @Transactional 标识。
  2. spring 在启动的时候会去解析生成相关的bean,这时候会查看拥有相关注解的类和方法,并且为这些类和方法生成代理,并根据@Transaction的相关参数进行相关配置注入,这样就在代理中为我们把相关的事务处理掉了(开启正常提交事务,异常回滚事务)。
  3. 真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。

在应用系统调用声明@Transactional 的目标方法时,Spring Framework 默认使用 AOP 代理,在代码运行时生成一个代理对象ProxyObject。

  • 整个事务的增强执行过程:
    在同一个Class内,非代理增强方法中调用了被@Transactional注解增强的方法,注解会失效。背后的实际原因是Spring AOP是基于代理,同一个类内这样调用的话,只有第一次调用了动态代理生成的ProxyClass,之后调用是不带任何切面信息的方法本身,因为没有直接调用Spring生成的代理对象。

AspectJ事务方面甚至被编织成私有方法(Spring3.0检查)。

参考文章

Spring 事务隔离级别

  1. DEFAULT (默认)
    这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与JDBC的隔离级别相对应。

  2. READ_UNCOMMITTED (读未提交)
    这是事务最低的隔离级别,它允许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。

  3. READ_COMMITTED (读已提交)
    保证一个事务修改的数据提交后才能被另外一个事务读取,另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。

  4. REPEATABLE_READ (可重复读)
    这种事务隔离级别可以防止脏读、不可重复读,但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了不可重复读。

  5. SERIALIZABLE(串行化)
    这是花费最高代价但是最可靠的事务隔离级别,事务被处理为顺序执行。除了防止脏读、不可重复读外,还避免了幻像读。

Spring 事务传播属性

  1. required(默认属性)
    如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。
    被设置成这个级别时,会为每一个被调用的方法创建一个逻辑事务域。如果前面的方法已经创建了事务,那么后面的方法支持当前的事务,如果当前没有事务会重新建立事务。

  2. Mandatory
    支持当前事务,如果当前没有事务,就抛出异常。

  3. Never
    以非事务方式执行,如果当前存在事务,则抛出异常。

  4. Not_supports
    以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

  5. requires_new
    新建事务,如果当前存在事务,把当前事务挂起。

  6. Supports
    支持当前事务,如果当前没有事务,就以非事务方式执行。

  7. Nested
    支持当前事务,新增Savepoint点,与当前事务同步提交或回滚。
    嵌套事务一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚。

Spring 中的 IOC&DI

笔记

Spring IOC初始化流程

  • Resource定位;指对BeanDefinition的资源定位过程。通俗地讲,就是找到定义Javabean信息的XML文件,并将其封装成Resource对象。

  • BeanDefinition的载入;把用户定义好的Javabean表示为IoC容器内部的数据结构,这个容器内部的数据结构就是BeanDefinition。

  • 向IoC容器注册这些BeanDefinition。

IOC 中的设计模式

  • 工厂模式
  • 单例模式
  • 策略模式
  • 装饰者模式

参考文章

Spring IOC自动装配

参考文章

AOP 的理解与实现

笔记

AOP 底层原理

举例:JDK 动态代理底层原理-反射

  • 动态代理是通过JDK的 Proxy 和一个调用处理器 InvocationHandler 来实现的,通过Proxy来生成代理类实例,而这个代理实例通过调用处理器InvocationHandler 接收不同的参数灵活调用真实对象的方法
  • 所以我们需要做的是创建调用处理器,该调用处理器必须实现 JDK 的 InvocationHandler

动态代理与静态代理区别

  • 静态代理是我们 直接控制 真实对象 的方法调用,
  • 而动态代理是通过调用处理器的 invoke 方法来调用真实对象的方法,而这个invoke方法就是我们自己覆写的方法,动态的生成代理类,而不用像静态代理一样,在编译期间进行定义类。
  • 动态代理更加灵活,不用显示的在所有方法前面或者后面加入权限验证、记录日志等操作。
  • 注解方式:
    @[email protected][email protected]/@After 等

Spring AOP的调用过程

参考文章

Spring Bean的完整生命周期

在这里插入图片描述

Bean的完整生命周期

在这里插入图片描述

  • 1.instantiate bean对象实例化
  • 2.populate properties 封装属性/依赖注入
  • 3.如果bean实现了BeanNameAware接口,spring将bean的id传给setBeanName()方法并执行
  • 4.如果bean实现了BeanFactoryAware接口 或者 ApplicationContextAware ,spring将调用setBeanFactory方法,将BeanFactory实例传进来
  • 5.如果存在类实现 BeanPostProcessor(后处理Bean) ,执行postProcessBeforeInitialization,BeanPostProcessor接口提供钩子函数,用来动态扩展修改Bean。(程序自动调用后处理Bean)
  • 6.如果Bean实现InitializingBean 执行 afterPropertiesSet
  • 7.调用 指定初始化方法 init
  • 8.如果存在类实现 BeanPostProcessor(处理Bean) ,执行postProcessAfterInitialization
  • 9.执行业务处理
  • 10.如果Bean实现 DisposableBean,执行 destroy
  • 11.调用指定销毁方法 customerDestroy

其他参考文章

Bean的简单生命周期

  • 1.bean定义:在配置文件里面用< bean >< /bean> 进行定义
  • 2.bean 初始化:有两种方式进行初始化
    • 在配置文件中通过指定 init-method属性来完成
    • 实现org.springframwork.beans.factory.InitializingBean接口
  • 3.bean 调用:三种方式得到bean实例并进行调用
    • 构造方法创建
    • 静态工厂创建
    • 实例工厂创建

参考文章

  • 4.bean销毁:两种方式
    • 使用配置文件指定的 destroy-method属性
    • 实现org.springframwork.bean.factory.DisposeableBean接口

Spring Bean的作用域

spring 起初的版本只有singleton,也就是是否是单例模式。

作用域包括:singleton、prototype、request、session和globalSession

  • singleton
    全局只有一个实例
  • prototype
    每次调用产生一个新的实例
    在web使用的时候还有三个作用域,但是必须在web.xml中注册一个RequestContextListener , 目的是为了设置每次请求开始和结束都可以使spring得到相应的事件。
  • request
    每次请求产生一个bean
  • session
    每个用户session可以产生一个新的bean,不同用户之间的bean互相不影响
  • globalSession
    作用和session类似,只是使用portlet的时候使用。

Spring Bean的注入

spring支持构造器注入和setter方法注入

  • 构造器注入,通过 元素完成注入
  • setter方法注入, 通过 元素完成注入【开发中常用方式】

使用构造器注入的好处:

保证依赖不可变(final关键字)
保证依赖不为空(省去了我们对其检查)
保证返回客户端(调用)的代码的时候是完全初始化的状态
避免了循环依赖
提升了代码的可复用性

Spring 中的 单例 Bean是线程安全吗

  • 如果单例Bean,是一个无状态Bean,也就是线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例Bean是线程安全的。
    比如Spring mvc 的 Controller、Service、Dao等,这些Bean大多是无状态的,只关注于方法本身。

  • 对于有状态的bean,Spring官方提供的bean,一般提供了通过ThreadLocal去解决线程安全的方法,比如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等。

  • 使用ThreadLocal的好处
    使得多线程场景下,多个线程对这个单例Bean的成员变量并不存在资源的竞争,因为ThreadLocal为每个线程保存线程私有的数据。这是一种以空间换时间的方式。
    当然也可以通过加锁的方法来解决线程安全,这种以时间换空间的场景在高并发场景下显然是不实际的。

有状态与无状态

  • 有状态对象(Stateful Bean) :就是有实例变量的对象,可以保存数据,是非线程安全的。每个用户有自己特有的一个实例,在用户的生存期内,bean保持了用户的信息,即“有状态”;一旦用户灭亡(调用结束或实例结束),bean的生命期也告结束。即每个用户最初都会得到一个初始的bean。

  • 无状态对象(Stateless Bean):就是没有实例变量的对象,不能保存数据,是不变类,是线程安全的。bean一旦实例化就被加进会话池中,各个用户都可以共用。即使用户已经消亡,bean 的生命期也不一定结束,它可能依然存在于会话池中,供其他用户调用。由于没有特定的用户,那么也就不能保持某一用户的状态,所以叫无状态bean。但无状态会话bean 并非没有状态,如果它有自己的属性(变量),那么这些变量就会受到所有调用它的用户的影响,这是在实际应用中必须注意的。

参考文章

BeanFactory接口和ApplicationContext接口区别

  • ApplicationContext 接口继承BeanFactory接口,Spring核心工厂是BeanFactory ,BeanFactory采取延迟加载,第一次getBean时才会初始化Bean, ApplicationContext是会在加载配置文件时初始化Bean。
  • ApplicationContext是对BeanFactory扩展,它可以进行国际化处理、事件传递和bean自动装配以及各种不同应用层的Context实现

开发中基本都在使用ApplicationContext, web项目使用WebApplicationContext ,很少用到BeanFactory

BeanFactory 与 FactoryBean 的区别

  • BeanFactory定义了IOC容器的最基本形式,并提供了IOC容器应遵守的的最基本的接口,也就是Spring IOC所遵守的最底层和最基本的编程规范。

    它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。 在Spring代码中,BeanFactory只是个接口,并不是IOC容器的具体实现。

  • FactoryBean为了实现更灵活的配置Bean,用户可以通过实现该接口定制实例化Bean的逻辑

  • BeanFactory是个Factory,也就是IOC容器或对象工厂,FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。但对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似。

参考文章