Spring

1、Spring优点:

  • 低侵入式的设计,代码污染度低;
  • 独立于各种应用服务器,基于Spring框架的应用真正实现了write onece、run anywhere;
  • Spring的IOC容器降低了业务对象替换的复杂度,提高了组件间的解耦;
  • Spring的AOP将一些通用的功能任务和安全、事物、日志等进行集中管理;
  • Spring的ORM(对象关系映射,虚拟数据库)和DAO(面向对象的数据库接口)提供了与第三方框架的整合,方便访问数据库;
    image.png

2、Spring核心机制:

  • 管理Bean 程序主要通过Spring容器来访问Bean,ApplicationContext是Spring容器最常用的接口,该接口有两个实现类:ClassPathXMLApplicationContext从类加载路径下搜索配置文件;FileSystemXMLApplicationContext从文件系统的相对路径下搜索配置文件;
    image.png
  • 依赖注入 当某个Java对象调用另一个Java对象时,传统方法有两种:
    (1)调用者主动创建被依赖的对象,然后再调用被依赖对象的方法;
    (2)简单工厂模式:调用者先找到被依赖对象的工厂,然后主动通过工厂去获取被依赖的对象。
    使用Spring后,调用者无需主动获取被依赖的对象,调用者只需要被动的接受Spring 容器为调用者的成员变量赋值,由原来的主动获取变成被动的赋值所以也叫控制反转。从Spring容器来看,Spring容器负责将被依赖的对象赋值给调用者的成员变量,相当于为调用者注入它所需要的实例,因此叫做依赖注入。依赖注入是一种优秀的解耦方式,可以让Bean以配置文件组织在一起而不是以硬编码的方式。注入方式有设值注入和构造注入,设值注入指IOC容器通过成员变量以setter的方式注入被依赖的对象;构造注入指利用构造器来设置依赖关系的方式,就是驱动Spring在底层以反射方式执行带指定参数的构造器,当执行带参数得构造器时,就可以利用构造器参数对成员变量执行初始化。
    image.png

3、SpringMVC的流程:
image.png

  • 用户发送请求至前端控制器DispatcherServelt;
  • 前端控制器收到请求调用处理器映射器HandlerMapping;
  • 处理器映射器找到具体的处理器,生成处理器对象及处理器拦截器一并返回给前端控制器;
  • 前端控制器调用处理器适配器HandlerAdapter;
  • 处理器适配器调用具体的处理器(如Controller,也叫后端处理器);
  • Controller执行完成返回ModelAndView;
  • 处理器适配器将controller执行结果ModelAndView返回给前端控制器;
  • 前端控制器将ModelAndView传给ViewReslover视图解析器;
  • ViewReslover解析后返回具体View;
  • DispatcherServelt根据View进行渲染视图(即将模型数据填充至视图中);
  • DispatcherServelt响应用户。

4、IOC

4.1 概念

Spring 通过一个配置文件描述 Bean 及 Bean 之间的依赖关系,利用 Java 语言的反射功能实例化 Bean 并建立 Bean 之间的依赖关系。 Spring 的 IoC 容器在完成这些底层工作的基础上,还提供了 Bean 实例缓存、生命周期管理、 Bean 实例代理、事件发布、资源装载等高级服务。

4.2 Spring容器高层视图

Spring 启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相应的Bean配置注册表,然后根据这张注册表实例化Bean,装配好Bean之间的依赖关系,为上层应用提供准备就绪的运行环境。其中Bean缓存池为HashMap实现
image.png

4.3 Spring 依赖注入四种方式

  • 构造器注入
/*带参数,方便利用构造器进行注入*/
public CatDaoImpl(String message){
this. message = message;
}



  • setter方法注入
public class Id {
  private int id;
  public int getId() {
    return id; 
  }
  public void setId(int id) {
     this.id = id; 
  }
}
  
  • 静态工厂注入
public class DaoFactory { //静态工厂
  public static final FactoryDao getStaticFactoryDaoImpl(){
    return new StaticFacotryDaoImpl();
  }
}
public class SpringAction {
  private FactoryDao staticFactoryDao; //注入对象
  //注入对象的set方法
  public void setStaticFactoryDao(FactoryDao staticFactoryDao) {
    this.staticFactoryDao = staticFactoryDao;
  }
}
//factory-method="getStaticFactoryDaoImpl"指定调用哪个工厂方法

  
  



  • 实例工厂
public class DaoFactory { //实例工厂
  public FactoryDao getFactoryDaoImpl(){
    return new FactoryDaoImpl();
  }
}
public class SpringAction {
  private FactoryDao factoryDao; //注入对象
  public void setFactoryDao(FactoryDao factoryDao) {
    this.factoryDao = factoryDao;
  }
}

  
  




4.4 5种不同方式的自动装配

Spring装配包括手动装配和自动装配,手动装配是有基于xml装配、构造方法、setter方法等
自动装配有五种自动装配的方式,可以用来指导Spring容器用自动装配方式来进行依赖注入。

  • no:默认的方式是不进行自动装配,通过显式设置ref 属性来进行装配。
  • byName:通过参数名 自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byname,之后容器试图匹配、装配和该bean的属性具有相同名字的bean。
  • byType:通过参数类型自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byType,之后容器试图匹配、装配和该bean的属性具有相同类型的bean。如果有多个bean符合条件,则抛出错误。
  • constructor:这个方式类似于byType, 但是要提供给构造器参数,如果没有确定的带参数的构造器参数类型,将会抛出异常。
  • autodetect:首先尝试使用constructor来自动装配,如果无法工作,则使用byType方式。

5、AOP

概念:aop是建立在java的反射基础上,将程序种公共的部分提取出来做成切面类,便于代码的复用,一旦需要改该功能的需求发生变化只需要改该代码即可。AOP的实现方式主要有JDK动态代理和CGLIB。

image.png

意义:增强类的功能(在目标对象的方法执行之间和执行之后);各个步骤之间的良好隔离性耦合性大大降低;源代码无关性,再拓展功能的同时不对源码进行修改操作。
原理:

  • 静态代理:AspectJ,AOP框架会在编译阶段将AspectJ织入Java的字节码中;AspectJ是静态代理的增强,所谓的静态代理就是AOP框架会在编译阶段生成AOP代理类,在程序运行之前,代理类的.class文件就已经生成,因此也称为编译时增强
  • 动态代理:AOP不会去修改字节码,而是在内存中临时为方法生成一个AOP对象,这个对象包含了目标对象的全部方法,并在特定的切点去做了增强处理,并回调原对象方法。主要有JDK动态代理(接口)和CGLIB动态代理(继承),JDK动态代理主要通过反射来接受被处理的对象,并且要求被代理的对象必须实现一个接口。
    JDK动态接口代理
    JDK动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编制在一起。Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。
    CGLib动态代理
    CGLib全称为Code Generation Library,是一个强大的高性能,高质量的代码生成类库,可以在运行期扩展Java类与实现Java接口,CGLib封装了asm,可以再运行期动态生成新的class。和JDK动态代理相比较:JDK创建代理有一个限制,就是只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,则可以通过CGLib创建动态代理。

6、SpringBean的作用域

  • Singleton:IOC容器仅创建一个Bean实例,IOC容器每次返回的都是同一个Bean实例默认的作用域
  • prototype:IOC容器可以创建多个Bean实例,每次返回的都是一个新的实例;
  • request:每次Http请求都会创建一个新的实例;
  • session:同一个session共享一个Bean实例;
  • global-session:所有的session共享一个Bean实例;

7、Bean的生命周期:
image.png

  • 实例化
    实例化一个Bean,也就是我们常说的new;
  • IOC依赖注入
    按照Spring上下文对实例化的Bean进行配置;
  • setBeanName实现
    如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String)方法,此处传递的就是Spring配置文件中Bean的id值;
  • BeanFactoryAware实现
    如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory(setBeanFactory(BeanFactory)传递的是Spring工厂自身(可以用这个方式来获取其它Bean,只需在Spring配置文件中配置一个普通的Bean就可以);
  • ApplicationContextAware实现
    如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文(同样这个方式也可以实现步骤4的内容,但比4更好,因为ApplicationContext是BeanFactory的子接口,有更多的实现方法);
  • postProcessBeforeInitialization接口实现-初始化预处理
    如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用那个的方法,也可以被应用于内存或缓存技术;
  • init-method
    如果Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法;
  • postProcessAfterInitialization
    如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法、;
    注:以上工作完成以后就可以应用这个Bean了,那这个Bean是一个Singleton的,所以一般情况下我们调用同一个id的Bean会是在内容地址相同的实例,当然在Spring配置文件中也可以配置非Singleton,这里我们不做赘述。
  • Destroy过期自动清理阶段
    当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用那个其实现的destroy()方法;
  • destroy-method自配置清理
    最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。
    一旦把一个bean纳入到Spring IoC容器之中,这个bean的生命周期就会交由容器进行管理,一般担当管理者角色的是BeanFactory或ApplicationContext。

8、Spring处理循环依赖参考

发生循环依赖的三种方式:

  • 构造器参数循环依赖(无法解决)
  • setter方式单例,默认方式
  • setter方式原型,prototype(无法解决)
    Spring bean初始化的循环依赖只能解决单例模式的set方式,spring通过三级缓存来解决单例模式循环依赖。
//singletonObjects指单例对象的cache
private final Map singletonObjects = new ConcurrentHashMap(256);
//单例对象工厂的cache
private final Map> singletonFactories = new HashMap>(16);
//提前曝光的单例对象的cache
private final Map earlySingletonObjects = new HashMap(16);
image.png
  • Spring Bean的的创建包含两部分:当前对象的实例化和对象属性的实例化。Spring中对象的实例化是通过反射来实现的,而对象的属性则是在对象实例化后通过一定的方式来设置的。

9、过滤器和拦截器的区别

  • 拦截器是基于java反射实现的,而过滤器是根据函数回调实现的;
  • 拦截器不依赖servelt,过滤器依赖servelt;
  • 拦截器只能对action请求起作用,过滤器可以对所有请求起作用;
  • 拦截器可以访问action上下文、值、栈里的值,而过滤器不能访问;
  • 在action的生命周期内,拦截器可以多次被调用,而过滤器只能在容器被初始化时被调用一次;
  • 拦截器可以获取IOC容器的各个Bean,过滤器不能。

10、Spring中用到的设计模式

  • 简单工厂:Spring中BeanFactory就是工厂模式的提现,根据传入一个唯一的标识来获得Bean对象;
  • 工厂方法:实现了FactoryBean接口的bean是一类叫做factory的bean。其特点是,spring会在使用getBean()调用获得该bean时,会自动调用该bean的getObject()方法,所以返回的不是factory这个bean,而是这个bean.getOjbect()方法的返回值。
  • 单例模式:Spring依赖注入Bean实例默认是单例的。Spring中的单例模式提供了一个全局的访问点BeanFactory,没有从构造器级别去控制实例,因为Spring管理的是任意的Bean。
  • 适配器模式:SpringMVC中的HandlerAdatper根据Handler规则执行不同的Handler。Spring定义了一个适配接口,使得每一种Controller有一种对应的适配器实现类,让适配器代替controller执行相应的方法。这样在扩展Controller时,只需要增加一个适配器类就完成了SpringMVC的扩展了。
  • 装饰器模式:Spring中用到的包装器模式在类名上有两种表现:一种是类名中含有Wrapper,另一种是类名中含有Decorator。
  • 代理模式:AOP底层,就是动态代理模式的实现。切面在应用运行的时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象创建动态的创建一个代理对象。SpringAOP就是以这种方式织入切面的。
  • 观察者模式:spring的事件驱动模型使用的是 观察者模式 ,Spring中Observer模式常用的地方是listener的实现。
  • 策略模式:Spring框架的资源访问Resource接口。该接口提供了更强的资源访问能力,Spring 框架本身大量使用了 Resource 接口来访问底层资源。
  • 模版方法模式:是模板方法模式和回调模式的结合,是Template Method不需要继承的另一种实现方式。Spring几乎所有的外接扩展都采用这种模式。

11、JPA 原理

事务是计算机应用中不可或缺的组件模型,它保证了用户操作的原子性 ( Atomicity )、一致性 ( Consistency )、隔离性 ( Isolation ) 和持久性 ( Durabilily )。

11.1

  • 本地事务
    紧密依赖于底层资源管理器(例如数据库连接 ),事务处理局限在当前事务资源内。此种事务处理方式不存在对应用服务器的依赖,因而部署灵活却无法支持多数据源的分布式事务。在数据库连接中使用本地事务示例如下:
public void transferAccount() {
  Connection conn = null;
  Statement stmt = null;
  try{
    conn = getDataSource().getConnection();
    // 将自动提交设置为 false,若设置为 true 则数据库将会把每一次数据更新认定为一个事务并自动提交
    conn.setAutoCommit(false);
    stmt = conn.createStatement();
    // 将 A 账户中的金额减少 500
    stmt.execute("update t_account set amount = amount - 500 where account_id = 'A'");
    // 将 B 账户中的金额增加 500
    stmt.execute("update t_account set amount = amount + 500 where account_id = 'B'");
    // 提交事务
    conn.commit();
    // 事务提交:转账的两步操作同时成功
  } catch(SQLException sqle){
    // 发生异常,回滚在本事务中的操做
    conn.rollback();
    // 事务回滚:转账的两步操作完全撤销
    stmt.close();
    conn.close();
  }
}
  • 分布式事务
    Java 事务编程接口(JTA:Java Transaction API)和 Java 事务服务 (JTS;Java Transaction Service) 为 J2EE 平台提供了分布式事务服务。分布式事务(Distributed Transaction)包括事务管理器(Transaction Manager)和一个或多个支持 XA 协议的资源管理器 ( Resource Manager )。我们可以将资源管理器看做任意类型的持久化数据存储;事务管理器承担着所有事务参与单元的协调与控制。比较适合单块应用里,跨多个库的分布式事务
public void transferAccount() {
  UserTransaction userTx = null;
  Connection connA = null; Statement stmtA = null;
  Connection connB = null; Statement stmtB = null;
  try{
    // 获得 Transaction 管理对象
    userTx = (UserTransaction)getContext().lookup("java:comp/UserTransaction");
    connA = getDataSourceA().getConnection();// 从数据库 A 中取得数据库连接
    connB = getDataSourceB().getConnection();// 从数据库 B 中取得数据库连接
    userTx.begin(); // 启动事务
    stmtA = connA.createStatement();// 将 A 账户中的金额减少 500
    stmtA.execute("update t_account set amount = amount - 500 where account_id = 'A'");
    // 将 B 账户中的金额增加 500
    stmtB = connB.createStatement();
    stmtB.execute("update t_account set amount = amount + 500 where account_id = 'B'");
    userTx.commit();// 提交事务
    // 事务提交:转账的两步操作同时成功(数据库 A 和数据库 B 中的数据被同时更新)
  } catch(SQLException sqle){
    // 发生异常,回滚在本事务中的操纵
    userTx.rollback();// 事务回滚:数据库 A 和数据库 B 中的数据更新被同时撤销 
  } catch(Exception ne){ }
}

两阶段提交主要保证了分布式事务的原子性:即所有结点要么全做要么全不做,所谓的两个阶段是指:第一阶段:准备阶段;第二阶段:提交阶段。
1)准备阶段
事务协调者(事务管理器)给每个参与者(资源管理器)发送Prepare消息,每个参与者要么直接返回失败(如权限验证失败),要么在本地执行事务,写本地的redo和undo日志,但不提交,到达一种“万事俱备,只欠东风”的状态。
2)提交阶段
如果协调者收到了参与者的失败消息或者超时,直接给每个参与者发送回滚(Rollback)消息;否则,发送提交(Commit)消息;参与者根据协调者的指令执行提交或者回滚操作,释放所有事务处理过程中使用的锁资源。(注意:必须在最后阶段释放锁资源)
将提交分成两阶段进行的目的很明确,就是尽可能晚地提交事务,让事务在提交前尽可能地完成所有能完成的工作。

11.2事务的传播性

一个开启了事务的方法A,调用了另一个开启了事务的方法B,此时会出现什么情况?这就要看传播行为的设置了。

  • PROPAGATION_REQUIRED: 如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。
  • PROPAGATION_SUPPORTS: 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。
  • PROPAGATION_MANDATORY: 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
  • PROPAGATION_REQUIRES_NEW: 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
  • PROPAGATION_NOT_SUPPORTED: 总是非事务地执行,并挂起任何存在的事务。使用PROPAGATION_NOT_SUPPORTED,也需要使用JtaTransactionManager作为事务管理器。
  • PROPAGATION_NEVER: 总是非事务地执行,如果存在一个活动事务,则抛出异常。
  • PROPAGATION_NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行。嵌套事务一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚。

12、Spring MVC接收参数的几种方式(原文地址):

  • 直接把表单的参数写在Controller相应的方法的形参中;
  • 通过HttpServeltRequest接收;
  • 通过一个bean来接收;
  • 通过json数据来接收;

13、JSP内置对象

  • request对象javax.servelt.http.HttpServletRequest,request对象代表客户端的请求信息,主要用于接受通过HTTP协议传送到服务器的数据。
  • response对象javax.servlet.http.HttpServletResponse,response代表的是对客户端的响应,主要是将JSP容器处理过的对象传回到客户端。
  • session对象javax.servlet.http.HttpSession,Session对象是一个JSP内置对象,它在第一个JSP也main被装载时自动创建,完成会话期管理。从一个客户打开浏览器并连接到服务器开始,到客户关闭浏览器离开这个服务器结束,被称为一个会话。当一个客户访问一个服务器时,可能会在这个服务器的几个页面之间切换,服务器通过Session对象知道这是一个客户。
  • application对象javax.servlet.ServletContext,application对象可将信息保存在服务器中,直到服务器关闭,否则application对象中保存的信息会在整个应用中都有效。与session对象相比,application对象生命周期更长,类似于系统的全局变量。
  • out对象javax.servlet.jsp.jspWriter,out对象用于在Web浏览器内输出信息,并且管理应用服务器上的输出缓存区。
  • pageContext对象javax.servelt.jsp.PageContext,pageContext对象的作用是取得任何范围的参数,通过它可以获取JSP页面的out、response、request、session、application等对象在jsp页面可以直接使用pageCOntext对象。
  • config对象javax.servlet.ServletConfig,config对象的主要作用是取得服务器的配置信息。
  • cookie对象,cookie是web服务器保存在用户硬盘上的一段文本。
  • exception对象java.lang.Throwable,exception对象的作用是显示异常信息,只有在包含isErrorPage=”true”的页面才可以使用,在一般的JSP页面中使用该对象将无法编译JSP文件。

14、BeanFactory和ApplicationContext的区别

接口 BeanFactory 和 ApplicationContext 都是用来从容器中获取 Spring beans( Spring 容器所管理的 Java 对象)。

  • BeanFactory 接口
    这是一个用来访问 Spring 容器的 root 接口,要访问 Spring 容器,我们将使用 Spring 依赖注入功能,使用 BeanFactory 接口和它的子接口 特性:BeanFactory 的实现是使用懒加载的方式,这意味着 beans 只有在我们通过getBean() 方法直接调用它们时才进行实例化 实现 BeanFactory 。
  • ApplicationContext 接口
    ApplicationContext 是 Spring 应用程序中的中央接口,用于向应用程序提供配置信息 它继承了 BeanFactory 接口,所以 ApplicationContext 包含 BeanFactory 的所有功能以及更多功能。ApplicationContext在启动的时候就把所有的Bean全部实例化了。它还可以为Bean配置lazy-init=true来让Bean延迟实例化;

你可能感兴趣的:(Spring)