Spring技术要点
1、spring的好处/特点 轻量:Spring是轻量的,基本的版本大约2MB。 控制反转(IOC):Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。 面向切面的编程(AOP):Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。 容器:Spring包含并管理应用中对象的生命周期和配置。 MVC框架:Spring的
1、spring的好处/特点
- 轻量:Spring是轻量的,基本的版本大约2MB。
- 控制反转(IOC):Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。
- 面向切面的编程(AOP):Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。
- 容器:Spring包含并管理应用中对象的生命周期和配置。
- MVC框架:Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品。
- 事务管理:Spring提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)。
- 异常处理:Spring提供方便的API把具体技术相关的异常(比如由JDBC,Hibernateor JDO抛出的)转化为一致的unchecked 异常。
2、Spring主要模块组成
- Core module
- Bean module
- Context module
- Expression Language module
- JDBC module
- ORM module
- OXM module
- Java Messaging Service(JMS) module
- Transaction module
- Web module
- Web-Servlet module
- Web-Struts module
- Web-Portlet module
3、Spring IOC/DI(控制反转/依赖注入)
简单的理解就是,原先将本程序中所使用到的对象,的生命周期交给容器去维护和管理。这就是IOC。SpringIOC 负责创建对象,管理对象(通过依赖注入(DI),装配对象,配置对象,并且管理这些对象的整个生命周期。
对于DI的理解是,本类中所使用到的其他对象,在程序代码中只需要声明一下,相关实例化的工作交给了容器,容器会在运行期new出相应的对象,并赋值给程序代码。这个过程类似于注入的过程。
4、ApplicationContext的实现
- FileSystemXmlApplicationContext:此容器从一个XML文件中加载beans的定义,XMLBean 配置文件的全路径名必须提供给它的构造函数。
- ClassPathXmlApplicationContext:此容器也从一个XML文件中加载beans的定义,这里,你需要正确设置classpath因为这个容器将在classpath里找bean配置。
- WebXmlApplicationContext:此容器加载一个XML文件,此文件定义了一个WEB应用的所有bean。
5、BeanFactory和ApplicationContext的区别
- BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化,这样,我们就不能发现一些存在的Spring的配置问题。而ApplicationContext则相反,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误。
- ApplicationContext建立在BeanFactory之上,并增加了其他的功能,比如更容易同SpringAOP特性整合, 消息资源处理(用于国际化),事件传递,以声明的方式创建ApplicationContext,可选的父上下文和与应用层相关的上下文(比如WebApplicationContext),以及其他方面的增强。
表格 1 BeanFactory和ApplicationContext对比
特性 | BeanFactory | ApplicationContext |
Bean实例化/装配 | Yes | Yes |
自动BeanPostProcessor注册 | No | Yes |
自动BeanFactoryPostProcessor注册 | No | Yes |
便捷的MessageSource访问(i18n) | No | Yes |
ApplicationEvent发送 | No | Yes |
6、获取ApplicationContext的方式
- 直接new出ApplicationContext
- 通过Spring提供的工具类获取ApplicationContext对象(WebApplicationContextUtils)
- 继承自抽象类ApplicationObjectSupport。说明:抽象类ApplicationObjectSupport提供getApplicationContext()方法,可以方便的获取到ApplicationContext。Spring初始化时,会通过该抽象类的setApplicationContext(ApplicationContextcontext)方法将ApplicationContext 对象注入。
- 继承自抽象类WebApplicationObjectSupport。说明:类似上面方法,调用getWebApplicationContext()获取WebApplicationContext
- 实现接口ApplicationContextAware
说明:实现该接口的setApplicationContext(ApplicationContextcontext)方法,并保存ApplicationContext 对象。Spring初始化时,会通过该方法将ApplicationContext对象注入。
7 Spring IOC(依赖注入)的方式
- Setter方法注入
- 构造器方法注入
- 工厂方法注入(实例工厂/静态工厂)
- 使用字段(Filed)注入(用注解方式)
- 自动装配(需要开启配置,不建议使用)
8 IOC方式建议(构造器注入还是 Setter方法注入)
两种依赖方式都可以使用,构造器注入和Setter方法注入。最好的解决方案是用构造器参数实现强制依赖,setter方法实现可选依赖。
9 什么是Spring beans
Springbeans是那些形成spring应用的主干的Java对象。它们被SpringIOC容器初始化,装配,和管理。这些beans通过容器中配置的元数据创建。比如,以XML文件中<bean/>的形式定义。
Spring框架定义的beans都是单例beans。在beantag中有个属性”singleton”,如果它被赋为TRUE,bean 就是单例,否则就是一个prototype bean。默认是TRUE,所以所有在Spring框架中的beans缺省都是单例。
10 Spring Bean定义包含什么
一个SpringBean的定义包含容器必知的所有配置元数据,包括如何创建一个bean,它的生命周期详情及它的依赖。
11 Spring容器提供配置元数据的方式
这里有三种重要的方法给Spring容器提供配置元数据。
- XML配置文件。
- 基于注解的配置。
- 基于java的配置。
12 Spring类的作用域
Spring framework支持五种作用域(其中有三种只能用在基于web的SpringApplicationContext)。
表格 2 spring scope作用域详解
singleton | 在每个Spring IoC容器中一个bean定义对应一个对象实例。 |
prototype | 一个bean定义对应多个对象实例。 |
request | 在一次HTTP请求中,一个bean定义对应一个实例;即每次HTTP请求将会有各自的bean实例,它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。 |
session | 在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。 |
global session | 在一个全局的HTTP Session中,一个bean定义对应一个实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于web的Spring ApplicationContext情形下有效。 |
13 Spring的单例bean是不是线程安全的
不,Spring框架中的单例bean不是线程安全的。
14 Spring中bean的生命周期
- Bean的建立:Spring容器从XML 文件中读取bean的定义,并实例化bean。
- 属性注入:Spring根据bean的定义填充所有的属性。
- 如果bean实现了BeanNameAware接口,Spring传递bean的ID到setBeanName方法。
- 如果Bean实现了BeanFactoryAware接口,Spring传递beanfactory给setBeanFactory方法。
- 如果Bean实现了ApplicationContextAware接口,Spring传递applicationContext给setApplicationContext方法。
- 如果有任何与bean相关联的BeanPostProcessors,Spring会在postProcesserBeforeInitialization()方法内调用它们。
- 如果bean实现IntializingBean了,调用它的afterPropertySet方法,如果bean声明了初始化方法,调用此初始化方法。
- 执行Bean的init-method:可以在Bean定义文件中使用"init-method"属性设定方法名称例如:<beancalss="onlyfun.caterpillar.HelloBean"init-method="initBean">。
- 如果有BeanPostProcessors和bean 关联,这些bean的postProcessAfterInitialization()方法将被调用。
- 如果bean实现了DisposableBean,它将调用destroy()方法。
- 执行Bean的destroy-method:在容器关闭时,可以在Bean定义文件中使用"destroy-method"属性设定方法名称,例如:<bean destroy-method="destroyBean">
15 Spring的内部bean
Spring的内部Bean在做注入时,只能用于当前的Bean属性注入,在外不可以引用。在Spring的 基于XML的 配置元数据中,可以在<property/>或<constructor-arg/> 元素内使用<bean/> 元素,内部bean通常是匿名的,它们的Scope一般是prototype。
16 Spring中注入java集合
Spring提供以下几种集合的配置元素:
- <list>类型用于注入一列值,允许有相同的值。
- <set>类型用于注入一组值,不允许有相同的值。
- <map>类型用于注入一组键值对,键和值都可以为任意类型。
- <props>类型用于注入一组键值对,键和值都只能为String类型
17 bean装配和自动装配
bean 装配:是指在Spring容器中把bean组装到一起,前提是容器需要知道bean的依赖关系,如何通过依赖注入来把它们装配到一起。
Spring容器能够自动装配相互合作的bean,这意味着容器不需要<constructor-arg>和<property>配置,能通过Bean工厂自动处理bean之间的协作。
18 Spring自动装配的方式
有五种自动装配的方式,可以用来指导Spring容器用自动装配方式来进行依赖注入。
- no:默认的方式是不进行自动装配,通过显式设置ref属性来进行装配。
- byName:通过参数名自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byname,之后容器试图匹配、装配和该bean的属性具有相同名字的bean。
- byType::通过参数类型自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byType,之后容器试图匹配、装配和该bean的属性具有相同类型的bean。如果有多个bean符合条件,则抛出错误。
- constructor:这个方式类似于byType,但是要提供给构造器参数,如果没有确定的带参数的构造器参数类型,将会抛出异常。
- autodetect:首先尝试使用constructor来自动装配,如果无法工作,则使用byType方式。
19 自动装配的局限性
自动装配的局限性是:
- 重写:你仍需用<constructor-arg>和<property> 配置来定义依赖,意味着总要重写自动装配。
- 基本数据类型:你不能自动装配简单的属性,如基本数据类型,String字符串和类。
- 模糊特性:自动装配不如显式装配精确,如果有可能,建议使用显式装配。
20 基于Java的spring注解配置(给一些注解的例子)
基于Java的配置,允许你在少量的Java注解的帮助下,进行你的大部分Spring配置而非通过XML文件。
以@Configuration注解为例,它用来标记类可以当做一个bean的定义,被SpringIOC容器使用。另一个例子是@Bean注解,它表示此方法将要返回一个对象,作为一个bean注册进Spring应用上下文。(一般很少用java代码对元数据进行配置)
21 Spring基于注解的容器配置、和开启配置
相对于XML文件,注解型的配置依赖于通过字节码元数据装配组件,而非尖括号的声明。开发者通过在相应的类,方法或属性上使用注解的方式,直接组件类中进行配置,而不是使用xml表述bean的装配关系。
注解装配在默认情况下是不开启的,为了使用注解装配,我们必须在Spring配置文件中配置<context:annotation-config/> 元素。(<context:annotation-config/>标签可以开启自动扫描,同时也开启注解装配)
22 Spring注解简介
- @Required:这个注解表明bean的属性必须在配置的时候设置,通过一个bean定义的显式的属性值或通过自动装配,若@Required注解的bean属性未被设置,容器将抛出BeanInitializationException。
- @Autowired:注解提供了更细粒度的控制,包括在何处以及如何完成自动装配。它的用法和@Required一样,修饰setter方法、构造器、属性或者具有任意名称和/或多个参数的PN方法。
- @Qualifier:当有多个相同类型的bean却只有一个需要自动装配时,将@Qualifier注解和@Autowire 注解结合使用以消除这种混淆,指定需要装配的确切的bean。
23 @Autowired 和@Resource 的区别
- @Autowired和@Resource都可以用来装配bean,都可以写在字段上,或者方法上。
- @Autowired属于Spring的;@Resource为JSR-250标准的注释,属于J2EE的。
- @Autowired默认按类型装配,默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,例如:@Autowired(required=false),如果我们想使用名称装配可以结合@Qualifier注解进行使用,如下:
@Autowired()
@Qualifier("baseDao")
private BaseDao baseDao;
- @Resource,默认安装名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。例如:
@Resource(name="baseDao")
private BaseDao baseDao;
推荐使用:@Resource注解在字段上,这样就不用写setter方法了,并且这个注解是属于J2EE的,减少了与spring的耦合。这样代码看起就比较优雅。
24 spring对DAO的支持
Spring对数据访问对象(DAO)的支持旨在简化它和数据访问技术如JDBC,Hibernateor JDO 结合使用。这使我们可以方便切换持久层。编码时也不用担心会捕获每种技术特有的异常。
- 优化了的异常类型体系:细化了数据访问异常,丰富了异常类型。(都是 Unchecked Exception,这种异常不会变动,采用同一种异常,表示同一种现象,与使用的持久化技术无关)
- 使用模板回调模式,开发者不再写模式化代码,简化编程:
不变:资源的获取,资源的释放,异常转化(Spring提供了模板类对此负责)。
变化:SQL,变量,结果集的提取。
25 基于JDBC的DAO(Hibernate类似)
简化对JDBC的操作
- 模板负责:JDBC对象的获取释放,异常类型的转化。
- 开发负责:提供SQL,设置SQL中的变量,提取ResultSet。
应用
- 核心方法:query() update()
- 回调接口:PreparedStatementCreator、PreparedStatementSetter、ResultSetExtractor、RowMapper
DAO中获得JdbcTemplate的两种方式:
- 给DAO注入JdbcTempate:Bean配置:DataSource->JdbcTemplate(需要bean工厂控制)->DAO
- 使DAO类继承 JdbcDaoSupport:继承的方法getJdbcTemplate()、Bean配置:DataSource->DAO。
26 Spring+Hibernate访问数据库的方式
在Spring中有两种方式访问hibernate:
- 使用HibernateTemplate和Callback。(推荐)
- 继承HibernateDAOSupport。(不推荐)
- 直接使用SessionFactory(不推荐)
27 通过HibernateDaoSupport将Spring和Hibernate集成
用Spring的SessionFactory调用LocalSessionFactory。集成过程分三步:
- 配置HibernateSessionFactory。
- 继承HibernateDaoSupport实现一个DAO。
- 在AOP支持的事务中装配。
28 Spring支持的事务管理类型
Spring支持两种类型的事务管理:
- 编程式事务管理:这意味你通过编程的方式管理事务,给你带来极大的灵活性,但是难维护。
- 声明式事务管理:这意味着你可以将业务代码和事务管理分离,你只需用注解和XML配置来管理事务。
29 Spring事务管理的优点
- 它为不同的事务API 如JTA,JDBC,Hibernate,JPA和JDO,提供一个不变的编程模式。
- 它为编程式事务管理提供了一套简单的API而不是一些复杂的事务API。
- 它支持声明式事务管理。
- 它和Spring各种数据访问抽象层很好得集成。
30 常用的内置事务管理器实现
- DataSourceTransactionManager:位于org.springframework.jdbc.datasource包中,数据源事务管理器,提供对单个javax.sql.DataSource事务管理,用于SpringJDBC抽象框架、iBATIS框架的事务管理;
- HibernateTransactionManager:位于org.springframework.orm.hibernate3或者hibernate4包中,提供对单个org.hibernate.SessionFactory事务支持,用于集成Hibernate框架时的事务管理;该事务管理器只支持Hibernate3+版本,且Spring3.0+版本只支持Hibernate3.2+版本;
- JtaTransactionManager:位于org.springframework.transaction.jta包中,提供对分布式事务管理的支持,并将事务管理委托给JavaEE应用服务器事务管理器;
31 Spring事务的传播行为(propagation)7个
- required:指定当前方法必需在事务环境中运行,如果当前有事务环境就加入当前正在执行的事务环境,如果当前没有事务,就新建一个事务。这是默认值。
- supports:指定当前方法加入当前事务环境,如果当前没有事务,就以非事务方式执行。
- mandatory:指定当前方法必须加入当前事务环境,如果当前没有事务,就抛出异常。
- requires_new:当前方法总是会为自己发起一个新的事务,如果发现当前方法已运行在一个事务中,则原有事务被挂起,自己创建一个属于自己的事务,直到自己这个方法commit结束,原先的事务才会恢复执行。
- not_supported:当前方法以非事务方式执行操作,如果当前存在事务,就把当前事务挂起,等以非事务的状态运行完,再继续原来的事务。
- never:当前方法绝对不能在事务范围内执行,如果方法在某个事务范围内执行,容器就抛异常,只有没关联到事务,才正常执行。
- nested:指定当前方法执行时,如果已经有一个事务存在,则运行在这个嵌套的事务中。如果当前环境没有运行的事务,就新建一个事务,并与父事务相互独立,这个事务拥有多个可以回滚的保证点。就是指我自己内部事务回滚不会对外部事务造成影响,只对DataSourceTransactionManager事务管理器起效。
32 Spring事务配置属性详解(<tx:method >或@Transactional)
表格3 Spring事务配置选项
属性 | 类型 | 默认值 | 说明 |
propagation | Propagation枚举 | REQUIRED | 事务传播属性 |
isolation | isolation枚举 | DEFAULT(所用数据库默认级别) | 事务隔离级别 |
readOnly | boolean | false | 是否用优化的只读事务 |
timeout | int | -1 | 超时(秒) |
rollbackFor | Class[] | {} | 需要回滚的异常类 |
rollbackForClassName | String[] | {} | 需要回滚的异常类名 |
noRollbackFor | Class[] | {} | 不需要回滚的异常类 |
noRollbackForClassName | String[] | {} | 不需要回滚的异常类名 |
33 spring AOP的概念
面向切面的编程,是一种编程技术,是OOP(面向对象编程)的补充和完善。OOP的执行是一种从上往下的流程,并没有从左到右的关系。因此在OOP编程中,会有大量的重复代码。而AOP则是将这些与业务无关的重复代码抽取出来,然后再嵌入到业务代码当中。常见的应用有:权限管理、日志、事务管理等。
实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。Spring AOP实现用的是动态代理的方式。
34 AOP的相关概念
- 切面/方面(Aspect):AOP核心就是切面,它将多个类的通用行为封装成可重用的模块,该模块含有一组API提供横切功能。如,一个日志模块可以被称作日志的AOP切面。根据需求的不同,一个应用程序可以有若干切面。在SpringAOP中,切面通过带有@Aspect注解的类实现。
- 连接点(Joinpoint):程序执行过程中明确的点,如方法的调用或特定的异常被抛出。
- 通知/增强(Advice):在切入点上,可以应用的增强包括:around、before和throws。许多AOP框架包括Spring都是以拦截器做通知模型,维护一个“围绕”连接点的拦截器链。Spring中定义了四个advice:BeforeAdvice, AfterAdvice, ThrowAdvice和DynamicIntroductionAdvice。
- 切入点(Pointcut):将被增强(Advice)应用的连接点的集合(通常是Method集合)。Spring定义了Pointcut接口,用来组合MethodMatcher和ClassFilter,可以通过名字很清楚的理解,MethodMatcher是用来检查目标类的方法是否可以被应用此通知,而ClassFilter是用来检查Pointcut是否应该应用到目标类上。
- 目标对象(TargetObject):被通知(Advice)或被代理对象。
- AOP代理(AOP Proxy):AOP框架创建的对象,包含通知(Advice)。在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。
35 Spring AOP的增强/通知(Advice)类型
- Before Advice:在方法执行前执行。
- AfterAdvice:在方法执行之后调用的通知,无论方法执行是否成功。
- After ReturningAdvice:在方法执行后返回一个结果后执行。
- After ThrowingAdvice:在方法执行过程中抛出异常的时候执行。
- Around Advice:在方法执行前后和抛出异常时执行,相当于综合了以上三种通知。(相关接口MethodIntercept)
- IntroductionAdvice(引入增强):引入通知是一种特殊的通知,它能将新的成员变量、成员方法引入到目标类中。它不能作用于任何切入点,因为它只作用于类层次,而不是方法层次。实现引入通知需要实现IntroductionAdvisor和IntroductionInterceptor接口。
36 Spring AOP 的关注点和横切关注的区别
- 关注点是应用中一个模块的行为,一个关注点可能会被定义成一个我们想实现的一个功能。
- 横切关注点是一个关注点,此关注点是整个应用都会使用的功能,并影响整个应用,比如日志,安全和数据传输,几乎应用的每个模块都需要的功能。因此这些都属于横切关注点。
37 引入(Introduction)的概念
引入(Introduction):添加方法或字段到被通知的类。Spring允许引入新的接口到任何被通知的对象。例如,你可以使用一个引入使任何对象实现IsModified接口,来简化缓存。Spring中要使用Introduction,可有通过DelegatingIntroductionInterceptor来实现通知,通过DefaultIntroductionAdvisor来配置Advice和代理类要实现的接口。
38 Spring有几种自动代理器
代理器有三类:
- 基于Bean的名字的自动代理创建器,例如BeanNameAutoProxyCreator
- 基于Advisor(切面)匹配机制的自动代理创建器。对spring容器中的所有的Advisor扫描,并将其应用到匹配的Bean中。例如DefaultAdvisorAutoProxyCreator
- 基于Bean中的AspjectJ注解标签的自动代理创建器,例如AnnotationAwareAspectJAutoProxyCreator
所有的自动代理创建器,都是实现了BeanPostProcessor。spring容器在实例化Bean时,BeanPostProcessor会对其加工,对满足匹配规则的Bean自动创建代理对象。
39 Spring织入概念
织入(Weaving):把切面(Aspect)应用到目标对象来创建新的代理对象的过程,织入一般发生在如下几个时机:
- 编译时:当一个类文件被编译时进行织入,这需要特殊的编译器才可以做的到,例如AspectJ的织入编译器。
- 类加载时:使用特殊的ClassLoader在目标类被加载到程序之前增强类的字节代码。
- 运行时:切面在运行的某个时刻被织入,SpringAOP就是以这种方式织入切面的,原理应该是使用了动态代理技术。
40 Spring AOP的实现方式
1、经典的基于代理的AOP:使用Java代码实现,编写Advice、PointCut,然后提供给Advisor使用。开启自动代理后,即可在applicationContext中获得增强后的bean。
2、@AspectJ注解驱动的切面:基于注解的开发(推荐使用),在项目中需要开启AOP自动代理<aop:aspectj-autoproxy/>。
3、XML Schema方式:需要实现相应的增强接口,如BeforeAdvice、AfterAdvice等。然后利用一下配置如:
41 spring MVC原理
Spring工作流程描述
1、用户向服务器发送请求,请求被Spring前端控制DispatcherServlet捕获;
2、DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;
3、DispatcherServlet根据获得的Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(...)方法)
4、提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
HttpMessageConveter:将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息。
数据转换:对请求消息进行数据转换。如String转换成Integer、Double等。
数据根式化:对请求消息进行数据格式化。如将字符串转换成格式化数字或格式化日期等。
数据验证:验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中。
5、Handler执行完成后,向DispatcherServlet返回一个ModelAndView对象;
6、根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet;
7、ViewResolver结合Model和View,来渲染视图。
8、将渲染结果返回给客户端。
42 Spring MVC的DispatcherServlet
Spring的MVC框架是围绕DispatcherServlet来设计的,它用来处理所有的HTTP请求和响应。DispatcherServlet主要用作职责调度工作,本身主要用于控制流程,主要职责如下:
1、文件上传解析,如果请求类型是multipart将通过MultipartResolver进行文件上传解析;
2、通过HandlerMapping,将请求映射到处理器(返回一个HandlerExecutionChain,它包括一个处理器、多个HandlerInterceptor拦截器);
3、通过HandlerAdapter支持多种类型的处理器(HandlerExecutionChain中的处理器);
4、通过ViewResolver解析逻辑视图名到具体视图实现;
5、本地化解析;
6、渲染具体的视图等;
7、如果执行过程中遇到异常将交给HandlerExceptionResolver来解析。
43 Spring MVC WebApplicationContext
WebApplicationContext继承了ApplicationContext并增加了一些WEB应用必备的特有功能,它不同于一般的ApplicationContext,因为它能处理主题,并找到被关联的servlet。
44 Spring中DispatcherServlet、WebApplicationContext、ServletContext之间的关系
1、首先,对于一个Web应用来说,Web容器提供一个全局的上下文环境(servletContext),为后面的SpringIOC容器作为宿主环境。
2、然后,在web.xml中会有提供ContextLoaderListener。在web容器启动的过程当中,会监听到servletContext的变化,其contextInitialized方法会被调用。在这个方法中,Spring会启动一个跟上下文(WebApplicationContext/XmlWebApplicationContext)。这个就是SpringIOC容器,对应的Bean定义的配置由web.xml中的context-param标签指定。在这个IoC容器初始化完毕后,spring以WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE为属性Key,将其存储到ServletContext中,便于获取;
3、最后,contextLoaderListener监听器初始化完毕后,开始初始化web.xml中配置的Servlet,这个servlet可以配置多个,以最常见的DispatcherServlet为例,这个servlet实际上是一个标准的前端控制器,用以转发、匹配、处理每个servlet请求。DispatcherServlet上下文在初始化的时候会建立自己的IoC上下文,用以持有springmvc相关的bean。在建立DispatcherServlet自己的IoC上下文时,会利用WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE先从ServletContext中获取之前的根上下文(即WebApplicationContext)作为自己上下文的parent上下文。有了这个parent上下文之后,再初始化自己持有的上下文。这个DispatcherServlet初始化自己上下文的工作在其initStrategies方法中可以看到,大概的工作就是初始化处理器映射、视图解析等。这个servlet自己持有的上下文默认实现类也是XmlWebApplicationContext。初始化完毕后,spring以与servlet的名字相关(此处不是简单的以servlet名为Key,而是通过一些转换,具体可自行查看源码)的属性为属性Key,也将其存到ServletContext中,以便后续使用。这样每个servlet就持有自己的上下文,即拥有自己独立的bean空间,同时各个servlet共享相同的bean,即根上下文(第2步中初始化的上下文)定义的那些bean。
45 Spring MVC的注解
@Controller:该注解表明该类扮演控制器的角色,Spring不需要你继承任何其他控制器基类或引用ServletAPI。
@RequestMapping:该注解是用来映射一个URL到一个类或一个特定的方处理法上。
@RequestParam:绑定HttpServletRequest请求参数到控制器方法参数。(默认在方法入参中按参数名绑定)
@RequestHeader:注解绑定HttpServletRequest头信息到Controller方法参数。
@CookieValue:绑定cookie的值到Controller方法参数。
46 @RequestMapping注解支持的方法参数和返回类型
支持的方法参数类型
(1)HttpServlet对象,主要包括HttpServletRequest、HttpServletResponse和HttpSession对象。这些参数Spring在调用处理器方法的时候会自动给它们赋值,所以当在处理器方法中需要使用到这些对象的时候,可以直接在方法上给定一个方法参数的申明,然后在方法体里面直接用就可以了。但是有一点需要注意的是在使用HttpSession对象的时候,如果此时HttpSession对象还没有建立起来的话就会有问题。
(2)Spring自己的WebRequest对象。使用该对象可以访问到存放在HttpServletRequest和HttpSession中的属性值。
(3)InputStream、OutputStream、Reader和Writer。InputStream和Reader是针对HttpServletRequest 而言的,可以从里面取数据;OutputStream和Writer 是针对HttpServletResponse而言的,可以往里面写数据。
(4)使用@PathVariable、@RequestParam、@CookieValue和@RequestHeader标记的参数。
(5)使用@ModelAttribute标记的参数。
(6)Java.util.Map、Spring封装的Model和ModelMap。这些都可以用来封装模型数据,用来给视图做展示。
(7)实体类。可以用来接收上传的参数。
(8)Spring封装的MultipartFile。用来接收上传文件的。
(9)Spring封装的Errors和BindingResult对象。这两个对象参数必须紧接在需要验证的实体对象参数之后,它里面包含了实体对象的验证结果。
支持的返回类型
(1)一个包含模型和视图的ModelAndView对象。
(2)一个模型对象,这主要包括Spring封装好的Model和ModelMap ,以及java.util.Map,当没有视图返回的时候视图名称将由RequestToViewNameTranslator来决定。
(3)一个View对象。这个时候如果在渲染视图的过程中模型的话就可以给处理器方法定义一个模型参数,然后在方法体里面往模型中添加值。
(4)一个String字符串。这往往代表的是一个视图名称。这个时候如果需要在渲染视图的过程中需要模型的话就可以给处理器方法一个模型参数,然后在方法体里面往模型中添加值就可以了。
(5)返回值是void。这种情况一般是我们直接把返回结果写到HttpServletResponse中了,如果没有写的话,那么Spring将会利用RequestToViewNameTranslator来返回一个对应的视图名称。如果视图中需要模型的话,处理方法与返回字符串的情况相同。
(6)如果处理器方法被注解@ResponseBody标记的话,那么处理器方法的任何返回类型都会通过HttpMessageConverters转换之后写到HttpServletResponse中,而不会像上面的那些情况一样当做视图或者模型来处理。
(7)除以上几种情况之外的其他任何返回类型都会被当做模型中的一个属性来处理,而返回的视图还是由RequestToViewNameTranslator来决定,添加到模型中的属性名称可以在该方法上用@ModelAttribute(“attributeName”)来定义,否则将使用返回类型的类名称的首字母小写形式来表示。使用@ModelAttribute标记的方法会在@RequestMapping 标记的方法执行之前执行。
47 @ModelAttribute和@SessionAttributes传递和保存数据
SpringMVC支持使用@ModelAttribute和@SessionAttributes在不同的模型和控制器之间共享数据。
@ModelAttribute:一种是标注在方法上,另一种是标注在Controller方法参数上。
当@ModelAttribute标记单独使用时,被标注的方法将在处理器方法执行之前执行,然后把返回的对象存放在模型属性中,传给标注在方法入参上的变量。
@SessionAttributes:用于标记需要在Session中使用到的数据,包括从Session中取数据和存数据。@SessionAttributes一般是标记在Controller类上的,可以通过名称、类型或者名称加类型的形式来指定哪些属性是需要存放在session中的。
当使用@SessionAttributes时,如没有@ModelAttribute标注的方法,则去session中寻找。当controller类中的方法的变量,能匹配到@SessionAttributes中的名称或类型时,在方法返回后会将变量存放在Session中。
48 Spring MVC 自定义数据类型转换
Spring 3.0以后,可以继承org.springframework.core.convert.converter接口,实现对应的转换器,然后,
1、通过XMLSchema注册到ConversionService。
2、通过ConfigurableWebBindingInitializer注册ConversionService。
3、注册ConfigurableWebBindingInitializer到RequestMappingHandlerAdapter。
更多推荐
所有评论(0)