Spring系统学习笔记二
来源:互联网 发布:武威广电网络客服电话 编辑:程序博客网 时间:2024/05/18 03:38
Spring系统学习笔记二
@(Experience)[java|Spring]
本笔记学习自Spring in Action 第三版
Spring 应用程序核心组件,将介绍如下方面:
- 数据库部分
- 事务管理
- Spring MVC
- Spring Web Flow
5 数据库
内容
- 定义Spring对数据访问的支持
- 配置数据库资源
- 使用Spring的JDBC模板
- Spring与Hibernate和JPA集成使用
5.1 Spring的数据访问哲学
DAO框架
5.1.1 了解Spring的数据访问异常体系
可能导致抛出SQLException的常见问题包括:
- 应用程序无法连接数据库;
- 要执行的查询有语法错误;
- 查询中所使用的表或列不存在;
- 试图插入或更新的数据违反了数据库的完整性约束。
Spring的平台无关持久化异常
Spring提供了多个访问异常,但是他并没有与特定的持久化方式相关联。
所有的异常都继承自DataAccessException,并且DataAccessException是非检查型异常,所以没有必要捕获Spring所抛出的数据访问异常。
5.1.2 数据访问模板化
Spring使用模板模式来设计Spring的数据访问。他将数据访问过程中固定的和可变的部分明确划分为两个不同的类:模板(template)和回调(callback)。
Spring提供了多个可选的模板:
5.1.3 使用DAO支持类
5.2 配置数据源
Spring提供了在AppliactionContext中配置数据源Bean的多种方式:
- 通过JDBC驱动程序定义的数据源;
- 通过JNDI查找的数据源;
- 连接池的数据源。
5.2.1 使用JNDI数据源
样例:
<jee:jndi-lookup id="dataSource" jndi-name="/jdbc/SpitterDS" resource-ref="true"/>
5.2.2 使用数据源连接池
Spring并没有提供数据源连接池实现,DBCP项目是一个非常不错的选择。
DBCP包含了多个提供连接池功能的数据源,最常用的是BasicDataSource。
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="org.hsqldb.jdbcDriver"/> <property name="url" value="jdbc:hsqldb:hsql://localhost/spitter/spitter"/> <property name="username" value="sa"/> <property name="password" value=""/> <property name="initialSize" value="5"/> <property name="maxActive" value="10"/></bean>
5.2.3 基于JDBC驱动的数据源
Spring提供了2种数据源对象:
DriverManagerDataSource :每个连接请求都会返回一个新建的连接。他没有进行池化管理。
SingleConnectionDataSource : 每个连接请求返回同一个连接。
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="org.hsqldb.jdbcDriver"/> <property name="url" value="jdbc:hsqldb:hsql://localhost/spitter/spitter"/> <property name="username" value="sa"/> <property name="password" value=""/></bean>
5.3 在Spring中使用JDBC
5.3.1 使用JDBC模板
Spring为JDBC提供了3个模板类供使用。
- JdbcTemplate:最基本的JDBC模板,这个模板支持最简单的JDBC数据库访问功能以及简单的索引参数查询。
- NamedParameterJdbcTemplate:可以将查询值以命名参数的形式绑定到SQL中,而不是使用简单的索引参数。
- SimpleJdbcTemplate:该模板利用自动装箱、泛型、可变参数列表来简化JDBC模板的使用。
使用SimpleJdbcTemplate访问数据
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate"> <constructor-arg ref="dataSource"/></bean>
将template装配入Dao:
public class JdbcSpitterDAO implements SpitterDAO{...private SimpleJdbcTemplate jdbcTemplate; public void setJdbcTemplate(SimpleJdbcTemplate jdbcTemplate){ this.jdbcTemplate = jdbcTemplate; }}
<bean id="spitterDao" class="com.habuma.spitter.persistence.SimpleJdbcTemplateSpitterDao"> <property name="jdbcTemplate" ref="jdbcTemplate"/></bean>
基于template的增加:
public voidaddSpitter(Spitterspitter){ jdbcTemplate.update(SQL_INSERT_SPITTER, spitter.getUsername(), spitter.getPassword(), spitter.getFullName(), spitter.getEmail(), spitter.isUpdateByEmail()); spitter.setId(queryForIdentity());}
命名参数方式不占篇幅解释。
5.4 在Spring中集成Hibernate
延迟加载、预先抓取、级联。这些超越JDBC能力的特性在ORM工具中得到服务。
(延迟加载,预先抓取也是iBATIS的重要概念)。
Spring对ORM提供了集成点,以及一些附加的服务:
- Spring声明式事务的集成支持;
- 透明的异常处理;
- 线程安全的、轻量级的模板类;
- DAO支持类;
- 资源管理。
5.4.1 Hibernate预览
HibernateTemplate的职责之一是管理Hibernate的Session。
5.4.2 声明Hibernate的Session工厂
获取Hibernate的Session接口的标准方式是借助于Hibernate的SessionFactory接口的实现类。
如果要使用XML来定义对象与数据之间的映射,那么需要在Spring中配置LocalSessionFactoryBean。
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="mappingResources"> <list> <value>Spitter.hbm.xml </value> </list> </property> <property name="hibernateProperties"> <props> <prop key="dialect">org.hibernate.dialect.HSQLDialect</prop> </props> </property></bean>
如果希望用注解的方式,那就需要使用AnnotationSessionFactoryBean来代替LocalSessionFactoryBean:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="packagesToScan" value="com.habuma.spitter.domain"/> <property name="hibernateProperties"> <props> <prop key="dialect">org.hibernate.dialect.HSQLDialect</prop> </props> </property></bean>
扫描packagesToScan指定的包中,含有JPA@Entity或@MappedSuperclass注解以及Hibernate的@Entity注解。
其他写法:
<property name="packagesToScan"> <list> <value>com.habuma.spitter.domain</value> </list></property><property name="annotatedClasses"> <list> <value>com.habuma.spitter.domain.Spitter</value> <value>com.habuma.spitter.domain.Spittle</value> </list></property>
5.4.3 构建不依赖于Spring的Hibernate代码
package com.habuma.spitter.persistence;import java.util.List;import org.hibernate.SessionFactory;import org.hibernate.classic.Session;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Repository;import com.habuma.spitter.domain.Spitter;import com.habuma.spitter.domain.Spittle;@Repositorypublic class HibernateSpitterDao implements SpitterDao{ private SessionFactory sessionFactory; @Autowired public HibernateSpitterDao(SessionFactory sessionFactory){ this.sessionFactory = sessionFactory; } private Session currentSession(){ return sessionFactory.getCurrentSession(); } public void addSpitter(Spitter spitter){ currentSession().save(spitter); } public Spitter getSpitterById(longid){ return(Spitter)currentSession().get(Spitter.class,id); } public void saveSpitter(Spitterspitter){ currentSession().update(spitter); } ...}
@Autowired注解将SessionFactory注入到sessionFactory中
@Repository注解一能被Spring的<context:component-scan>所扫描,二会在类上添加一个通知器,会捕获任何平台相关的异常并以Spring的非检查型数据访问异常重新抛出。
5.5 Spring与Java持久化API
Spring放弃了对EJB的支持,支持了JPA。
JPA诞生于EJB规范。
5.5.1 配置实体管理器工厂
基于JPA的应用程序使用EntityManagerFactory的实现类来获取EntityManager实例。JPA定义了两种类型的实体管理器:
- 应用程序管理类型
- 容器管理类型
这两种实体管理器工厂分别由对应的Spring工厂Bean创建的:
- LocationEntityManagerFactoryBean生成应用程序管理类型的Entity-ManagerFactory;
- LocalContainerEntityManagerFactoryBean生成容器管理类型的EntityManagerFactory。
使用应用程序管理类型的JPA
persistence.xml配置文件:
<persistencexmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> <persistence-unit name="spitterPU"> <class>com.habuma.spitter.domain.Spitter</class> <class>com.habuma.spitter.domain.Spittle</class> <properties> <property name="toplink.jdbc.driver" value="org.hsqldb.jdbcDriver"/> <property name="toplink.jdbc.url" value="jdbc:hsqldb:hsql://localhost/spitter/spitter"/> <propertyn ame="toplink.jdbc.user" value="sa" /> <propert yname="toplink.jdbc.password" value="" /> </properties> </persistence-unit></persistence>
Spring bean配置:
<bean id="emf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="spitterPU"/></bean>
使用容器管理类型的JPA
我们可以在容器中生成EntityManagerFactory,即可以将数据源信息配置在Spring应用的上下文,而不是persistence.xml中
<bean id="emf" class= "org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/></bean>
Spring提供了多个JPA厂商适配器:
- EclipseLinkJpaVendorAdapter
- HibernateJpaVendorAdapter
- OpenJpaVendorAdapter
- TopLinkJpaVendorAdapter
本例中,我们使用Hibernate作为JPA实现
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="database" value="HSQL"/> <property name="showSql" value="true"/> <property name="generateDdl" value="false"/> <property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect"/></bean>
从JNDI获取实体管理器工厂
<jee:jndi-lookup id="emf" jndi-name="persistence/spitterPU" />
5.5.2 编写基于JPA的DAO
一旦获取了EntityManagerFactory,就可以开始编写DAO了
package com.habuma.spitter.persistence;import java.util.List;import javax.persistence.EntityManager;import javax.persistence.PersistenceContext;import org.springframework.dao.DataAccessException;import org.springframework.stereotype.Repository;import org.springframework.transaction.annotation.Transactional;import com.habuma.spitter.domain.Spitter;import com.habuma.spitter.domain.Spittle;@Repository("spitterDao")@Transactionalpublic class JpaSpitterDao implements SpitterDao{ private static final String RECENT_SPITTLES="SELECTsFROMSpittles"; private static final String ALL_SPITTERS="SELECTsFROMSpitters"; private static final String SPITTER_FOR_USERNAME="SELECTsFROMSpittersWHEREs.username=:username"; private static final String SPITTLES_BY_USERNAME="SELECTsFROMSpittlesWHEREs.spitter.username=:username"; @PersistenceContext private EntityManager em; public void addSpitter(Spitter spitter){ em.persist(spitter); } public Spitter getSpitterById(long id){ returnem.find(Spitter.class,id); } public void saveSpitter(Spitter spitter){ em.merge(spitter); } ...}
6 事务管理
内容:
- 集成事务管理
- 编码方式管理事务
- 使用声明式事务
- 以注解的方式描述事务
在软件开发领域,全有或全无的操作被称为事务
6.1 理解事务
作为事务,这些过程将被视为一个操作,从而保证所有操作要么都成功要么全部回滚,就像这些操作从未发生过。
6.1.1 用4个词来表示事务
在传统的软件开发中,人们创建了一个术语来描述事务:A C I D。
原子性 Atomic,一致性 Consistent,隔离性 Isolated,持久性 Durable。
6.1.2 理解Spring对事务管理的支持
Spring提供了编码式和声明式事务管理的支持。
6.2 选择事务管理器
Spring并不直接管理事务,而是提供了多种事务管理器。每个事务管理器都会充当某一特定平台的事务实现的门面。
6.2.1 JDBC事务
DataSourceTransactionManager
<bean id="transactionManager" class="org.springframework.jdbc.➥datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/></bean>
6.2.2 Hibernate事务
<bean id="transactionManager" class="org.springframework.➥orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/></bean>
6.2.3 持久化API事务
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/></bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect"/>
6.4 声明式事务
Spring提供3种方式来声明事务式边界。以前,Spring只能使用Spring AOP和TransactionProxyFactoryBean的代理Bean来实现声明式事务。现在使用Spring的tx命名空间和@Transactional注解。
6.4.1 定义事务属性
在Spring中,声明式事务是通过事务属性(transaction attribute)来定义的。
传播行为
事务的第一个方面是传播行为(propagation behavior)。传播行为定义了客户端与被调用方法之间的事务边界。
隔离级别
隔离级别定义了一个事务可能受其他并发事务影响的程度。
只读
声明事务的第三个特性是否是只读事务。
事务超时
定义事务的执行时间
回滚规则
默认情况下,遇到运行期异常回滚,二遇到检查型异常不会回滚
6.4.2 在XML中定义事务
命名空间:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/ spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
tx配置事务:
<tx:advice id="txAdvice"> <tx:attributes> <tx:method name="add*" propagation="REQUIRED"/> <tx:method name="*" propagation="SUPPORTS" read-only="true"/> </tx:attributes></tx:advice>
6.4.3 定义注解驱动的事务
<tx:annotation-driven/>
指定特定的事务管理器
<tx:annotation-driven transaction-manager="txManager"/>
通过<tx:annotation-driven>元素高速Spring检查上下文中所有的Bean并查找使用@Transactional注解的Bean。
7 使用Spring MVC构建Web应用程序
内容:
- 映射请求到Spring控制器
- 透明地绑定表单参数
- 校验表单提交
- 上传文件
7.1 Spring MVC起步
7.1.1 跟踪Spring MVC请求
7.1.2 搭建Spring MVC
Spring MVC的核心是DispatcherServlet,这个组件充当了Spring MVC的前段控制器,与其他Servlet一样,DispatcherServlet必须在Web应用程序的web.xml中进行配置。
<servlet> <servlet-name>spitter</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup></servlet>
因为servlet的名字为spitter,DispatcherServlet将尝试从一个名为spitter-servlet.xml文件(在WEB-INF目录下)中加载应用上下文。
<servlet-mapping> <servlet-name>spitter</servlet-name> <url-pattern>/</url-pattern></servlet-mapping>
创建spitter-servlet.xml文件,用它来创建应用上下文
<?xml version="1.0"encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <mvc:resources mapping="/resources/**" location="/resources/"/></beans>
mvc:resources建立了一个服务于静态资源的处理器。根据以上配置,所有以/resources路径开头的请求都会自动由应用程序根目录下的/resources目录提供服务。所有图片,样式表,JavaScript以及其他静态资源都必须放在/resources。
7.2 编写基本的控制器
7.2.1配置注解驱动的Spring MVC
Spring自带了多个处理器映射实现供我们选择:
- BeanNameUrlHandlerMapping :根据控制器Bean的名字将控制器映射到URL。
- ControllerBeanNameHandlerMapping:与上类似,Bean的名字不需要遵守URL的约定
- ControllerClassNameHandlerMapping:使用控制器的类名作为URL基础,将控制器映射到URL
- DefaultAnnotationHandlerMapping:将请求映射给使用@RequestMapping注解的控制器和控制器方法
- SimpleUrlHandlerMapping:使用定义在Spring应用上下文的属性集合将控制器映射到URL
7.2.2 定义首页的控制器
HomeController是一个基本的Spring MVC控制器,用来处理首页的请求
package com.habuma.spitter.mvc;import javax.inject.Inject;import java.util.Map;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import com.habuma.spitter.service.SpitterService;@Controllerpublic class HomeController{ public static final int DEFAULT_SPITTLES_PER_PAGE=25; private SpitterService spitterService; @Inject public HomeController(SpitterService spitterService){ this.spitterService=spitterService; } @RequestMapping({"/","/home"}) public String showHomePage(Map<String,Object>model){ model.put("spittles",spitterService.getRecentSpittles(DEFAULT_SPITTLES_PER_PAGE)); return "home"; }}
测试控制器:
public class HomeControllerTest{ @Test public void shouldDisplayRecentSpittles(){ List<Spittle> expectedSpittles= asList(newSpittle(),newSpittle(),newSpittle()); SpitterService spitterService=mock(SpitterService.class); when(spitterService.getRecentSpittles(DEFAULT_SPITTLES_PER_PAGE)). thenReturn(expectedSpittles); HomeControllercontroller= new HomeController(spitterService); HashMap<String,Object> model =new HashMap<String,Object>(); String viewName=controller.showHomePage(model); assertEquals("home",viewName); assertSame(expectedSpittles,model.get("spittles")); verify(spitterService).getRecentSpittles(DEFAULT_SPITTLES_PER_PAGE);}
7.2.3 解析视图
Spring自带了多个视图解析器实现供选择。
解析内部视图
InternalResourceViewResolver是一个面向约定的元素。它将逻辑视图名称解析为View对象。
它通过逻辑视图名称添加前缀和后缀来确定Web应用程序中的模板的路径。
比如:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/"/> <property name="suffix" value=".jsp"/></bean>
如果home.jsp使用JSTL标签:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="prefix" value="/WEB-INF/views/"/> <property name="suffix" value=".jsp"/></bean>
解析Tiles视图
Apache Tiles是一个模板框架,它将页面分成片段并在运行时组装成完整的页面。
<bean class= "org.springframework.web.servlet.view.tiles2.TilesViewResolver"/>
<bean class= "org.springframework.web.servlet.view.tiles2.TilesConfigurer"> <property name="definitions"> <list> <value>/WEB-INF/views/**/views.xml</value> </list> </property></bean>
7.2.4 定义首页的视图
<%@ taglibprefix="c"uri="http://java.sun.com/jsp/jstl/core"%><%@ taglibprefix="s"uri="http://www.springframework.org/tags"%><%@ taglibprefix="t"uri="http://tiles.apache.org/tags-tiles"%><%@ taglibprefix="fmt"uri="http://java.sun.com/jsp/jstl/fmt"%><div><h2>A globalcommunityoffriendsandstrangersspittingouttheirinner-mostandpersonalthoughtsonthewebforeveryoneelsetosee.</h2><h3>Lookatwhatthesepeoplearespittingrightnow...</h3><ol class="spittle-list"><c:forEach var="spittle" items="${spittles}"> <s:url value="/spitters/{spitterName}" var="spitter_url"> <s:param name="spitterName" value="${spittle.spitter.username}"/> </s:url> <li> <span class="spittleListImage"> <img src="http://s3.amazonaws.com/spitterImages/${spittle.spitter.id}.jpg" width="48" border="0" align="middle" onError="this.src='<s:urlvalue="/resources/images"/>/spitter_avatar.png';"/> </span> <span class="spittleListText"> <a href="${spitter_url}"> <c:out value="${spittle.spitter.username}"/></a> - <c:out value="${spittle.text}"/><br/> <small><fmt:formatDate value="${spittle.when}" pattern="hh:mmaMMMd,yyyy"/></small> </span> </li></c:forEach></ol></div>
7.2.5 完成Spring应用上下文
Web.xml配置ContextLoaderListener
<listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class></listener>
必须制定ContextLoaderListener需要加载哪些配置文件,如果没有规定就会加载/WEB-INF/applicationContext.xml这个配置文件。
servlet配置:
<context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/spitter-security.xml classpath:service-context.xml classpath:persistence-context.xml classpath:dataSource-context.xml </param-value></context-param>
- Spring系统学习笔记二
- Spring学习笔记二
- Spring学习笔记二
- spring学习笔记二
- spring学习笔记二
- 学习Spring笔记二
- Spring学习笔记<二>
- Spring学习笔记二
- Spring学习笔记二
- spring学习笔记(二)
- spring JpetStore学习笔记(二)
- Spring学习笔记(二)
- spring学习笔记(二)
- Spring学习笔记(二)
- spring学习笔记(二)
- Spring Integration学习笔记二
- Spring security学习笔记二
- Spring学习笔记(二)
- 详解Linux下SSH远程文件传输命令scp
- Dialog
- iOS面试-名词解释
- qwt3d在qt5里面的编译问题
- Makefile文件简介
- Spring系统学习笔记二
- redhat6.5 配置使用centos的yum源
- android Shape使用(转)
- GCD和多线程
- 建造者模式
- activity 的四种启动方式
- 关于手机自动化测试的认知。
- App启动缓冲界面之SplashActivity
- 最简单易懂的Unity1.2 源码 (注入)