1. 程式人生 > >第二天 : AOP 面向切面程式設計 、 JdbcTemplete 工具類使用

第二天 : AOP 面向切面程式設計 、 JdbcTemplete 工具類使用

AOP 面向切面程式設計 、 JdbcTemplete 工具類使用

目錄

一、 什麼是 AOP *****

二、 AOP 的底層實現

1、 JDK動態代理

2、 使用CGlib 完成動態代理

三、 Spring AOP

1、 傳統Spring AOP 提供 五類 Advice

2、 Spring 的切面  Advisor

3、案例一(不帶切點的切面) : 使用普通Advisor, 使用Advice作為一個切面 ,不定義切點,攔截目標類 所有方法

  1) 匯入jar包

  2) 編寫被代理 介面和實現類

  3) 編寫前置通知 (在目標方法前執行...)

  4) 為目標物件建立 , 配置applicationContext.xml

4 案例二 (帶有切點的切面): 定義單獨切點切面,指定被代理物件 哪些方法 會被增強

5、 自動代理

1) BeanNameAutoProxyCreator

2) DefaultAdvisorAutoProxyCreator

四、 使用AspectJ 實現AOP *****

1、 基於@AspectJ 程式設計

    1) 下載 匯入 aspectJ 開發包 (AspectJ 依賴 AOP 的 jar包 )

    2) 編寫Spring配置檔案  (需要aop名稱空間)

    3)    @AspectJ 常用註解

    4) 切點表示式定義

2、 基於XML配置 AspectJ 程式設計

五、 Spring JdbcTemplate 使用

1 、 Spring 提供 不同持久化技術 模板工具類

2、 快速入門

3、 外部屬性檔案引入

4、 使用JdbcTemplate 實現CURD 操作

1) Spring 為每種持久化技術 提供一個支援類

2)  通過jdbcTemplate 提供 int update(String sql, Object... args)  實現增加 、修改 、刪除

3)  簡單查詢,返回原始資料型別, String型別

4) 複雜查詢


一、 什麼是 AOP *****

AOP Aspect Oriented Programing 面向切面程式設計 , 人們說AOP 是對 OOP (面向物件程式設計)思想一個延伸
AOP採取橫向抽取機制,取代了傳統縱向繼承體系重複性程式碼(效能監視、事務管理、安全檢查、快取)

**** AOP 面向切面程式設計 底層原理 代理!!!
1、 Spring 傳統 AOP
2、 Spring 2.0 之後整合 AspectJ 第三方 AOP技術

相關術語 *****
Joinpoint(連線點):所謂連線點是指那些被攔截到的點。在spring中,這些點指的是方法,因為spring只支援方法型別的連線點.
Pointcut(切入點):所謂切入點是指我們要對哪些Joinpoint進行攔截的定義.
Advice(通知/增強):所謂通知是指攔截到Joinpoint之後所要做的事情就是通知.通知分為前置通知,後置通知,異常通知,最終通知,環繞通知(切面要完成的功能)
Introduction(引介):引介是一種特殊的通知在不修改類程式碼的前提下, Introduction可以在執行期為類動態地新增一些方法或Field.
Target(目標物件):代理的目標物件
Weaving(織入):是指把增強應用到目標物件來建立新的代理物件的過程.
    spring採用動態代理織入,而AspectJ採用編譯期織入和類裝在期織入
Proxy(代理):一個類被AOP織入增強後,就產生一個結果代理類
Aspect(切面): 是切入點和通知(引介)的結合

 

二、 AOP 的底層實現

AOP 底層使用的代理技術 : JDK動態代理 和 CGlib的動態代理

1、 JDK動態代理

原理: 針對記憶體中Class物件,使用類載入器 動態為目標物件實現介面的建立代理類
    * 代理類 是動態建立的, 代理類 和 被代理物件 實現相同介面
    * 被代理物件 必須要實現 介面 (JDK代理 只能針對介面 進行代理 )
    public class MyJDKProxy implements InvocationHandler {
        private UserDAO userDAO;// 被代理物件
        // 通過被代理物件 構造 代理類物件
        public MyJDKProxy(UserDAO userDAO) {
            this.userDAO = userDAO;
        }
        /**
         * 使用JDK進行 動態代理
         *
         * @param userDAO
         *            被代理物件
         * @return
         */
        public UserDAO createJDKProxy() {
            return (UserDAO) Proxy.newProxyInstance(userDAO.getClass()
                    .getClassLoader(), userDAO.getClass().getInterfaces(), this);
        }
        @Override
        // 訪問被代理物件 任何方法,都和執行 invoke
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            // 針對 add 方法進行 增強,記錄日誌 ...
            if (method.getName().equals("add")) {// 如果訪問方法 是 add方法
                System.out.println("記錄日誌....");
                // 呼叫目標方法
                return method.invoke(userDAO, args);
            } else {
                // 其它方法
                return method.invoke(userDAO, args);
            }
        }
    }

2、 使用CGlib 完成動態代理

    * JDK 動態代理原理, 為目標物件 介面生成代理物件 ,對於不使用介面的業務類,無法使用JDK動態代理

CGLIB(Code Generation Library)是一個開源專案!
    是一個強大的,高效能,高質量的Code生成類庫,它可以在執行期擴充套件Java類與實現Java介面。Hibernate支援CGlib 來實現PO位元組碼的動態生成。
    * Hibernate 預設PO 位元組碼生成技術  javassist

CGLIB 是一個第三方技術,使用時 ,需要下載 jar 包
    http://sourceforge.net/projects/cglib/
    * Spring3.2 版本, spring-core jar包 已經整合 cglib 開發類

原理 : CGlib採用非常底層位元組碼技術,可以為一個類建立子類,解決無介面代理問題
    public class MyCglibProxy implements MethodInterceptor {
        // 目標物件
        private ProductDAO productDAO;
        // 通過構造器 傳入被代理物件
        public MyCglibProxy(ProductDAO productDAO) {
            this.productDAO = productDAO;
        }
        // 建立代理
        public ProductDAO createCglibProxy() {
            // 建立代理核心物件
            Enhancer enhancer = new Enhancer();
            // 設定被代理類 (為類建立子類)
            enhancer.setSuperclass(productDAO.getClass());

            // 設定回撥函式
            enhancer.setCallback(this);

            // 返回代理 (返回代理子類物件)
            return (ProductDAO) enhancer.create();
        }
        @Override
        // 被代理物件所有方法執行 ,都會呼叫 intercept 方法
        public Object intercept(Object proxy, Method method, Object[] args,
                MethodProxy methodProxy) throws Throwable {
            // 為 addProduct 計算運算時間
            if (method.getName().equals("addProduct")) {// 當前執行方法
                long start = System.currentTimeMillis();
                Object result = methodProxy.invokeSuper(proxy, args);
                long end = System.currentTimeMillis();
                System.out.println("addProduct方法執行時間 : " + (end - start));
                return result;
            } else {
                // 不進行增強
                return methodProxy.invokeSuper(proxy, args);
            }
        }
    }

結論:
    1).若目標物件實現了若干介面,spring使用JDK的java.lang.reflect.Proxy類代理。
    2).若目標物件沒有實現任何介面,spring使用CGLIB庫生成目標物件的子類
程式中應優先對介面建立代理,便於程式解耦維護

 

三、 Spring AOP

AOP 開發規範 : AOP聯盟為通知Advice定義了org.aopalliance.aop.Interface.Advice
Spring AOP 實現 AOP聯盟定義 規範

1、 傳統Spring AOP 提供 五類 Advice

前置通知(程式碼增強) org.springframework.aop.MethodBeforeAdvice
    * 在目標方法執行前實施增強
後置通知 org.springframework.aop.AfterReturningAdvice
    * 在目標方法執行後實施增強
環繞通知 org.aopalliance.intercept.MethodInterceptor
    * 在目標方法執行前後實施增強
異常丟擲通知 org.springframework.aop.ThrowsAdvice
    * 在方法丟擲異常後實施增強
引介通知 org.springframework.aop.IntroductionInterceptor (課程不講 瞭解)
    * 在目標類中新增一些新的方法和屬性

2、 Spring 的切面  Advisor

    Advisor 就是對PointCut 應用 Advice (通常所說Advisor 指只有一個Point 和 一個 Advice )

型別:
Advisor : 代表一般切面,Advice本身就是一個切面,對目標類所有方法進行攔截 (沒有切點)
PointcutAdvisor : 代表具有切點的切面,可以指定攔截目標類哪些方法
IntroductionAdvisor : 代表引介切面,針對引介通知而使用切面(不要求掌握)

3、案例一(不帶切點的切面) : 使用普通Advisor, 使用Advice作為一個切面 ,不定義切點,攔截目標類 所有方法

  1) 匯入jar包

    匯入 aop聯盟的規範 : com.springsource.org.aopalliance-1.0.0.jar
    匯入 spring aop實現 : spring-aop-3.2.0.RELEASE.jar

  2) 編寫被代理 介面和實現類

    CustomerDAO
    CustomerDAOImpl

  3) 編寫前置通知 (在目標方法前執行...)

    MyMethodBeforeAdvice

  4) 為目標物件建立 , 配置applicationContext.xml

    使用ProxyFactoryBean 為目標物件建立代理

    <!-- 被代理物件 -->
    <bean id="customerDAO" class="cn.itcast.aop.c_advisor.CustomerDAOImpl"></bean>

    <!-- 增強 -->
    <bean id="mybeforeadvice" class="cn.itcast.aop.c_advisor.MyMethodBeforeAdvice"></bean>

    <!-- 建立代理  -->
    <bean id="customerDAOProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!-- 目標 -->
        <property name="target" ref="customerDAO"></property>
        <!-- 針對介面代理 -->
        <property name="proxyInterfaces" value="cn.itcast.aop.c_advisor.CustomerDAO"></property>
        <!-- 增強
            interceptorNames 表示可以運用多個 Advice, 必須寫value
        -->
        <property name="interceptorNames" value="mybeforeadvice"></property>
    </bean>

注意事項: 在程式設計時,應該使用 ProxyFactoryBean 建立後代理物件(CustomerDAOProxy ), 不要引入原來Bean (CustomerDAO)

4 案例二 (帶有切點的切面): 定義單獨切點切面,指定被代理物件 哪些方法 會被增強

    * JdkRegexpMethodPointcut 構造正則表示式切點
    * 使用正則表示式 切點切面 org.springframework.aop.support.RegexpMethodPointcutAdvisor
    1)  建立被代理物件 (沒有介面 的類 )
     OrderDAO
    2)  增強 (編寫環繞通知)
      MyMethodInterceptor
    3) 通過配置 ProxyFactory 為目標物件建立代理
    <!-- 定義切點切面 -->
    <bean id="myadvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <!-- 正則表示式規則 -->
        <property name="pattern" value=".*"></property>
        <property name="advice" ref="mymethodinterceptor"></property>
    </bean>

    <!-- 建立代理 -->
    <bean id="orderDAOProxy" class="org.springframework.aop.framework.ProxyFactoryBean" >
        <!-- 目標 -->
        <property name="target" ref="orderDAO"></property>
        <!-- 針對類代理 -->
        <property name="proxyTargetClass" value="true"></property>
        <!-- 增強 -->
        <property name="interceptorNames" value="myadvisor"></property>
    </bean>

正則表示式案例
    cn\.itcast\.aop\.d_pointcutadvisor\.OrderDAO\.save.*   ---- 執行OrderDAO 的save方法
    .*save.*  ----- 包含save方法
    <property name="patterns" value=".*save.*,.*delete.*"></property> ---- 同時增強save和delete方法

5、 自動代理

    使用ProxyFactoryBean 建立代理,需要為每個Bean 都配置一次 ,非常麻煩
    自動代理原理: 根據xml中配置advisor的規則,得知切面對哪個類的哪個方法進行代理 (切面中本身就包含 被代理物件資訊) ,就不需要ProxyFactoryBean ,使用BeanPostProcessor 完成自動代理

BeanNameAutoProxyCreator 根據Bean名稱建立代理
DefaultAdvisorAutoProxyCreator 根據Advisor本身包含資訊建立代理
* AnnotationAwareAspectJAutoProxyCreator 基於Bean中的AspectJ 註解進行自動代理

1) BeanNameAutoProxyCreator

    <!-- 第一種 BeanName自動代理  -->
    <!-- 後處理Bean 不需要配置 id -->
    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <!-- 對所有DAO結尾Bean 進行代理 -->
        <property name="beanNames" value="*DAO"></property>
        <!-- 增強 -->
        <property name="interceptorNames" value="mymethodinterceptor"></property>
    </bean>

*** 自動代理和ProxyFactoryBean 本質區別 :
    ProxyFactoryBean, 先有被代理物件, 傳遞ProxyFactoryBean,建立代理
    自動代理 , 在Bean構造過程中, 使用後處理Bean 建立代理,返回構造完成物件就是代理物件

2) DefaultAdvisorAutoProxyCreator

    基於切面資訊進行代理

    <!-- 切面 -->
    <bean id="myadvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <!-- 切點攔截資訊 -->
        <property name="patterns" value="cn\.itcast\.aop\.d_pointcutadvisor\.OrderDAO\.save.*"></property>
        <!-- 增強 -->
        <property name="advice" ref="mybeforeadvice"></property>
    </bean>

    <!-- 第二種 基於切面資訊自動代理  -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>

 

四、 使用AspectJ 實現AOP *****

AspectJ是一個面向切面的框架,它擴充套件了Java語言。AspectJ定義了AOP語法所以它有一個專門的編譯器用來生成遵守Java位元組編碼規範的Class檔案。

Spring2.0之後 為了簡化 AOP程式設計,支援AspectJ 技術
@AspectJ 是AspectJ1.5新增功能,通過JDK5註解技術,允許直接在Bean類中定義切面

新版本Spring框架,建議使用AspectJ方式來開發AOP ,而不需要使用傳統 Spring AOP 程式設計

1、 基於@AspectJ 程式設計

    1) 下載 匯入 aspectJ 開發包 (AspectJ 依賴 AOP 的 jar包 )

    AspectJ開發包 com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
    匯入spring 整合 aspectj 的jar包 spring-aspects-3.2.0.RELEASE.jar

    2) 編寫Spring配置檔案  (需要aop名稱空間)

        使用 <aop:aspectj-autoproxy />  配置自動代理
        * 底層 <bean class="... AnnotationAwareAspectJAutoProxyCreator" />

    3) @AspectJ 常用註解

        @Aspect 定義切面
    通知型別
        @Before 前置通知,相當於BeforeAdvice
        @AfterReturning 後置通知,相當於AfterReturningAdvice
        @Around 環繞通知,相當於MethodInterceptor
        @AfterThrowing丟擲通知,相當於ThrowAdvice
        @After 最終final通知,不管是否異常,該通知都會執行
        @DeclareParents 引介通知,相當於IntroductionInterceptor (不要求掌握)

    4) 切點表示式定義

        切點使用指定哪些連線點 會被增強 , 通過execution函式,可以定義切點的方法切入
        語法: execution(<訪問修飾符>?<返回型別><方法名>(<引數>)<異常>)
    例如:
        execution(public * *(..)) 匹配所有public修飾符 任何方法
        execution(* cn.itcast.service.HelloService.*(..))  匹配HelloService類中所有方法
        execution(int cn.itcast.service.UserService.regist(..))  匹配UserService中int返回型別 regist方法
        execution(* cn.itcast.dao..*(..))  匹配cn.itcast.dao包下 (包含子包) 所有類 所有方法
        execution(* cn.itcast.dao.*(..)) 不包含子包
        execution(* cn.itcast.dao.GenericDAO+.*(..))  匹配GenericDAO 所有子類 或者 實現類 所有方法


開發步驟
    第一步 : 匯入jar、 自動代理
    第二步 : 編寫被代理物件
        UserDAO
    第三步 : 編寫切面類
        @Aspect
        // 聲明當前類是一個切面類
        public class MyAspect {
            // 前置增強
            @Before("execution(* cn.itcast.aspectj.a_annotation.UserDAO.*(..))")
            public void before1() {
                System.out.println("前置增強 1 ...");
            }

            @Before("execution(* cn.itcast.aspectj.a_annotation.UserDAO.*(..))")
            public void before2() {
                System.out.println("前置增強2 ...");
            }
        }
    第四步: 配置applicationContext.xml 註冊被代理物件 和 切面類
            <!-- 被代理目標 -->
            <bean id="userDAO" class="cn.itcast.aspectj.a_annotation.UserDAO"></bean>

            <!-- 切面 -->
            <bean id="myaspect" class="cn.itcast.aspectj.a_annotation.MyAspect"></bean>

@AspectJ 支援通知型別詳解 :
    第一種 前置通知 @Before  : 前置通知不能攔截目標方法執行 , 每個前置通知方法接收JoinPoint
        * JoinPoint  引包 org.aspectj.lang.JoinPoint
        * JoinPoint  獲得攔截增強方法資訊
    第二種 後置通知 @AfterReturning : 後置通知,在目標方法執行,返回後 呼叫增強程式碼
        * 通過 returning 獲得目標方法返回值
    // 後置增強
    @AfterReturning(value = "execution(* cn.itcast.aspectj.a_annotation.UserDAO.update(..))", returning = "returnValue")
    // returnValue 是代理方法 ,引數名, 用來獲得目標業務方法執行後返回值
    public void afterReturning(Object returnValue) {
        System.out.println("後置增強.... 獲得方法返回值:" + returnValue);
    }

    第三種 環繞通知 @Around : 在目標方法前後增強 ,阻止目標方法執行
        * 引數為ProceedingJoinPoint 可以呼叫攔截目標方法執行
    // 環繞增強
    @Around("execution(* cn.itcast.aspectj.a_annotation.UserDAO.search(..))")
    // 可以阻止目標方法執行,通過引數
    public Object around(ProceedingJoinPoint proceedingJoinPoint)
            throws Throwable {
        System.out.println("環繞前增強...");
        Object result = proceedingJoinPoint.proceed();// 執行目標方法
        System.out.println("環繞後增強...");
        return result;
    }
    如果 不寫 proceedingJoinPoint.proceed(); 目標方法就無法執行

    第四種 丟擲通知 @AfterThrowing : 在方法出現異常後,該方法獲得執行
        * 在方法沒有錯誤時,不會得到執行
    // 丟擲增強
    @AfterThrowing(value = "execution(* cn.itcast.aspectj.a_annotation.UserDAO.search(..))", throwing = "e")
    // throwing 用來指定異常物件 引數名稱
    public void afterThrowing(Throwable e) {
        System.out.println("不好了,出問題了, " + e.getMessage());
    }

    第五種 最終通知 @After : 不管目標方法是否存在異常,都將執行 類似finally 程式碼塊(釋放資源)
    // 最終增強 ,無論目標方法是否有異常,都必須執行
    @After("execution(* cn.itcast.aspectj.a_annotation.UserDAO.search(..))")
    public void after() {
        System.out.println("這是必須執行的程式碼 .....");
    }

@Pointcut 切點定義
    在通知上定義切點表示式,會造成一些切點表示式重複
    在每個通知內定義切點,會造成工作量大,不易維護,對於重複的切點,可以使用@Poingcut進行定義

    格式: private void 無引數方法,方法名為切點名
    @Pointcut("execution(* cn.itcast.aspectj.a_annotation.UserDAO.search(..))")
    private void mypointcut() {}

    應用切點的通知
    @After("MyAspect.mypointcut()")
    public void after() {
        System.out.println("這是必須執行的程式碼 .....");
    }
    * 在Aspect中 可以定義 多個切點

面試題 : advisor 和 aspect 區別 ?
    advisor 是 spring 中 aop定義切面,通常由一個切點和一個通知組成
    aspect 是規範中切面 , 允許由多個切點和 多個通知組成

2、 基於XML配置 AspectJ 程式設計

     1) 定義被代理物件 ProductDAO
     2) 定義切面 MyAspect

     3) 編寫Advice增強方法,在xml配置
        前置通知
            public void before() {
                System.out.println("前置增強....");
            }
            <aop:config>
                <!-- 定義切面 -->
                <aop:aspect ref="myAspect">
                    <!-- 切點 -->
                    <aop:pointcut expression="execution(* cn.itcast.aspectj.b_xml.ProductDAO.*(..))" id="mypointcut"/>
                    <!-- 通知 -->
                    <aop:before method="before" pointcut-ref="mypointcut"/>
                </aop:aspect>
            </aop:config>
        後置增強
            // 後置增強 (返回值)
            public void afterReturing(Object returnVal) {
                System.out.println("後置增強,返回值: " + returnVal);
            }

            <aop:after-returning method="afterReturing" returning="returnVal" pointcut-ref="mypointcut"/>
            returning 指定方法代表返回值引數名
        環繞增強
            public Object around(ProceedingJoinPoint proceedingJoinPoint)
                    throws Throwable {
                System.out.println("環繞前增強...");
                Object result = proceedingJoinPoint.proceed();
                System.out.println("環繞後增強....");
                return result;
            }

            <aop:around method="around" pointcut-ref="mypointcut"/>
        異常通知
            public void afterThrowing(Throwable ex) {
                System.out.println("發生異常,原因: " + ex.getMessage());
            }

            <aop:after-throwing method="afterThrowing" throwing="ex" pointcut-ref="mypointcut"/>
        最終通知
            public void after() {
                System.out.println("最終通知....");
            }
            <aop:after method="after" pointcut-ref="mypointcut"/>

問題:
    1、 AOP的思想是什麼 ?
    2、 struts2 的攔截器機制使用 AOP的思想? 能說說嗎?
    3、 AOP在開發中能實現哪些功能呢?
    4、 使用AOP 實現監控業務層方法執行時間? 你會嗎?


五、 Spring JdbcTemplate 使用

1 、 Spring 提供 不同持久化技術 模板工具類

JDBC  ----  org.springframework.jdbc.core.JdbcTemplate
Hibernate3.0  --- org.springframework.orm.hibernate3.HibernateTemplate
IBatis(MyBatis)    --- org.springframework.orm.ibatis.SqlMapClientTemplate
JPA    --- org.springframework.orm.jpa.JpaTemplate

JdbcTemplate 是用來簡化JDBC操作的 , 操作和Apache DbUtils 框架非常類似

2、 快速入門

   步驟一 : 匯入jar包
    在Spring 最基本jar包 基礎上, 匯入JDBC模板開發包
        spring-jdbc-3.2.0.RELEASE.jar  --- 存放JdbcTemplate 工具類
        spring-tx-3.2.0.RELEASE.jar   ---- 進行事務管理
    操作資料庫 別忘了驅動
        mysql-connector-java-5.1.13-bin.jar ----資料庫連線驅動

    步驟二 :編寫配置檔案
        1) 建立連線池
        2) 構造jdbcTemplate物件
        3) 執行SQL語句
步驟二的實現可以分為兩種情況:

 *** 情況一:不使用xml 配置資料庫連線池(愚蠢的做法)
        程式碼實現:
            public void demo1() {

                // 1 構造jdbcTemplate 必須 資料庫連線池
                // 內建 連線池 DriverManagerDataSource

                DriverManagerDataSource dataSource = new DriverManagerDataSource();
                dataSource.setDriverClassName("com.mysql.jdbc.Driver");
                dataSource.setUrl("jdbc:mysql:///spring3day2");
                dataSource.setUsername("root");
                dataSource.setPassword("abc");


                // 2、使用連線池構造 jdbcTemplate
                JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

                // 3、操作資料庫
                jdbcTemplate.execute("create table user(id int, name varchar(20))");
            }

*** 情況二、使用xml 配置資料庫連線池(明智的選擇)
    常用資料來源
    * Spring 資料來源實現類 DriverManagerDataSource
        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
            <property name="url" value="jdbc:mysql:///spring3day2"></property>
            <property name="username" value="root"></property>
            <property name="password" value="abc"></property>
        </bean>
    * DBCP 資料來源 BasicDataSource
        匯入jar包
        com.springsource.org.apache.commons.dbcp-1.2.2.osgi.jar
        com.springsource.org.apache.commons.pool-1.5.3.jar

        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
            <property name="url" value="jdbc:mysql:///spring3day2"></property>
            <property name="username" value="root"></property>
            <property name="password" value="abc"></property>
        </bean>


    * C3P0 資料來源  ComboPooledDataSource (重點掌握)
        匯入jar包
        com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar

        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
            <property name="jdbcUrl" value="jdbc:mysql:///spring3day2"></property>
            <property name="user" value="root"></property>
            <property name="password" value="abc"></property>
        </bean>

3、 外部屬性檔案引入

    在Spring 直接修改常用屬性,不方便,可以將屬性抽取出來 建立單獨 properties 檔案,在Spring 中引入properties

在Spring的applicationContext.xml 引入properties 有兩種寫法

寫法一 :
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
          <property name="location" value="classpath:jdbc.properties"></property>
    </bean>

將連線池配置引數,使用 ${屬性key}
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"></property>
        <property name="jdbcUrl" value="${jdbc.url}"></property>
        <property name="user" value="${jdbc.user}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>

寫法二:
    <context:property-placeholder location="classpath:jdbc.properties" />

4、 使用JdbcTemplate 實現CURD 操作

    UserDAO 實現資料庫操作,必須要使用 JdbcTemplate, Spring 將jdbcTemplate 注入 UserDAO

1) Spring 為每種持久化技術 提供一個支援類

    支援類作用,在DAO 中注入 模板工具類
    JDBC :    org.springframework.jdbc.core.support.JdbcDaoSupport
    Hibernate 3.0 :org.springframework.orm.hibernate3.support.HibernateDaoSupport
    iBatis :org.springframework.orm.ibatis.support.SqlMapClientDaoSupport

使用者自己編寫DAO 只需要繼承 JdbcDaoSupport, 就可以注入 JdbcTemplate

2)  通過jdbcTemplate 提供 int update(String sql, Object... args)  實現增加 、修改 、刪除

3)  簡單查詢,返回原始資料型別, String型別

    String sql = "select count(*) from user";   //  int queryForInt(String sql)
    String sql = "select name from user where id = ? "; // <T> T queryForObject(String sql, Class<T> requiredType, Object... args)

4) 複雜查詢

    JdbcTemplate 沒有handler, 手動完成物件封裝

編寫實體類 RowMapper
    class UserRowMapper implements RowMapper<User> {
        @Override
        public User mapRow(ResultSet rs, int rowNum) throws SQLException {
            // rs 已經指向每一條資料,不需要自己呼叫 next,將rs指向資料 轉換 User物件
            User user = new User();
            user.setId(rs.getInt("id"));
            user.setName(rs.getString("name"));
            return user;
        }
    }

查詢單個物件  <T> T queryForObject(String sql, RowMapper<T> rowMapper, Object... args)
    return this.getJdbcTemplate().queryForObject(sql, new UserRowMapper(),id);
    
    //RowMapper:行對映器---把每一條記錄轉換成一個物件

查詢所有物件List集合 <T> List<T> query(String sql, RowMapper<T> rowMapper, Object... args)
     return this.getJdbcTemplate().query(sql, new UserRowMapper());


總結:
1、 AOP概述 : 橫向抽取機制和縱向繼承 , AOP術語 (掌握)
2、 AOP 底層實現 : JDK動態代理 和 CGLib 動態代理 (瞭解)
3、 使用ProxyFactoryBean 建立代理 (瞭解)
    無切點切面
    帶有切點切面
4、 掌握自動代理如何實現 ---- 後處理Bean ,在Bean構造過程中完成代理
5、 註解 實現 AspectJ (掌握)
    @Aspect
    @Pointcut

    @Before @AfterReturning  @Around @AfterThrowing @After 必須
    **** 重點使用  @Around 環繞增強 (日誌、執行時間、許可權)
6、 XML 實現AspectJ (掌握)

7、 JdbcTemplate  (掌握)
    資料庫連線池配置
    外部屬性檔案
    增刪改查DAO