SpringMVC面试题

一、springMVC工作原理:

1.spring mvc请所有的请求都提交给DispatcherServlet,它会委托应用系统的其他模块负责负责对请求进行真正的处理工作。 

2.DispatcherServlet查询一个或多个HandlerMapping,找到处理请求的Controller.

3.DispatcherServlet请请求提交到目标Controller

4.Controller进行业务逻辑处理后,会返回一个ModelAndView

5.Dispathcher查询一个或多个ViewResolver视图解析器,找到ModelAndView对象指定的视图对象 

6.视图对象负责渲染返回给客户端。 

 

二、为什么要用spring

 

三、介绍一下Spring的事务管理

     事务就是对一系列的数据库操作(比如插入多条数据)进行统一的提交或回滚操作,如果插入成功,那么一起成功,如果中间有一条出现异常,那么回滚之前的所有操作。 

这样可以防止出现脏数据,防止数据库数据出现问题。 开发中为了避免这种情况一般都会进行事务管理。Spring中也有自己的事务管理机制,一般是使用TransactionMananger进行管理,可以通过Spring的注入来完成此功能。

     sping的事务管理的两种方式:

1、编程式(粒度是到代码块级别);

       编程式主要使用transactionTemplate;手动编程管理事务

2、声明式(粒度是到方法级别);

    通过AOP实现,  其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。

@Transactional注解

用法

       @Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。

         虽然 @Transactional 注解可以作用于接口、接口方法、类以及类方法上,但是 Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外, @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的,Spring使用AOP代理实现事务特性;代理有2种,分别是基于接口和基于类(代理机制有兴趣可百度一下);而这2种代理机制均不能实现或继承private方法。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。

        默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰。

 

事务隔离级别

  隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:

  • TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。比如PostgreSQL实际上并没有此级别。
  • TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
  • TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读。
  • TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

事务传播行为

      所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:

  • TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
  • TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
  • TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  • TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
  • TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
  • TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

总结:

  Spring将事务管理分为了两类:

               一、编程式事务管理

                     需要手动编写代码进行事务的管理(一般不用)

               二、声明式事务管理:

                 1、基于TransactionProxyFactoryBean的方式(很少使用) 

                          需要为每个事务管理的类配置一个TransactionProxyFactoryBean进行管理。使用时还需要在类中注入该代理类。

                  2、基于AspectJ的方式(常使用)

                        配置好之后,按照方法的名字进行管理,无需再类中添加任何东西。

                  3、基于注解的方式(经常使用)

                        配置简单,在业务层类上添加注解@Transactional。

     

Spring声明式事务处理的步骤:

                       1、搭建环境,引入tx和context命名空间;

                       2、在spring的配置文件中,先导入dataSource;

                      3、测试dataSource是否配置正确;(可省略)

                       4、导入dao和service层的bean

                      5、测试dao和service是否配置正确(可省略)

                     6、引入事务管理器

                      7、 配置通知<tx:advice/>

                     8、启用事务通知<aop:config/>,将切入点和通知器织入

                      9、测试service层的类,看是否是代理对象。

 

四、Spring里面如何配置数据库驱动?

 

使用”org.springframework.jdbc.datasource.DriverManagerDataSource”数据源来配置数据库驱动。示例如下: 

<bean id=”dataSource”>

    <property name=”driverClassName”>

        <value>org.hsqldb.jdbcDriver</value>

    </property>

    <property name=”url”>

        <value>jdbc:hsqldb:db/appfuse</value>

    </property>

    <property name=”username”><value>sa</value></property>

    <property name=”password”><value></value></property>

</bean>

数据库连接池的话:采用的是阿里的数据库连接池,com.alibaba.druid.pool.DruidDataSource

五、解释一下Dependency injection(DI,依赖注入)IOC(Inversion of control,控制反转)?

 

       传统上由程序代码直接操控的对象的调用权交给容器,现在通过容器来实现对象组件的装配和管理。

       在应用程序中,经常涉及到多个对象的操作,对象之间的依赖关系很大,一个对象改换,应用程序就要相应的修改,我们把对象依赖的资源交给第三方进行管理,需要操作该资源的时候,直接由第三方容器注入就行,依赖对象的整个生命周期由容器负责管理。

 

六、spring中的BeanFactoryApplicationContext的作用有哪些? 

 

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

Spring 提供了两种类型的 IOC 容器实现. 

  • BeanFactory: IOC 容器的基本实现.
  • ApplicationContext: 提供了更多的高级特性. 是 BeanFactory 的子接口.

         Bean 工厂( com.springframework.beans.factory.BeanFactory )是 Spring 框架中最核心的接口,它提供了高级 IoC 的配置机制 。BeanFactory 使管理不同类型的 Java 对象成为可能。而

         应用上下文( com.springframework.context.ApplicationContext )建立在 BeanFactory 基础之上,提供了更多面向应用的功能,它提供了国际化支持和框架事件体系,更易于创建实际应用 。

我们一般称 BeanFactory 为 IoC 容器,而称 ApplicationContext 为应用上下文或 Spring 容器 。

 

1、BeanFactory(Bean工厂,可以创建并管理各种类的对象,Spring 称这些被创建并管理的类对象为 Bean,启动时需要手动编写代码)

     BeanFactory负责读取bean配置文档,管理bean的加载,实例化,维护bean之间的依赖关系,负责bean的声明周期。BeanFactory 只能管理单例(Singleton)Bean 的生命周期。它不能管理原型(prototype,非单例)Bean 的生命周期。这是因为原型 Bean 实例被创建之后便被传给了客户端,容器失去了对它们的引用。

   BeanFactory在启动容器时,并不会初始化配置文件中定义的Bean,初始化发生在第一次调用,对于单例的Bean,BeanFactory会缓存在Bean实例,所以在第二次使用时,直接从缓存中获取Bean实例。

 

   具体如何获取bean的操作:

         BeanFactory 有众多的实现,建议是XmlBeanDefinitionReader 与 DefaultListableBeanFactory。:

1、初始化Bean(在配置文件中配置people类,在代码中通过XmlBeanDefinitionReader 与 DefaultListableBeanFactory启动IOC容器,实例化bean)

 

       采取延迟加载,第一次getBean时才会初始化Bean

     

      过程:Resource 来装载 Spring 的配置信息   ----->  getBean(name) 获取 Bean

.

      在 Spring 配置文件中配置 Bean People,然后通过 BeanFactory 加载配置文件,启动 Ioc 容器。

     Spring 配置文件:

    

     然后使用 DefaultListableBeanFactory 与 XmlBeanDefinitionReader 来启动 Ioc 容器:(在代码中,初始化bean工厂)

    XmlBeanDefinitionReader 通过 Resource 来装载 Spring 的配置信息并启动 Ioc 容器,然后就可以通过 BeanFactory#getBean(name) 获取 Bean 咯。Bean 初始化操作发生在第一次调用时(而不是spring初始化期间)。对于单实例的 Bean 来说, BeanFactory 会缓存 Bean 实例, 所以第二次使用 getBean() 方法时就会直接从 IoC 容器的缓存中获取 Bean 的实例。

 

 

 

2、ApplicationContext() ( 对BeanFactory功能的增强)


   ApplicationContext 由 BeanFactory 派生而来,提供了很多实际应用的功能 。 在 BeanFactory 中,很多功能需要以编程的方式实现,而在 ApplicationContext 中则可以通过配置的方式来实现。 所以大多数的用户更喜欢使用ApplicationContext的XML形式,通过ApplicationContext对象来管理bean,ApplicationContext除了提供上述BeanFactory所能提供的功能之外,还提供了更完整的框架功能:

a. 国际化支持
b. 资源访问:Resource rs = ctx. getResource(“classpath:config.properties”), “file:c:/config.properties”
c. 事件传递:通过实现ApplicationContextAware接口
3. 常用的获取ApplicationContext的方法:
FileSystemXmlApplicationContext:从文件系统或者url指定的xml配置文件创建,参数为配置文件名或文件名数组
ClassPathXmlApplicationContext:从classpath的xml配置文件创建,可以从jar包中读取配置文件
WebApplicationContextUtils:从web应用的根目录读取配置文件,需要先在web.xml中配置,可以配置监听器或者servlet来实现

 

初始化ApplicationContext

         ApplicationContext则在初始化应用上下文时就实例化所有单实例的Bean。

 

初始化 ApplicationContext 时,根据配置文件的所在路径,来选择 ApplicationContext 的实现类。

ApplicationContext 的主要实现类是:

  1. ClassPathXmlApplicationContext - 从类路径加载配置文件。
  2. FileSystemXmlApplicationContext - 从文件系统加载配置文件。

 

ApplicationContext 与 BeanFactory 初始化之间的区别:

  • ApplicationContext - 在初始化应用上下文时,会实例化所有单实例的 Bean,所以相对来说,初始化时间会比 BeanFactory 稍长,不过稍后的调用没有 “第一次惩罚” 的问题。但是由于是单例,之后使用就能够快速得到Bean。如果不希望Spring容器一开始就初始化某一个Bean,可以在<bean ../>元素指定lazy-init="true",这样只有在需要用到该类时,才初始化。
  • BeanFactory - 在初始化容器时,并未实例化 Bean。直到 Bean 被访问时,才会被实例化。

 

 

BeanFactory与FactoryBean

没有更多推荐了,返回首页