Spring學習筆記(二)

Spring學習筆記(二)

這是一個沉澱的過程,大概第一次接觸Spring是在去年的這個時候,當初在實訓,初次接觸Java web,直接學習SSM框架(當是Servlet都沒有學),因而,養成了一個很很差的學習習慣,就是「照貓畫虎」。別人作什麼,照着樣子就是了,沒有任何的思考,這樣的學習習慣確定不會走太遠。如今我產生不少疑惑,這是什麼?爲何這麼作?如何作的更好?所以此次筆記的主題就是《這是什麼?java

1. AOP

1.1 AOP介紹

1.1.1 什麼是AOP

  • 在軟件業,AOP爲Aspect Oriented Programming的縮寫,意爲:面向切面編程,經過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。AOP是OOP(面向對象編程)的延續,是軟件開發中的一個熱點,也是Spring框架中的一個重要內容,是函數式編程的一種衍生範型。利用AOP能夠對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度下降,提升程序的可重用性,同時提升了開發的效率。
  • AOP採起橫向抽取機制,取代了傳統縱向繼承體系重複性代碼
  • 經典應用:事務管理、性能監視、安全檢查、緩存 、日誌等
  • Spring AOP使用純Java實現,不須要專門的編譯過程和類加載器,在運行期經過代理方式向目標類織入加強代碼
  • AspectJ是一個基於Java語言的AOP框架,Spring2.0開始,Spring AOP引入對Aspect的支持,AspectJ擴展了Java語言,提供了一個專門的編譯器,在編譯時提供橫向代碼的織入

1.1.2 AOP 實現原理

  • aop底層將採用代理機制進行實現。
  • 接口 + 實現類:spring採用 jdk 的動態代理Proxy。
  • 實現類:spring 採用 cglib字節碼加強。

1.1.2 AOP 術語

  1. target目標類:須要被代理的類。例如:UserService
  2. Joinpoint鏈接點:所謂鏈接點是指那些可能被攔截到的方法。例如:全部的方法
  3. PointCut切入點:已經被加強的鏈接點。例如:addUser()web

  4. advice通知/加強,加強代碼。例如:after、before
  5. Weaving織入:是指把加強advice應用到目標對象target來建立新的代理對象proxy的過程.
  6. proxy代理類
  7. Aspect切面:是切入點pointcut和通知advice的結合
    一個線是一個特殊的面。
    一個切入點和一個通知,組成成一個特殊的面。
    術語spring

1.2 手動方式

1.2.1 JDK 動態代理

  • JDK動態代理 對「裝飾者」設計模式 簡化。使用前提:必須有接口
  1. 目標類:接口 + 實現類
  2. 切面類:用於存通知 MyAspect
  3. 工廠類:編寫工廠生成代理
  4. 測試
    jdk動態代理sql

    1.2.1.1 目標類
public interface UserService {

    void addUser();
    void updateUser();
    void deleteUser();
}
1.2.1.2 切面類
public class MyAspect {

    public void before(){
        System.out.println("this is before");
    }

    public void after(){
        System.out.println("this is after");
    }
}
1.2.1.3 工廠
public class MyBeanFactory {

    public static UserService createService(){
        //1 目標類
        final UserService userService = new UserServiceImpl();
        //2 切面類
        final MyAspect myAspect = new MyAspect();
        /**
         * 3 代理類:將目標類(切入點)和 切面類(通知) 結合 --> 切面
         *  Proxy.newProxyInstance
         *      參數1:loader ,類加載器,動態代理類 運行時建立,任何類都須要類加載器將其加載到內存。
         *          通常狀況:當前類.class.getClassLoader();
         *          目標類實例.getClass().get...
         *      參數2:Class[] interfaces 代理類須要實現的全部接口
         *          方式1:目標類實例.getClass().getInterfaces()  ;注意:只能得到本身接口,不能得到父元素接口
         *          方式2:new Class[]{UserService.class}
         *          例如:jdbc 驅動  --> DriverManager  得到接口 Connection
         *      參數3:InvocationHandler  處理類,接口,必須進行實現類,通常採用匿名內部
         *          提供 invoke 方法,代理類的每個方法執行時,都將調用一次invoke
         *              參數31:Object proxy :代理對象
         *              參數32:Method method : 代理對象當前執行的方法的描述對象(反射)
         *                  執行方法名:method.getName()
         *                  執行方法:method.invoke(對象,實際參數)
         *              參數33:Object[] args :方法實際參數
         *
         */
        UserService proxService = (UserService) Proxy.newProxyInstance(
                MyBeanFactory.class.getClassLoader(),
                userService.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        //前執行
                        myAspect.before();

                        //執行目標類的方法
                        Object obj = method.invoke(userService,args);

                        //後方法
                        myAspect.after();

                        return obj;
                    }
                }
        );
        return proxService;
    }
    }
}
1.2.1.4 測試類
@Test
    public void demo01(){
        UserService userService = MyBeanFactory.createService();
        userService.addUser();
        userService.updateUser();
        userService.deleteUser();
    }

1.2.2 CGLIB 字節碼加強

  • 沒有接口,只有實現類
  • 採用字節碼加強框架cglib,在運行時建立目標類的子類,從而對目標類進行加強。
  • 導入jar包:
    本身導包(瞭解):
    核心:hibernate-distribution-3.6.10.Final\lib\bytecode\cglib\cglib-2.2.jar
    依賴:struts-2.3.15.3\apps\struts2-blank\WEB-INF\lib\asm-3.3.jar
    spring-core..jar 已經整合以上兩個內容
    CCGLIB代理
1.2.2.1 工廠類
public class MyBeanFactory {

    public static UserService createService(){
        //1 目標類
        final UserService userService = new UserServiceImpl();
        //2 切面類
        final MyAspect myAspect = new MyAspect();
        // 3.代理類 ,採用cglib ,底層建立目標類的子類
        // 3.1 核心類
        Enhancer enhancer = new Enhancer();
        // 3.2 肯定父類
        enhancer.setSuperclass(userService.getClass());

        /**
         * 3.3 設置回調函數 , MethodInterceptor接口 等效 jdk InvocationHander接口
         *      intercept() 等效 jdk  invoke()
         *          參數一、參數二、參數3:以invoke同樣
         *          參數4:methodProxy 方法的代理
         */

        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                //前執行
                myAspect.before();

                //執行目標類方法
                Object obj = method.invoke(userService,objects);
                // * 執行代理類的父類,執行目標類(目標類和代理類 父子關係)
             //   methodProxy.invokeSuper(o,objects);

                //後執行
                myAspect.after();
                return obj;
            }
        });
        //3.4 建立代理
        UserServiceImpl proxService = (UserServiceImpl) enhancer.create();

        return proxService;
    }
}

1.3 AOP 聯盟通知類型

  • AOP聯盟爲通知Advice定義了org.aopalliance.aop.Advice
  • Spring按照通知Advice在目標類方法的鏈接點位置,能夠分爲5類
    • 前置通知 org.springframework.aop.MethodBeforeAdvice
      • 在目標方法執行前實施加強
    • 後置通知 org.springframework.aop.AfterReturningAdvice
      • 在目標方法執行後實施加強
    • 環繞通知 org.aopalliance.intercept.MethodInterceptor
      • 在目標方法執行先後實施加強
    • 異常拋出通知 org.springframework.aop.ThrowsAdvice
      • 在方法拋出異常後實施加強
    • 引介通知 org.springframework.aop.IntroductionInterceptor
      • 在目標類中添加一些新的方法和屬性
      環繞通知,必須手動執行目標方法
      try{
       //前置通知
       //執行目標方法
       //後置通知
      } catch(){
       //拋出異常通知
      }

      1.4 spring 編寫代理:半自動

  • 讓spring 建立代理對象,從spring容器中手動的獲取代理對象。
  • 導入jar包:
    核心:4+1
    AOP:AOP聯盟(規範)、spring-aop (實現)
    jar

1.4.1 目標類

public interface UserService {

    void addUser();
    void updateUser();
    void deleteUser();
}

1.4.2 切面類

/**
 *  切面類中肯定通知,須要實現不一樣接口,接口就是規範,從而就肯定方法名稱。
 *  採用「環繞通知」 MethodInterceptor
 */
public class MyAspect implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("this is before");

        //手動執行目標方法
        Object obj = methodInvocation.proceed();

        System.out.println("this is after");
        return obj;
    }
}

1.4.3 spring 配置

<!-- 1 建立目標類-->
    <bean id="userService" class="com.springlearning.spring_proxy.UserServiceImpl"></bean>
    <!-- 2 建立切面類-->
    <bean id="myAspect" class="com.springlearning.spring_proxy.MyAspect"></bean>

    <!-- 3 建立代理類
         * 使用工廠bean FactoryBean ,底層調用getObject() 返回特殊bean
         * ProxyFactoryBean 用於建立代理工廠bean ,生成特殊代理對象
                interfaces : 肯定接口們
                    經過<array> 能夠設置多個值
                    只有一個值時, value=""
                target : 肯定目標類
                interceptorNames : 通知 切面類的名稱,類型String[], 若是設置一個值 value=""
                optimize :強制使用cglib
                    <property name="optimize" value="true"></property>
          底層機制
                若是目標類有接口,採用jdk動態代理
                若是沒有接口,採用cglib 字節碼加強
                若是聲明 optimize = true ,不管是否有接口 ,都採用cglib
    -->
    <bean id="proxyService" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="interfaces" value="com.springlearning.spring_proxy.UserService"></property>
        <property name="target" ref="userService"></property>
        <property name="interceptorNames" value="myAspect"></property>
    </bean>

1.4.4 測試

@Test
    public void demo01(){
        String xmlPath = "com/springlearning/spring_proxy/beans.xml";
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        //得到代理類
        UserService userService = (UserService) applicationContext.getBean("proxyService");
        userService.addUser();
        userService.updateUser();
        userService.deleteUser();
    }

1.5 spring aop 編程:全自動

  • 從spring容器得到目標類,若是配置aop,spring將自動生成代理。
  • 要肯定目標類,aspectj 切入點表達式,導入jar包
  • 在spring-aop-5.0.4版本中包含了aopalliance和aspectj
    jar包數據庫

  • 這裏我在調試的時候出了問題,其中在spring-aop-5.0.4版本中包含了aopalliance,而我看的教學是3.x的版本,須要導入另外的aopalliance包,還有錯把aspectjrt 當成 aspectjweaver,然而兩個包有着不一樣的功能。express

1.5.1 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: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">

    <!-- 1 建立目標類 -->
    <bean id="userService" class="com.springlearning.spring_proxy.UserServiceImpl"></bean>
    <!-- 2 建立切面類(通知)-->
    <bean id="myAspect" class="com.springlearning.spring_proxy.MyAspect"></bean>
    <!-- 3 aop編程
        3.1 導入命名空間
        3.2 使用 <aop:config> 進行配置
                proxy-target-class="true" 聲明時使用cglib代理
            <aop:pointcut> 切入點 , 從目標對象得到具體方法
            <aop:advisor> 特殊的切面, 只用一個通知 和一個切入點
                advice-ref 通知引用
                pointcut-ref 切入點引用
        3.3 切入點表達式
            execution(* com.springlearning.spring_proxy.*.(..))
            選擇方法   返回值任意  包         類名稱任意  方法名任意   參數任意
    -->
    <aop:config proxy-target-class="true">
        <aop:pointcut id="myPointCut" expression="execution(* com.springlearning.spring_proxy.*.*(..))"/>
        <aop:advisor advice-ref="myAspect" pointcut-ref="myPointCut"></aop:advisor>
    </aop:config>
</beans>

1.5.2 測試

@Test
    public void demo01(){
        String xmlPath = "com/springlearning/spring_proxy/beans.xml";
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);

        //得到代理類
        UserService userService = (UserService) applicationContext.getBean("userService");
        userService.addUser();
        userService.updateUser();
        userService.deleteUser();
    }

2. AspectJ

2.1 介紹

  • AspectJ是一個基於Java語言的AOP框架
  • Spring2.0之後新增了對AspectJ切點表達式支持
  • @AspectJ 是AspectJ1.5新增功能,經過JDK5註解技術,容許直接在Bean類中定義切面
    新版本Spring框架,建議使用AspectJ方式來開發AOP
  • 主要用途:自定義開發

2.2 切入點表達式

  1. execution() 用於描述方法
    語法:execution(修飾符 返回值 包.類.方法名(參數) throws異常)
    修飾符,通常省略
    public 公共方法
    * 任意
    返回值,不能省略
    void 返回沒有值
    String 返回值字符串
    * 任意
    包,[省略]
    com.springlearning.proxy 固定包
    com.springlearning.proxy..service proxy包下面子包任意 (例如:com.springlearning.proxy.staff.service)
    com.springlearning.proxy.. proxy包下面的全部子包(含本身)
    com.springlearning.proxy.
    .service.. proxy包下面任意子包,固定目錄service,service目錄任意包
    類,[省略]
    UserServiceImpl 指定類
    Impl 以Impl結尾
    User
    以User開頭
    * 任意
    方法名,不能省略
    addUser 固定方法
    add* 以add開頭
    Do 以Do結尾
    任意
    (參數)
    () 無參
    (int) 一個整型
    (int ,int) 兩個
    (..) 參數任意
    throws ,可省略,通常不寫。

綜合 1
execution(* com.springlearning.proxy..service...*(..))apache

綜合 2
<aop:pointcut expression="execution(* com.springlearning.WithCommit.(..)) ||
execution(* com.springlearning.Service.(..))" id="myPointCut"/>編程

  1. within:匹配包或子包中的方法
    within(com.springlearning.aop..*)
  2. this:匹配實現接口的代理對象中的方法
    this(com.springlearning.aop.user.UserDAO)
  3. target:匹配實現接口的目標對象中的方法
    target(com.springlearning.aop.user.UserDAO)
  4. args:匹配參數格式符合標準的方法
    args(int,int)
  5. bean(id) 對指定的bean全部的方法(瞭解)
    bean('userService')

2.3 AspectJ 通知類型

  • aop聯盟定義通知類型,具備特性接口,必須實現,從而肯定方法名稱。
  • aspectj 通知類型,只定義類型名稱。已經方法格式。
  • 個數:6種,知道5種,掌握1中
    before:前置通知(應用:各類校驗)
    在方法執行前執行,若是通知拋出異常,阻止方法運行
    afterReturning:後置通知(應用:常規數據處理)
    方法正常返回後執行,若是方法中拋出異常,通知沒法執行
    必須在方法執行後才執行,因此能夠得到方法的返回值。
    around:環繞通知(應用:十分強大,能夠作任何事情)
    方法執行先後分別執行,能夠阻止方法的執行
    必須手動執行目標方法
    afterThrowing:拋出異常通知(應用:包裝異常信息)
    方法拋出異常後執行,若是方法沒有拋出異常,沒法執行
    after:最終通知(應用:清理現場)
    方法執行完畢後執行,不管方法中是否出現異常
環繞

try{
     //前置:before
    //手動執行目標方法
    //後置:afterRetruning
} catch(){
    //拋出異常 afterThrowing
} finally{
    //最終 after
}

aspectj通知類型
相關類
AfterThrowing
After

2.4 導入jar包

  • 4個:
    aop聯盟規範
    spring aop 實現
    aspect 規範
    spring aspect 實現

2.5 基於xml

  1. 目標類:接口 + 實現
  2. 切面類:編寫多個通知,採用aspectj 通知名稱任意(方法名任意)
  3. aop編程,將通知應用到目標類
  4. 測試

2.5.1 切面類

/**
 * 切面類,含有多個通知
 */
public class MyAspect {

    public void myBefore(JoinPoint joinPoint){
        System.out.println("前置通知:" + joinPoint.getSignature().getName());
    }
    public void myAfterReturning(JoinPoint joinPoint,Object ret){
        System.out.println("後置通知 : " + joinPoint.getSignature().getName() + " , -->" + ret);
    }
    public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.println("前");
        //手動執行目標方法
        Object obj = joinPoint.proceed();
        System.out.println("後");
        return obj;
    }
    public void myAfterThrowing(JoinPoint joinPoint,Throwable throwable){
        System.out.println("拋出異常通知:" + throwable.getMessage());
    }
    public void myAfter(JoinPoint joinPoint){
        System.out.println("最終通知");
    }
}

2.5.2 spring配置

<!-- 1 建立目標類 -->
    <bean id="userService" class="com.springlearning.aspectj.UserServiceImpl"></bean>
    <!-- 2 建立切面類(通知)-->
    <bean id="myAspect" class="com.springlearning.aspectj.MyAspect"></bean>
    <!-- 3 aop編程
          <aop:aspect> 將切面類 聲明「切面」,從而得到通知(方法)
                ref 切面類引用
          <aop:pointcut> 聲明一個切入點,全部通知均可以使用。
                expression 切入點表達式
                id 名稱,用於其餘通知引用
    -->
    <aop:config>
        <aop:aspect ref="myAspect">
            <aop:pointcut id="myPointcut" expression="execution(* com.springlearning.aspectj.UserServiceImpl.*(..))"/>
            <!-- 3.1 前置通知
                <aop:before method="" pointcut="" pointcut-ref=""/>
                    method : 通知,及方法名
                    pointcut :切入點表達式,此表達式只能當前通知使用。
                    pointcut-ref : 切入點引用,能夠與其餘通知共享切入點。
                通知方法格式:public void myBefore(JoinPoint joinPoint){
                    參數1:org.aspectj.lang.JoinPoint  用於描述鏈接點(目標方法),得到目標方法名等
                例如:
            <aop:before method="myBefore" pointcut-ref="myPointCut"/>
            -->

            <!-- 3.2後置通知  ,目標方法後執行,得到返回值
                <aop:after-returning method="" pointcut-ref="" returning=""/>
                    returning 通知方法第二個參數的名稱
                通知方法格式:public void myAfterReturning(JoinPoint joinPoint,Object ret){
                    參數1:鏈接點描述
                    參數2:類型Object,參數名 returning="ret" 配置的
                例如:
            <aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="ret" />
            -->

            <!-- 3.3 環繞通知
                <aop:around method="" pointcut-ref=""/>
                通知方法格式:public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
                    返回值類型:Object
                    方法名:任意
                    參數:org.aspectj.lang.ProceedingJoinPoint
                    拋出異常
                執行目標方法:Object obj = joinPoint.proceed();
                例如:
            <aop:around method="myAround" pointcut-ref="myPointCut"/>
            -->
            <!-- 3.4 拋出異常
                <aop:after-throwing method="" pointcut-ref="" throwing=""/>
                    throwing :通知方法的第二個參數名稱
                通知方法格式:public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
                    參數1:鏈接點描述對象
                    參數2:得到異常信息,類型Throwable ,參數名由throwing="e" 配置
                例如:
            <aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="e"/>
            -->
            <!-- 3.5 最終通知-->
            <aop:after method="myAfter" pointcut-ref="myPointcut"></aop:after>

        </aop:aspect>

    </aop:config>

2.6 基於註解

2.6.1 替換bean

<!-- 1 建立目標類 -->
    <bean id="userService" class="com.springlearning.aspectj.UserServiceImpl"></bean>
    <!-- 2 建立切面類(通知)-->
    <bean id="myAspect" class="com.springlearning.aspectj.MyAspect"></bean>
@Component
public class MyAspect {
@Service("userService")
public class UserServiceImpl implements UserService {
  • 注意:掃描
<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"
       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
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 1. 掃描 註解類 -->
    <context:component-scan base-package="com.springlearning.aspectj"></context:component-scan>

2.6.2 替換 aop

  • 必須進行aspectj 自動代理
<!-- 2.肯定 aop註解生效 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  • 聲明切面
<aop:aspect ref="myAspect"> <!--被下面註解替換 -->
@Component
@Aspect //添加註解
public class MyAspect {
  • 替換前置通知
<aop:before method="myBefore" pointcut="execution(* com.ithspringlearning.aspectj.UserServiceImpl.*(..))"/> <!--被下面註解替換 -->
//切入點當前有效
    @Before("execution(* com.springlearning.aspectj.UserServiceImpl.*(..))")
    public void myBefore(JoinPoint joinPoint){
        System.out.println("前置通知:" + joinPoint.getSignature().getName());
    }
  • 替換 公共切入點
<aop:pointcut id="myPointcut" expression="execution(* com.springlearning.aspectj.UserServiceImpl.*(..))"/>
 <!--被下面註解替換 -->
//聲明公共切入點
    @Pointcut("execution(* com.springlearning.aspectj.UserServiceImpl.*(..))")
    private void myPointCut(){}
  • 替換後置
<aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="ret" />
@AfterReturning(value = "myPointCut()",returning = "ret")
    public void myAfterReturning(JoinPoint joinPoint,Object ret){
        System.out.println("後置通知 : " + joinPoint.getSignature().getName() + " , -->" + ret);
    }

引用

  • 環繞替換
<aop:around method="myAround" pointcut-ref="myPointCut"/>
@Around(value = "myPointCut()")
    public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.println("前");
        //手動執行目標方法
        Object obj = joinPoint.proceed();
        System.out.println("後");
        return obj;
    }
  • 替換拋出異常
<aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="throwable"/>
@AfterThrowing(value = "myPointCut()" ,throwing = "throwable")
    public void myAfterThrowing(JoinPoint joinPoint,Throwable throwable){
        System.out.println("拋出異常通知:" + throwable.getMessage());
    }

2.6.3 切面類

/**
 * 切面類,含有多個通知
 */
@Component
@Aspect
public class MyAspect {

    //聲明公共切入點
    @Pointcut("execution(* com.springlearning.aspectj.UserServiceImpl.*(..))")
    private void myPointCut(){}
//    @AfterReturning(value = "myPointCut()",returning = "ret")
    public void myAfterReturning(JoinPoint joinPoint,Object ret){
        System.out.println("後置通知 : " + joinPoint.getSignature().getName() + " , -->" + ret);
    }
    //切入點當前有效
 //   @Before("execution(* com.springlearning.aspectj.UserServiceImpl.*(..))")
    public void myBefore(JoinPoint joinPoint){
        System.out.println("前置通知:" + joinPoint.getSignature().getName());
    }

 //   @Around(value = "myPointCut()")
    public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.println("前");
        //手動執行目標方法
        Object obj = joinPoint.proceed();
        System.out.println("後");
        return obj;
    }
 //   @AfterThrowing(value = "myPointCut()" ,throwing = "throwable")
    public void myAfterThrowing(JoinPoint joinPoint,Throwable throwable){
        System.out.println("拋出異常通知:" + throwable.getMessage());
    }
    @After(value = "myPointCut()")
    public void myAfter(JoinPoint joinPoint){
        System.out.println("最終通知");
    }
}

2.6.4 spring 配置

<!-- 1. 掃描 註解類 -->
    <context:component-scan base-package="com.springlearning.aspectj"></context:component-scan>
    
    <!-- 2.肯定 aop註解生效 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

2.6.5 aop 註解總結

  • @Aspect 聲明切面,修飾切面類,從而得到 通知。
  • 通知
    • @Before 前置
    • @AfterReturning 後置
    • @Around 環繞
    • @AfterThrowing 拋出異常
    • @After 最終
  • 切入點
    • @PointCut ,修飾方法 private void xxx(){} 以後經過「方法名」得到切入點引用

3. JdbcTemplate

  • spring 提供用於操做JDBC工具類,相似:DBUtils。
  • 依賴 鏈接池DataSource (數據源)

3.1 環境搭建

3.1.1 建立表

create table t_user(
  id int primary key ,
  username varchar(50),
  password varchar(32)
);

3.1.2 導入 jar 包

jar包

3.1.3 javaBean

public class User {

    private Integer id;
    private String username;
    private String password;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

3.2 使用api

@Test
    public void demo(){
        //1 建立數據源(鏈接池) dbcp
        BasicDataSource dataSource = new BasicDataSource();
        // * 基本4項
        dataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
        dataSource.setUrl("jdbc:oracle:thin:@localhost:1530/orcl");
        dataSource.setUsername("sys as sysdba");
        dataSource.setPassword("sys");
        //2  建立模板
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        //3 經過api操做
        jdbcTemplate.update("insert into t_user(id,username,password) values(?,?,?)","6", "tom","998");
    }

3.3 配置DBCP

<!-- 建立數據源 -->
    <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"></property>
        <property name="url" value="jdbc:oracle:thin:@localhost:1530/orcl"></property>
        <property name="username" value="sys as sysdba"></property>
        <property name="password" value="sys"></property>
    </bean>
    <!-- 建立模板 ,須要注入數據源-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 配置dao -->
    <bean id="userDao" class="com.springlearning.jdbctemplate.UserDao">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>

3.4 配置C3P0

<!-- 建立C3P0數據源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="oracle.jdbc.driver.OracleDriver"></property>
        <property name="jdbcUrl" value="jdbc:oracle:thin:@localhost:1530/orcl"></property>
        <property name="user" value="sys as sysdba"></property>
        <property name="password" value="sys"></property>
    </bean>
  • 這兒裏注意c3p0的jar包版本,須要mchange-commons-java-0.2.3.包,這是c3p0數據庫鏈接池的輔助包,沒有這個包系統啓動的時候會報classnotfoundexception,這是c3p0-0.9.2版本後分離出來的包,0.9.1的時候仍是一個包就搞定的

3.5 使用JdbcDaoSupport

3.5.1 dao層

package com.springlearning.jdbctemplate;

import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

import java.util.List;

/**
 * @ClassName:UserDao
 * @author: donkey-boy
 * @date:2019/7/19 10:52
 */
public class UserDao extends JdbcDaoSupport {

    /**
      * @Author: donkey-boy
     * @Description: 更新操做
     * @Param: user
     * @Return:  void
     * @Date: 2019/7/19 15:04
     */
    public void update(User user){
        String sql = "UPDATE t_user SET username=?,password=? WHERE id=?";
        Object[] args = {user.getUsername(),user.getPassword(),user.getId()};
        this.getJdbcTemplate().update(sql,args);
    }
    /**
      * @Author: donkey-boy
     * @Description: 查詢所有
     * @Param: []
     * @Return: java.util.List<com.springlearning.jdbctemplate.User>
     * @Date: 2019/7/19 15:06
     */
    public List<User> findAll(){
        List<User> userList = this.getJdbcTemplate().query("select * from t_user", BeanPropertyRowMapper.newInstance(User.class));
        return userList;
    }

    /**
      * @Author: donkey-boy
     * @Description: 獲取單個用戶
     * @Param: [id]
     * @Return: com.springlearning.jdbctemplate.User
     * @Date: 2019/7/19 15:06
     */
    public User getUser(int id){
        User user = this.getJdbcTemplate().queryForObject("select * from t_user where id=?", BeanPropertyRowMapper.newInstance(User.class), id);
        return user;
    }
}

3.5.2 spring 配置文件

<!--  配置dao
        * dao 繼承 JdbcDaoSupport,以後只須要注入數據源,底層將自動建立模板
    -->
    <!-- 配置dao -->
    <bean id="userDao" class="com.springlearning.jdbctemplate.UserDao">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

3.5.3 源碼分析

源碼

3.6 配置 properties

3.6.1 properties 文件

jdbc.driverClass=oracle.jdbc.driver.OracleDriver
jdbc.jdbcUrl=jdbc:oracle:thin:@localhost:1530/orcl
jdbc.user=sys as sysdba
jdbc.password=sys

3.6.2 spring 配置

<!-- 加載配置文件 
        "classpath:"前綴表示 src下
        在配置文件以後經過  ${key} 得到內容
    -->
    <context:property-placeholder location="classpath:com/springlearning/jdbctemplate/jdbcInfo.properties"></context:property-placeholder>
    <!-- 建立C3P0數據源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driverClass}"></property>
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
        <property name="user" value="${jdbc.user}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>

筆記源自傳智播客Spring教學設計模式

相關文章
相關標籤/搜索