Spring4.5使用笔录
1、Spring启动需要的jar包

2、如果要使用Spring-MVC还需要jar包

3、如果要集成mybatis,需要以下jar包:

4、Spring各个jar包说明:
附:可以参考网址 http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/

5、单独启动Spring配置文件
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <display-name>SpringDemo</display-name> <!-- 监听spring上下文容器 --> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <!-- 加载spring的xml配置文件到 spring的上下文容器中 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:config/spring-context*.xml</param-value> </context-param> </web-app>
spring-context*.xml即是Spring的配置文件,*是通配符————Spring配置文件可以按用途分为多个
spring-context.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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd"> <!-- 导入自定义配置文件(交给Spring管理) --> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:config/jdbc.properties</value> </list> </property> </bean> <!-- 导入自定义配置文件(交给Spring管理) --> <context:property-placeholder location="classpath:config/jdbc.properties" /> </beans>
两种导入自定义配置文件的方式任选一种即可。

6、Spring集成Spring-MVC配置文件
在Spring基础上web.xml中增加
<!-- SpringMVC的请求都统一由DispatcherServlet处理 --> <servlet> <servlet-name>handler</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:config/springmvc-context.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <!-- SpringMVC拦截的请求类型 --> <servlet-mapping> <servlet-name>handler</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <!-- 过滤UTF-8以外的字符集 --> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
springmvc-context.xml
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 配置包扫描,配置之后SpringMVC和Spring都能注解了 --> <context:component-scan base-package="test.mvc.*" /> </beans:beans>
SpringMVC配置文件中设置了包扫描后,Spring的配置文件可以不用设置

7、Spring集成Mybatis
Spring配置文件增加数据源和会话工厂
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd"> <!-- 导入自定义配置文件(交给Spring管理) --> <context:property-placeholder location="classpath:config/jdbc.properties" /> <!-- 数据源 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <property name="initialSize" value="${pool.initialSize}" /> <property name="maxActive" value="${pool.maxActive}" /> <property name="maxIdle" value="${pool.maxIdle}" /> <property name="minIdle" value="${pool.minIdle}" /> </bean> <!-- 使用mybatis方式持久化数据 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="configLocation" value="classpath:config/mybatis-config.xml"/> <!-- 当mybatis的xml文件和mapper接口不在相同包下时,需要用mapperLocations属性指定xml文件的路径。 *是个通配符,代表所有的文件 --> <property name="mapperLocations" value="classpath:com/czgps/ssm/mybatis/*.xml" /> </bean> <!-- mybatis批量扫描,扫描出mapper接口自动创建代理对象并在Spring容器中注册 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!-- mapper.java和mapper.xml文件名称保持一致且在同一目录中,扫描出的mapper对应的bean的id是类型名(首字母必须小写) --> <property name="basePackage" value="com.czgps.ssm.mapper" /> <!-- Spring整合Mybatis是会出现加载jdbc参数异常(因为配置文件加载问题) --> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /> </bean> </beans>
mybatis配置文件mybatis-config.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <typeAliases> <!-- 为com.czgps.ssm.po包下的类取别名,别名就是类型名(首字母大小写均可) --> <package name="com.czgps.ssm.po" /> </typeAliases> </configuration>

注意:mybatis延迟加载特性依赖于cglib,而cglib依赖asm,所以要导入cglib和asm两个jar包,jar包下载:https://github.com/mybatis/mybatis-3/releases

使用log4j在控制台输出日志,方便debug导入log4j的jar包和commons-logging,slf4j是日志抽象层

如果mybatis要支持分页查询,可以使用分页插件,jar包下载:http://git.oschina.net/free/Mybatis_PageHelper/blob/master/wikis/HowToUse.markdown

同时在mybatis-config.xml中增加插件拦截
<plugins> <!-- com.github.pagehelper为PageHelper类所在包名 --> <plugin interceptor="com.github.pagehelper.PageHelper"> <!-- 该参数默认为false --> <!-- 设置为true时,会将RowBounds第一个参数offset当成pageNum页码使用 --> <!-- 和startPage中的pageNum效果一样--> <property name="offsetAsPageNum" value="true"/> <!-- 3.3.0版本可用 - 分页参数合理化,默认false禁用 --> <!-- 启用合理化时,如果pageNum<1会查询第一页,如果pageNum>pages会查询最后一页 --> <!-- 禁用合理化时,如果pageNum<1或pageNum>pages会返回空数据 --> <property name="reasonable" value="true"/> <!-- 支持通过Mapper接口参数来传递分页参数 --> <property name="supportMethodsArguments" value="false"/> <!-- always总是返回PageInfo类型,check检查返回类型是否为PageInfo,none返回Page --> <property name="returnPageInfo" value="none"/> </plugin> </plugins>
如果要支持事务,在spring-context.xml中增加事务配置;现在一般使用声明式注解@Transactional ,配置如下:
<!-- 事务管理 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 使用annotation定义事务 --> <tx:annotation-driven transaction-manager="transactionManager" />
如果使用配置文件配置方式使用事务(不推荐),配置如下;主要是先定义一个增强,然后为这个增强配置切点;这种的缺点是为方法配置事务策略时不够灵活需要更改配置文件,注解就没有这种限制。
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 增强 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!-- 事务传播行为propagation默认REQUIRED / 事务隔离级别isolation默认DEFAULT --> <tx:attributes> <tx:method name="*" rollback-for="java.lang.Exception" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1"/> </tx:attributes> </tx:advice> <!-- aop切点 --> <aop:config> <aop:advisor advice-ref="txAdvice" pointcut="execution(* czgps.app.service.*.*(..))" /> </aop:config>
运行期(unchecked)异常RuntimeException默认回滚,编译时(checked)异常默认不会回滚
unchecked异常如果不想回滚就用noRollbackFor来指定,对子类有效
checked异常如果需要回滚就用rollbackFor来指定,对子类有效
详细参考如下:
注意的几点: 1 @Transactional 只能被应用到public方法上, 对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能. 2用 spring 事务管理器,由spring来负责数据库的打开,提交,回滚.默认遇到运行期例外(throw new RuntimeException("注释");)会回滚,即遇到不受检查(unchecked)的例外时回滚;而遇到需要捕获的例外(throw new Exception("注释");)不会回滚,即遇到受检查的例外(就是非运行时抛出的异常,编译器会检查到的异常叫受检查例外或说受检查异常)时,需我们指定方式来让事务回滚 要想所有异常都回滚,要加上 @Transactional( rollbackFor={Exception.class,其它异常}) .如果让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class) 如下: @Transactional(rollbackFor=Exception.class) //指定回滚,遇到异常Exception时回滚 public void methodName() { throw new Exception("注释"); } @Transactional(noRollbackFor=Exception.class)//指定不回滚,遇到运行期例外(throw new RuntimeException("注释");)会回滚 public ItimDaoImpl getItemDaoImpl() { throw new RuntimeException("注释"); } 3、@Transactional 注解应该只被应用到 public 可见度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错, 但是这个被注解的方法将不会展示已配置的事务设置。 4、@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。然而,请注意仅仅 @Transactional 注解的出现不足于开启事务行为,它仅仅 是一种元数据,能够被可以识别 @Transactional 注解和上述的配置适当的具有事务行为的beans所使用。上面的例子中,其实正是 <tx:annotation-driven/>元素的出现 开启 了事务行为。 5、Spring团队的建议是你在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。你当然可以在接口上使用 @Transactional 注解,但是这将只能当你设置了基于接口的代理时它才生效。因为注解是 不能继承 的,这就意味着如果你正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装(将被确认为严重的)。因 此,请接受Spring团队的建议并且在具体的类上使用 @Transactional 注解。
8、以上使用到的jdbc.properties内容
###数据库连接池设置######## pool.initialSize=5 pool.maxActive=10 pool.maxIdle=5 pool.minIdle=1 pool.maxWait=1000 pool.poolPreparedStatements=true pool.defaultAutoCommit=false ###########数据库连接设置########## #驱动类 jdbc.driver=com.mysql.jdbc.Driver #连接地址 jdbc.url=jdbc:mysql://192.168.1.100:3306/Study?useUnicode=true&characterEncoding=utf8 #用户名 jdbc.username=root #密码 jdbc.password=root
9、使用slf4j日志替代log4j(桥接)
jcl-over-slf4j-1.7.22.jar用于替代替代common-logging.jar(这就是桥接的作用,相当于冒名顶替,有一个包名结构几乎一样的jar包替换掉common-logging.jar)
如下是几个依赖包:

<dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>1.7.22</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.22</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.1.8</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.1.8</version> </dependency>
10、Spring决策代理类型(Cglib和JDK)
Spring优先采用JDK动态代理(有接口的前提),没有接口只能用cglib
ProxyProcessorSupport类的evaluateProxyInterfaces方法与DefaultAopProxyFactory类中createAopProxy方法一起决策Spring的代理
<aop:aspectj-autoproxy proxy-target-class="true"/>表示强制使用cglib,如果不要proxy-target-class则Spring自己会在JDK代理与cglib间切换
<aop:aspectj-autoproxy/>在Spring和SpringMVC的配置文件中分别配置
@Service这样的注解要放在实现类上,不是放在接口上(代理的是目标类,不是它实现的接口)
ProxyProcessorSupport类的evaluateProxyInterfaces方法可以看出,如果目标类没有实现接口直接就是Cglib代理
protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) { // 获取接口的所有父接口;递归查找包括直接和间接实现的接口 Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader()); boolean hasReasonableProxyInterface = false; for (Class<?> ifc : targetInterfaces) { if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) && ifc.getMethods().length > 0) { hasReasonableProxyInterface = true; break; } } if (hasReasonableProxyInterface) { // Must allow for introductions; can't just set interfaces to the target's interfaces only. for (Class<?> ifc : targetInterfaces) { proxyFactory.addInterface(ifc); } } else { // 没有实现任何接口,直接就走Cglib proxyFactory.setProxyTargetClass(true); } }
DefaultAopProxyFactory类中createAopProxy方法,最终决定生成的AopProxy是Cglib还是JDK的
@Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { // 1、config.isOptimize()基本类型 // 2、config.isProxyTargetClass()表示已经判断出要使用Cglib // 3、用户没有提供任何实现的接口 if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } // 如果目标类是接口或者Proxy类,也默认走JDK代理 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } }
11、SpringMVC返回值问题
1、 返回ModleAndView,表示直接返回一个视图
2、 自定义模型(json),一般做为数据接口,需要@ResponseBody注解——表示将序列化出的json写入到响应流的响应体中
3、 返回值类型为String类型的逻辑视图名称(带有forward或redirect前缀的视图名称后必须是完整的资源路径)
往请求对象中添加属性键值对的三种方式
1、HttpServletRequest的setAttribute
2、Model的addAttribute
3、ModelAndView的addObject
带有forward或redirect前缀的逻辑视图名
1、forward只能调转当前web应用内的资源,其实框架内部就是调用的RequestDispatcher.forward
2、redirect可以调转其他web应用的资源(使用http://url格式的绝对路径),框架内部调用response.sendRedirect
SpringMVC框架返回值有专门的处理器,其对应关系是:
ModleAndView——ModelAndViewMethodReturnValueHandler
String(逻辑视图名)——ViewNameMethodReturnValueHandler
带@ResponseBody注解的自定义模型(json)——RequestResponseBodyMethodProcessor
每个处理器都实现了HandlerMethodReturnValueHandler并重写了handleReturnValue方法,该方法就是用于处理返回值的。
查看ViewNameMethodReturnValueHandler的handleReturnValue方法可以看到,直接返回String时,返回值直接作为了视图名称

在对逻辑视图名url进行解析时,会处理forward和redirect前缀;只有不带forward或者redirect前缀的视图才会拼接视图解析器配置的前后缀,
查看UrlBasedViewResolver类的createView方法如下

结合上图可以看到super.createView最终会调用UrlBasedViewResolver类的buildView来构建视图,buildView中读取了视图解析器的前后缀

附带测试项目:https://files.cnblogs.com/files/xy-nb/springmvc-total.zip
12、占位

浙公网安备 33010602011771号