1. 程式人生 > >Java進階學習第二十三天(Spring框架:代理模式、AOP程式設計、jdbc支援)

Java進階學習第二十三天(Spring框架:代理模式、AOP程式設計、jdbc支援)

一、共性問題

1、伺服器啟動報錯,什麼原因? ① jar包缺少或者jar包衝突 ◆ 先檢查專案中是否缺少jar包引用 ◆ 伺服器:檢查jar包有沒有釋出到伺服器下;使用者庫jar包,需要手動釋出到tomcat(每次新建專案) ◆ 重新發布專案 ② 配置檔案錯誤(web.xml / struts.xml /bean.xml /hibernate.xml / *.hbm.xml)會有明確的提示 ③ 端口占用 ④ webapps專案過多 當前專案沒有問題,有可能是其他專案出錯,這樣啟動也會報錯!但這個錯誤不是當前錯誤報的,所以不影響當前專案執行。 注意:一般開發中,一個tomcat下只有一個專案。

2、一般啟動報錯: ClassNotFoundException異常 少jar包。

3、訪問404,什麼原因? ① 客戶端路徑寫錯,或跳轉錯誤。 ② 啟動報錯:Web專案中,啟動後一定要看下,是否報錯。

4、點選某個功能報錯。 後臺程式碼錯誤:找到頁面,點選哪個操作,提交到哪個地址,在後臺在提交地址的第一行打斷點

目標: 1) 代理模式 靜態代理 動態代理 Cglib代理 2)手動實現AOP程式設計 【代理模式】 3)AOP程式設計 * 註解方式實現 * XMl配置方式實現 4) Spring DAO Spring對jdbc操作的支援

二、代理模式

1、概述 代理(Proxy)是一種設計模式, 提供了對目標物件另外的訪問方式;即通過代理訪問目標物件。 這樣好處: 可以在目標物件實現的基礎上,增加額外的功能操作(擴充套件目標物件的功能)

代理模式的關鍵點: 代理物件與目標物件。

2、靜態代理 ① 代理物件,要實現與目標物件一樣的介面; ② 舉例:儲存使用者 UserDaoImpl,直接儲存 UserDaoProxy,給儲存方法新增事務處理

/**
 *  代理物件(靜態代理)
 * 	代理物件,要實現與目標物件一樣的介面
 */
public class UserDaoProxy implements UserDao{
	// 接收儲存目標物件
	private UserDao target;
	public UserDaoProxy(UserDao target) {
		this.target = target;
	}
	
	@Override
	public void save() {
		System.out.println("開始事務...");
		target.save(); 			// 執行目標物件的方法
		System.out.println("提交事務...");
	}	
}

③ 總結 ◆ 可以做到在不修改目標物件的功能前提下,對目標物件功能擴充套件。 ◆ 缺點:因為代理物件需要與目標物件實現一樣的介面,所以會有很多代理類,類太多。一旦介面增加方法,目標物件與代理物件都要維護。 ◆ 解決:可以使用動態代理。

3、動態代理 ① 代理物件不需要實現介面 ② 代理物件的生成是利用JDKAPI, 動態的在記憶體中構建代理物件(需要我們指定建立代理物件/目標物件的實現的介面的型別) ③ 動態代理,也叫作JDK代理,或者介面代理 ④ JDK中生成代理物件的API

static Object newProxyInstance(
ClassLoader loader,       // 指定當前目標物件使用類載入器
Class<?>[] interfaces,    // 目標物件實現的介面的型別
InvocationHandler h       // 事件處理器
) ; 

⑤ 總結:代理物件不需要實現介面,但是目標物件一定要實現介面,否則不能用動態代理!

// 介面
public interface UserDao {
	void save();	
}
/**
 * 目標物件
 */
public class UserDaoImpl implements UserDao{
	@Override
	public void save() {
		System.out.println("-----已經儲存資料!!!------");
	}
}
/**
 * 給所有的dao建立代理物件【動態代理】
 * 代理物件,不需要實現介面
 */
public class ProxyFactory {
	// 維護一個目標物件
	private Object target;
	public ProxyFactory(Object target){
		this.target = target;
	}
	
	// 給目標物件生成代理物件  
	public Object getProxyInstance() {
		return Proxy.newProxyInstance(
				target.getClass().getClassLoader(), 
				target.getClass().getInterfaces(),
				new InvocationHandler() {
					@Override
					public Object invoke(Object proxy, Method method, Object[] args)
							throws Throwable {
						System.out.println("開啟事務");
						// 執行目標物件方法
						Object returnValue = method.invoke(target, args);
						System.out.println("提交事務");
						return returnValue;
					}
				});
	}
}
public class App {
	public static void main(String[] args) {
		// 目標物件
		UserDao target = new UserDaoImpl();
		System.out.println(target.getClass());	// 原始的型別 class cn.itcast.b_dynamic.UserDaoImpl	
		// 給目標物件,建立代理物件
		UserDao proxy = (UserDao) new ProxyFactory(target).getProxyInstance();
		System.out.println(proxy.getClass());// class $Proxy0   記憶體中動態生成的代理物件
		// 執行方法   【代理物件】
		proxy.save();
	}
}

⑥ 思考:有一個目標物件,想要功能擴充套件,但目標物件沒有實現介面,怎樣功能擴充套件? 以子類的方式實現(cglib代理)

4、Cglib代理 ① Cglib代理也叫做子類代理,它是在記憶體中構建一個子類物件從而實現對目標物件功能的擴充套件。 ◆ JDK的動態代理有一個限制,就是使用動態代理的物件必須實現一個或多個介面。如果想代理沒有實現介面的類,就可以使用CGLIB實現。 ◆ CGLIB是一個強大的高效能的程式碼生成包,它可以在執行期擴充套件Java類與實現Java介面。它廣泛的被許多AOP的框架使用,例如Spring AOP和dynaop,為他們提供方法的interception(攔截)。 ◆ CGLIB包的底層是通過使用一個小而快的位元組碼處理框架ASM,來轉換位元組碼並生成新的類。不鼓勵直接使用ASM,因為它要求你必須對JVM內部結構包括class檔案的格式和指令集都很熟悉。 ② Cglib子類代理: ◆ 需要引入cglib – jar檔案, 但是spring的核心包中已經包括了cglib功能,所以直接引入spring-core-3.2.5.jar即可。 ◆ 引入功能包後,就可以在記憶體中動態構建子類 ◆ 代理的類不能為final, 否則報錯。 ◆ 目標物件的方法如果為final/static, 那麼就不會被攔截,即不會執行目標物件額外的業務方法。

/**
 * 目標物件
 */
public class UserDao {
	public void save() {
		System.out.println("-----已經儲存資料!!!------");
	}
}
/**
 * Cglib子類代理工廠
 * (對UserDao 在記憶體中動態構建一個子類物件)
 */
public class ProxyFactory implements MethodInterceptor{
	// 維護目標物件
	private Object target;
	public ProxyFactory(Object target){
		this.target = target;
	}
	
	// 給目標物件建立代理物件
	public Object getProxyInstance(){
		//1. 工具類
		Enhancer en = new Enhancer();
		//2. 設定父類
		en.setSuperclass(target.getClass());
		//3. 設定回撥函式
		en.setCallback(this);
		//4. 建立子類(代理物件)
		return en.create();
	}

	@Override
	public Object intercept(Object obj, Method method, Object[] args,
			MethodProxy proxy) throws Throwable {
		System.out.println("開始事務.....");
		// 執行目標物件的方法
		Object returnValue = method.invoke(target, args);
		System.out.println("提交事務.....");
		return returnValue;
	}
}
public class App {
	public static void main(String[] args) {
		// 目標物件
		UserDao target = new UserDao();	
		System.out.println(target.getClass());// class cn.itcast.c_cglib.UserDao
		// 代理物件
		UserDao proxy = (UserDao) new ProxyFactory(target).getProxyInstance();
		System.out.println(proxy.getClass());	// UserDao子類:class cn.itcast.c_cglib.UserDao$$EnhancerByCGLIB$$25d4aeab
		// 執行代理物件的方法
		proxy.save();
	}
}

③ 在Spring的AOP程式設計中, 如果加入容器的目標物件有實現介面,用JDK代理; 如果目標物件沒有實現介面,用Cglib代理;

三、AOP程式設計

1、AOP:面向切面的程式設計:就是指對很多功能都有的重複的程式碼抽取,再在執行的時候往業務方法上動態植入“切面類程式碼”。 功能:可以實現“業務程式碼”與“關注點程式碼”分離 關注點:重複程式碼 切面:關注點形成的類,就叫切面(類) 切入點:執行目標物件方法,動態植入切面程式碼 可以通過切入點表示式,指定攔截哪些類的哪些方法, 給指定的類在執行的時候植入切面類程式碼。

// 儲存一個使用者
public void add(User user) { 
		Session session = null; 
		Transaction trans = null; 
		try { 
			session = HibernateSessionFactoryUtils.getSession();   // 【關注點程式碼】
			trans = session.beginTransaction();    // 【關注點程式碼】 
			session.save(user);     // 核心業務程式碼	 
			trans.commit();     //…【關注點程式碼】
		} catch (Exception e) {     
			e.printStackTrace(); 
			if(trans != null){ 
				trans.rollback();   //..【關注點程式碼】
			} 
		} finally{ 
			HibernateSessionFactoryUtils.closeSession(session);   ////..【關注點程式碼】
		} 
   } 

① 分析總結 ◆ 關注點程式碼,就是指重複執行的程式碼。 ◆ 業務程式碼與關注點程式碼分離的好處? ◇ 關注點程式碼寫一次即可; ◇ 開發者只需要關注核心業務; ◇ 執行時期,執行核心業務程式碼時候動態植入關注點程式碼; 【代理】 ② 如何分離? 過程式/物件式/代理模式分離

2、手動實現AOP程式設計

<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"
    xsi:schemaLocation="
        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">
	
	<!-- 開啟註解掃描 -->
	<context:component-scan base-package="cn.itcast.d_myaop"></context:component-scan>
	
	<!-- 呼叫工廠方法,返回UserDao代理後的物件 -->
	<bean id="userDaoImpl_proxy" class="cn.itcast.d_myaop.ProxyFactory" factory-method="getProxyInstance">
		<constructor-arg index="0" ref="userDaoImpl"></constructor-arg>
		<constructor-arg index="1" ref="aop"></constructor-arg>
	</bean>
</beans>
/**
 * 代理工廠
 */
public class ProxyFactory {
	// 目標物件
	private static Object target;
	private static Aop aop;
	// 生成代理物件的方法
	public static Object getProxyInstance(Object target_,Aop aop_){
		target = target_;
		aop = aop_;
		return Proxy.newProxyInstance(
				target.getClass().getClassLoader(), 
				target.getClass().getInterfaces(), 
				new InvocationHandler() {	
					@Override
					public Object invoke(Object proxy, Method method, Object[] args)
							throws Throwable {
						aop.begin();// 執行重複程式碼
						// 執行目標物件的方法
						Object returnValue = method.invoke(target, args);
						aop.commite(); // 執行重複程式碼
						return returnValue;
					}
				});
	}
}
// 介面
public interface UserDao {
	void save();
}
/**
 * 目標物件
 */
@Component   // 加入容器
public class UserDaoImpl implements UserDao{
	@Override
	public void save() {
		System.out.println("-----核心業務:儲存!!!------");
	}
}
public class App {
	ApplicationContext ac = 
		new ClassPathXmlApplicationContext("cn/itcast/d_myaop/bean.xml");
	@Test
	public void testApp() {
		UserDao userDaoImpl = (UserDao) ac.getBean("userDaoImpl_proxy");
		System.out.println(userDaoImpl.getClass());
		userDaoImpl.save(); 
	}
}

3、註解方式實現AOP程式設計 步驟: ① 先引入aop相關jar檔案 (aspectj組織:整合aop優秀元件)

spring-aop-3.2.5.RELEASE.jar   【spring3.2原始碼】
aopalliance.jar				   【spring2.5原始碼/lib/aopalliance】
aspectjweaver.jar			   【spring2.5原始碼/lib/aspectj】或【aspectj-1.8.2\lib】
aspectjrt.jar				   【spring2.5原始碼/lib/aspectj】或【aspectj-1.8.2\lib】

注意: 用到spring2.5版本的jar檔案,如果用jdk1.7可能會有問題。需要升級aspectj元件,即使用aspectj-1.8.2版本中提供jar檔案提供。 ② bean.xml中引入aop名稱空間

xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop.xsd"

③ 開啟aop註解

<!-- 開啟aop註解方式 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

④ 使用註解

@Aspect							    指定一個類為切面類		
@Pointcut("execution(* cn.itcast.e_aop_anno.*.*(..))")  指定切入點表示式

@Before("pointCut_()")				前置通知:目標方法之前執行
@After("pointCut_()")				後置通知:目標方法之後執行(始終執行)
@AfterReturning("pointCut_()")		返回後通知: 執行方法結束前執行(異常不執行)
@AfterThrowing("pointCut_()")	    異常通知:出現異常時候執行
@Around("pointCut_()")				環繞通知:環繞目標方法執行

具體實現:

<?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:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="
        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
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
	
	<!-- 開啟註解掃描 -->
	<context:component-scan base-package="cn.itcast.e_aop_anno"></context:component-scan>
	
	<!-- 開啟aop註解方式 -->
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>   
@Component
@Aspect  // 指定當前類為切面類
public class Aop {
	// 指定切入點表單式: 攔截哪些方法; 即為哪些類生成代理物件
	@Pointcut("execution(* cn.itcast.e_aop_anno.*.*(..))")
	public void pointCut_(){
	}
	
	// 前置通知 : 在執行目標方法之前執行
	@Before("pointCut_()")
	public void begin(){
		System.out.println("開始事務/異常");
	}
	
	// 後置/最終通知:在執行目標方法之後執行  【無論是否出現異常最終都會執行】
	@After("pointCut_()")
	public void after(){
		System.out.println("提交事務/關閉");
	}
	
	// 返回後通知: 在呼叫目標方法結束後執行 【出現異常不執行】
	@AfterReturning("pointCut_()")
	public void afterReturning() {
		System.out.println("afterReturning()");
	}
	
	// 異常通知: 當目標方法執行異常時候執行此關注點程式碼
	@AfterThrowing("pointCut_()")
	public void afterThrowing(){
		System.out.println("afterThrowing()");
	}
	
	// 環繞通知:環繞目標方式執行
	@Around("pointCut_()")
	public void around(ProceedingJoinPoint pjp) throws Throwable{
		System.out.println("環繞前....");
		pjp.proceed();  // 執行目標方法
		System.out.println("環繞後....");
	}
}
// 介面
public interface UserDao {
	void save();
}
/**
 * 目標物件
 */
@Component   // 加入容器
public class UserDaoImpl implements UserDao{
	@Override
	public void save() {
		System.out.println("-----核心業務:儲存!!!------"); 
	}
}
/**
 * 目標物件
 */
@Component   // 加入容器
@Scope("prototype")
public class OrderDao{
	public void save() {
		System.out.println("-----核心業務:儲存!!!------");
	}
}
public class App {
	ApplicationContext ac = 
		new ClassPathXmlApplicationContext("cn/itcast/e_aop_anno/bean.xml");

	// 目標物件有實現介面,spring會自動選擇“JDK代理”
	@Test
	public void testApp() {
		UserDao userDaoImpl = (UserDao) ac.getBean("userDaoImpl");
		System.out.println(userDaoImpl.getClass());
		userDaoImpl.save();
	}
	
	// 目標物件沒有實現介面, spring會用“cglib代理”
	@Test
	public void testCglib() {
		OrderDao orderDao = (OrderDao) ac.getBean("orderDao");
		System.out.println(orderDao.getClass());
		orderDao.save();
	}
}

4、XML方式實現AOP程式設計 步驟: ① 引入jar檔案 【aop 相關jar, 4個】 ② 引入aop名稱空間 ③ aop 配置 ◆ 配置切面類 (重複執行程式碼形成的類) ◆ aop配置:攔截哪些方法 / 攔截到方法後應用通知程式碼

<?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:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="
        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
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
	
	<!-- dao 例項 -->
	<bean id="userDao" class="cn.itcast.f_aop_xml.UserDao"></bean>
	<bean id="orderDao" class="cn.itcast.f_aop_xml.OrderDao"></bean>
	
	<!-- 切面類 -->
	<bean id="aop" class="cn.itcast.f_aop_xml.Aop"></bean>
	
	<!-- Aop配置 -->
	<aop:config>
		<!-- 定義一個切入點表示式: 攔截哪些方法 -->
		<aop:pointcut expression="execution(* cn.itcast.f_aop_xml.*.*(..))" id="pt"/>
		<!-- 切面 -->
		<aop:aspect ref="aop">
			<!-- 環繞通知 -->
			<aop:around method="around" pointcut-ref="pt"/>
			<!-- 前置通知: 在目標方法呼叫前執行 -->
			<aop:before method="begin" pointcut-ref="pt"/>
			<!-- 後置通知: -->
			<aop:after method="after" pointcut-ref="pt"/>
			<!-- 返回後通知 -->
			<aop:after-returning method="afterReturning" pointcut-ref="pt"/>
			<!-- 異常通知 -->
			<aop:after-throwing method="afterThrowing" pointcut-ref="pt"/>
		</aop:aspect>
	</aop:config>
</beans>  

5、切入點表示式:可以對指定的“方法”進行攔截; 從而給指定的方法所在的類生層代理物件 語法: execution(訪問修飾符? 返回值 宣告的型別? 方法名(方法引數) throws-pattern?) ?代表0個或者1個

<?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:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="
        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
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
	
	<!-- dao 例項 -->
	<bean id="userDao" class="cn.itcast.g_pointcut.UserDao"></bean>
	<bean id="orderDao" class="cn.itcast.g_pointcut.OrderDao"></bean>
	
	<!-- 切面類 -->
	<bean id="aop" class="cn.itcast.g_pointcut.Aop"></bean>
	
	<!-- Aop配置 -->
	<aop:config>
		
		<!-- 定義一個切入點表示式: 攔截哪些方法 -->
		<!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.*.*(..))" id="pt"/>-->
		
		<!-- 【攔截所有public方法】 -->
		<!--<aop:pointcut expression="execution(public * *(..))" id="pt"/>-->
		
		<!-- 【攔截所有save開頭的方法 】 -->
		<!--<aop:pointcut expression="execution(* save*(..))" id="pt"/>-->
		
		<!-- 【攔截指定類的指定方法, 攔截時候一定要定位到方法】 -->
		<!--<aop:pointcut expression="execution(public * cn.itcast.g_pointcut.OrderDao.save(..))" id="pt"/>-->
		
		<!-- 【攔截指定類的所有方法】 -->
		<!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.*(..))" id="pt"/>-->
		
		<!-- 【攔截指定包,以及其自包下所有類的所有方法】 -->
		<!--<aop:pointcut expression="execution(* cn..*.*(..))" id="pt"/>-->
		
		<!-- 【多個表示式】 -->
		<!-- 下面2個或關係的,沒有意義 -->
		<!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.save()) || execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->
		<!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.save()) or execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->
		<!-- 下面2個且關係的,沒有意義 -->
		<!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.save()) &amp;&amp; execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->
		<!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.save()) and execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->
		
		<!-- 【取非值】 -->
		<!--<aop:pointcut expression="!execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->
		<aop:pointcut expression=" not execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>
		
		<!-- 切面 -->
		<aop:aspect ref="aop">
			<!-- 環繞通知 -->
			<aop:around method="around" pointcut-ref="pt"/>
		</aop:aspect>
	</aop:config>
</beans>    

四、Spring對jdbc支援

1、具體體現: ① Spring對C3P0連線池支援很完善 ② Spring對jdbc提供了JdbcTemplate(模板工具類,類似DbUtils元件),來簡化jdbc的操作

2、使用步驟: ① 引入jar檔案

spring-jdbc-3.2.5.RELEASE.jar         jdbc支援包
spring-tx-3.2.5.RELEASE.jar           事務包

② 優化

<?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:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="
        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
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
	
	<!-- 1. 資料來源物件: C3P0連線池 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql:///hib_demo"></property>
		<property name="user" value="root"></property>
		<property name="password" value="root"></property>
		<property name="initialPoolSize" value="3"></property>
		<property name="maxPoolSize" value="10"></property>
		<property name="maxStatements" value="100"></property>
		<property name="acquireIncrement" value="2"></property>
	</bean>
	
	<!-- 2. 建立JdbcTemplate物件 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- dao 例項 -->
	<bean id="userDao" class="cn.itcast.h_jdbc.UserDao">
		<property name="jdbcTemplate" ref="jdbcTemplate"></property>
	</bean>
</beans>   
public class UserDao {

	/*
	 *  儲存方法
	 *  需求優化的地方:
	 *  	1. 連線管理
	 *  	2. jdbc操作重複程式碼封裝
	 */
	// IOC容器注入
	private JdbcTemplate jdbcTemplate;
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}
	
	public void save() {
		String sql = "insert into t_dept(deptName) values('test');";
		jdbcTemplate.update(sql);
	}
	
	public Dept findById(int id) {
		String sql = "select * from t_dept where deptId=?";
		List<Dept> list = jdbcTemplate.query(sql,new MyResult(), id);
		return (list!=null && list.size()>0) ? list.get(0) : null;
	}
	
	public List<Dept> getAll() {
		String sql = "select * from t_dept";
		List<Dept> list = jdbcTemplate.query(sql, new MyResult());
		return list;
	}
	
	class MyResult implements RowMapper<Dept>{
		// 如何封裝一行記錄
		@Override
		public Dept mapRow(ResultSet rs, int index) throws SQLException {
			Dept dept = new Dept();
			dept.setDeptId(rs.getInt("deptId"));
			dept.setDeptName(rs.getString("deptName"));
			return dept;
		}	
	}
}
public class App {
	// 容器物件
	ApplicationContext ac = new ClassPathXmlApplicationContext("cn/itcast/h_jdbc/bean.xml");
	@Test
	public void testApp() throws Exception {
		UserDao ud = (UserDao) ac.getBean("userDao");
//		ud.save();
		System.out.println(ud.findById(9));
		System.out.println(ud.getAll());
	}
}