上一篇SpringMVC之web.xml讓我們了解到配置一個web項目的時候,怎樣做基礎的DispatcherServlet相關配置。作為SpringMVC上手的第一步。而application-context.xml則讓我們了解到怎樣將數據庫信息載入到項目中,包括重要的作用庫連接信息、sqlSessionFactory、事務等關鍵因素。
①、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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" 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/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<bean class="com.honzh.common.config.EncryptPropertyPlaceholderConfigurer">
<property name="locations">
<value>file:C:/properties/ymeng.properties</value>
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- Connection Info -->
<property name="driverClassName" value="${driver}" />
<property name="url" value="${url}?useUnicode=true&characterEncoding=utf8&" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
<!-- Connection Pooling Info -->
<property name="maxActive" value="${maxActive}" />
<property name="maxIdle" value="${maxIdle}" />
<property name="defaultAutoCommit" value="false" />
<property name="timeBetweenEvictionRunsMillis" value="3600000"/>
<property name="minEvictableIdleTimeMillis" value="3600000"/>
<property name="testOnBorrow" value="true" />
<property name="validationQuery">
<value>select 1 from DUAL</value>
</property>
</bean>
<!-- 創建SqlSessionFactory,同一時候指定數據源 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- Mapper接口所在包名。Spring會自己主動查找其下的Mapper -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.honzh.biz.database.mapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
<!-- transaction manager, use JtaTransactionManager for global tx -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 可通過注解控制事務 -->
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="springContextHolder" class="com.honzh.common.spring.SpringContextHolder" />
</beans>
②、重點內容介紹
1、EncryptPropertyPlaceholderConfigurer
<bean class="com.honzh.common.config.EncryptPropertyPlaceholderConfigurer">
<property name="locations">
<value>file:C:/properties/ymeng.properties</value>
</property>
</bean>
使用了file前綴引導spring從c盤固定的路徑載入數據庫連接信息。
剛看到這個類的時候,你或許會有一種似曾相識的感覺。沒錯,她繼承了PropertyPlaceholderConfigurer類。僅僅只是我為她加了一層神奇的色彩(Encrypt嘛),其作用呢,就是為了不直接在項目執行環境中暴露數據庫連接信息,比方說數據庫用戶名、密碼、URL等,這樣就等於系統多了一層的安全級別。個人認為還是非常實用的,所以我之前總結了一篇SpringMVC使用隱式jdbc連接信息。
標題寫的是SpringMVC,相同適用於Spring,那么這里我就不再嘮叨了。
2、dataSource
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- Connection Info -->
<property name="driverClassName" value="${driver}" />
<property name="url" value="${url}?useUnicode=true&characterEncoding=utf8&" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
<!-- Connection Pooling Info -->
<property name="maxActive" value="${maxActive}" />
<property name="maxIdle" value="${maxIdle}" />
<property name="defaultAutoCommit" value="false" />
<property name="timeBetweenEvictionRunsMillis" value="3600000"/>
<property name="minEvictableIdleTimeMillis" value="3600000"/>
<property name="testOnBorrow" value="true" />
<property name="validationQuery">
<value>select 1 from DUAL</value>
</property>
</bean>
使用了dbcp的數據庫連接池。
DBCP(DataBase connection pool),數據庫連接池。
是 apache 上的一個 java 連接池項目,也是 tomcat 使用的連接池組件。
單獨使用dbcp須要2個包:commons-dbcp.jar,commons-pool.jar因為建立數據庫連接是一個非常耗時耗資源的行為。所以通過連接池預先同數據庫建立一些連接,放在內存中,應用程序須要建立數據庫連接時直接到連接池中申請一個即可。用完后再放回去。
destroy-method=”close”的作用就是當數據庫連接不使用的時候,就把該連接又一次放到數據池中,方便下次使用調用.非常關鍵的一個元素。
關於數據庫連接信息URL、username等就不解釋了。
關於數據庫連接池信息我到如今還沒有搞得非常明確,之前也調查了非常多次,不見效果。無奈。。。。
testOnBorrow、validationQuery:通過“select 1 from DUAL”查詢語句來驗證connection的有效性。網上還有非常多資源對這塊有專業的解釋,反正我是沒有看得太明確,之前也曾專門調查過這塊東西,如今也回憶不起來了,以后再碰到的時候再補充進來。
3、sqlSessionFactory
<!-- 創建SqlSessionFactory。同一時候指定數據源 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
sqlSessionFactory對於Spring以及mybatis來說就比較關鍵了,spring在建立sql連接使都會使用到這個。因為我的不專業性,所以關於更深入的解釋,我就不來了。反正對於我來說,這段配置就是為了和數據庫連接鏈接、創建事務管理。
創建sqlSessionFactory時,可能還須要為mybatis配置別名,那么此處改為例如以下格式:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="dataSource" ref="dataSource" />
</bean>
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>
<typeAlias alias='Deals' type='com.honzh.biz.database.entity.Deals' />
</typeAliases>
</configuration>
這樣在mapper的xml文件中就能夠使用Deals,而不再是com.honzh.biz.database.entity.Deals全名。
<resultMap type="Deals" id="BaseResultMap">
4、transactionManager、tx:annotation-driven
<!-- transaction manager, use JtaTransactionManager for global tx -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 可通過注解控制事務 -->
<tx:annotation-driven transaction-manager="transactionManager" />
transactionManager就是為了開啟事務。
通過tx:annotation-driven就能夠直接在方法或者類上加“@transactional”來開啟事務回滾。關於這段,我也必須誠實的說,我僅僅停留在會用的基礎上。
5、springContextHolder
<bean id="springContextHolder" class="com.honzh.common.spring.SpringContextHolder" />
通過spring的IOC機制(依賴注入),配置springcontext的管理器,該類的詳細內容見例如以下:
package com.honzh.common.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/** * <strong>SpringContextHolder</strong><br> * Spring Context Holder<br> * <strong>Create on : 2011-12-31<br></strong> * <p> * <strong>Copyright (C) Ecointel Software Co.,Ltd.<br></strong> * <p> * @author peng.shi peng.shi@ecointel.com.cn<br> * @version <strong>Ecointel v1.0.0</strong><br> */
public class SpringContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) {
SpringContextHolder.applicationContext = applicationContext;
}
/** * 得到Spring 上下文環境 * @return */
public static ApplicationContext getApplicationContext() {
checkApplicationContext();
return applicationContext;
}
/** * 通過Spring Bean name 得到Bean * @param name bean 上下文定義名稱 */
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
checkApplicationContext();
return (T) applicationContext.getBean(name);
}
/** * 通過類型得到Bean * @param clazz * @return */
@SuppressWarnings("unchecked")
public static <T> T getBean(Class<T> clazz) {
checkApplicationContext();
return (T) applicationContext.getBeansOfType(clazz);
}
private static void checkApplicationContext() {
if (applicationContext == null) {
throw new IllegalStateException("applicaitonContext未注入,請在application-context.xml中定義SpringContextHolder");
}
}
}
如此,我們就能夠輕松的通過SpringContextHolder.getBean方法獲取相應的bean類。就不再通過new關鍵字來創建一個類了。當然該類必須有注解標識,比方說@Service、@Component等。
6、MapperScannerConfigurer
<!-- Mapper接口所在包名,Spring會自己主動查找其下的Mapper -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.honzh.biz.database.mapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
該段配置的目的就是掃描mapper接口。也就是你sql語句的地方。
當系統啟動執行時,spring會載入你的mapper類,然后檢查相應的sql語句是否正確。比方字段名是否匹配等等。若不匹配系統自然會報錯。另外特別注意的是basePackage的value值一定要正確,我就曾深受其害。
ps:
這里請注意。當mybatis-3.1.1-SNAPSHOT.jar的版本號為3.0以上時,這種配置就可能會引發這種錯誤
org.apache.commons.dbcp.SQLNestedException: Cannot load JDBC driver class ‘${driver}’
有同仁解釋了一下這個道理,見例如以下
在spring里使用org.mybatis.spring.mapper.MapperScannerConfigurer 進行自己主動掃描的時候,設置了sqlSessionFactory 的話。可能會導致PropertyPlaceholderConfigurer失效,也就是用${jdbc.username}這樣之類的表達式,將無法獲取到properties文件中的內容。 |
那么此時的簡單解決的方法就是將xml改為例如以下格式:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.honzh.biz.database.mapper" />
</bean>
