Spring系列教程六:AOP詳細講解

AOP 概述

什麼是 AOP

AOP:全稱是 Aspect Oriented Programming 即:面向切面編程。java

AOP技術是對OOP技術的一種延伸,AOP是面向縱向,OOP是面向橫向。簡單的說它就是把咱們程序重複的代碼抽取出來,在須要執行的時候,使用動態代理的技術,在不修改源碼的
基礎上,對咱們的已有方法進行加強。mysql

AOP 的做用以及優點

做用:在程序運行期間,不修改源碼對已有方法前面和後面進行加強。
優點:減小重複代碼、提升開發效率、維護方便spring

AOP實現方式

使用動態代理技術sql

基於xml方式的aop配置

實現步驟以下express

導入spring-aop jar包

<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>commons-dbutils</groupId>
            <artifactId>commons-dbutils</artifactId>
            <version>1.6</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        下面幾個是必需要導的包
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.2</version>
        </dependency>
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>

須要加強方法的StudentDao類,和寫加強方法的Userlogger類

package com.ithema.jdbc.dao;

public class StudentDao {
    //在執行add方法以前執行日誌

    public int add(int a,int b){
        System.out.println("執行了add方法");
        return a+b;
    }
    public  int jian(int a,int b){
        System.out.println("執行了減法");
        return a-b;
    }
   /* public void testexe(){
        int i=10/0;
    }*/
}
package com.ithema.jdbc.aop;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

import java.util.Arrays;

/**
 * 切面:
 * 前置加強、後置加強、異常加強、最終加強、環繞加強
 *
 * Spring aop徹底是用動態代理實現的
 * 可是動態代理又有兩種,jdkk代理,cglib代理(更強大一些)
 * spirng aop:默認使用jdk代理,可是你的目標類沒接口,會自動切換到cglib代理
 */
public class UserLogger {

    //在目標方法調用以前執行該方法
    Logger logger=Logger.getLogger(UserLogger.class);
    public void before(JoinPoint jp){
        logger.info("前置加強,目標類名"+jp.getTarget()+"裏面的"+jp.getSignature().getName()+
                "參數爲:"+ Arrays.toString(jp.getArgs()));
    }
    //在目標方法調用以後執行該方法
    //當方法拋出異常就不會執行了,全部該方法不適合作日誌收集,由於發生了異常不執行該方法沒法將日誌保存下來
    //全部後置加強用的不多
    public void after(JoinPoint jp,Object result){
        logger.info("後置加強,執行完類"+jp.getTarget()+"裏面的"+jp.getSignature().getName()+
                "方法,結果爲:"+ result);
    }
    //在方法拋出異常後就會加強、沒有異常就不會執行、若是用戶try-catch,也不會加強
    //執行錯誤的話,很是適合該加強(異常加強)
    //Java異常體系,根類是Throwable
    public void afterThorwing(JoinPoint jp,Throwable e){
        logger.info("異常加強,執行類"+jp.getTarget()+"裏面的"+jp.getSignature().getName()+
                "方法拋出異常:"+e.getMessage());
    }
    //最終加強:不管是否有異常,都會執行,相似與finally,能夠或者是認爲是後置加強的升級版
    public void finalafter(JoinPoint jp){
        logger.info("最終加強:執行完類"+jp.getTarget()+"裏面的"+jp.getSignature().getName());
    }
    //環繞加強,集合了前置添加後置,而且更增強大、當執行方法發生異常後面的就不執行了
    //一、能夠修改方法的參數 二、也能夠修改方法的返回值( return result)
    public Object around(ProceedingJoinPoint jp)throws Throwable{
        Object [] args=jp.getArgs();//獲取方法參數
        //能夠修改方法的參數
        //args = new Object[]{20,1};
        logger.info("環繞加強:方法爲:"+jp.getArgs());
        Object result=jp.proceed();//執行目標方法
        //也能夠修改方法的返回值
        //return 100;
        return result;
    }
}

配置aop約束到配置文件中,並實現ioc配置

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       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">
    <!--一個bean就是一個對象>
    <bean id="studentDao" class="com.ithema.jdbc.dao.StudentDao">
    </bean>
    <bean id="userLogger" class="com.ithema.jdbc.aop.UserLogger">
    </bean>

使用 aop:aspect 配置切面,使用 aop:pointcut  配置切入點表達式

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       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">

    <bean id="studentDao" class="com.ithema.jdbc.dao.StudentDao">
    </bean>
    <bean id="userLogger" class="com.ithema.jdbc.aop.UserLogger">
    </bean>
    <!--aop配置,實現dao裏面的方法先後加強-->
    <aop:config>
        <!--定義切入點-->
        <!--標準寫法格式:(返回值:全類名(包名.類名.方法名(參數類型列表))-->
        <aop:pointcut id="pointcut" expression="execution(* com.ithema.jdbc..*.*(..))"></aop:pointcut>
        <!--組織加強-->
        <!--切面ref:應用其餘bean對象-->
        <aop:aspect ref="userLogger">
            <aop:before method="before" pointcut-ref="pointcut"></aop:before>
            <aop:after-returning method="after" pointcut-ref="pointcut" returning="result"></aop:after-returning>
            <aop:after-throwing method="afterThorwing" pointcut-ref="pointcut" throwing="e"></aop:after-throwing>
            <aop:after method="finalafter" pointcut-ref="pointcut"></aop:after>
            <aop:around method="around" pointcut-ref="pointcut"></aop:around>
        </aop:aspect>
    </aop:config>
</beans>

基於註解方式的aop配置

導入spring-aop jar包

<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>commons-dbutils</groupId>
            <artifactId>commons-dbutils</artifactId>
            <version>1.6</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        下面幾個是必需要導的包
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.2</version>
        </dependency>
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>

配置aop約束到配置文件中,在配置文件中指定 spring 要掃描的包,開啓 spring 對註解 AOP 的支持

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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/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">
    <!--告訴Spring容器在建立的時候要掃描包,配置所須要的標籤不在bean約束中,而是
    在一個叫作context的空降名稱和約束中-->
    <context:component-scan base-package="com.bdqn"></context:component-scan>
   <!-- 開啓註解aop-->
   <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

使用註解配置加強方法

package com.bdqn.aop;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
@Aspect
public class UserLogger {

    //在目標方法調用以前執行該方法
    Logger logger=Logger.getLogger(UserLogger.class);
    //定義切點
    @Pointcut("execution(* com.bdqn.aop..*.*(..))")
    public void pointcut(){}
    @Before("pointcut()")
    public void before(JoinPoint jp){
        logger.info("前置加強,目標類名"+jp.getTarget()+"裏面的"+jp.getSignature().getName()+
                "參數爲:"+ Arrays.toString(jp.getArgs()));
    }
    //在目標方法調用以後執行該方法
    //當方法拋出異常就不會執行了,全部該方法不適合作日誌收集,由於發生了異常不執行該方法沒法將日誌保存下來
    //全部後置加強用的不多
    public void after(JoinPoint jp,Object result){
        logger.info("後置加強,執行完類"+jp.getTarget()+"裏面的"+jp.getSignature().getName()+
                "方法,結果爲:"+ result);
    }
    //在方法拋出異常後就會加強、沒有異常就不會執行、若是用戶try-catch,也不會加強
    //執行錯誤的話,很是適合該加強(異常加強)
    //Java異常體系,根類是Throwable
    @AfterThrowing(pointcut = "execution(* com.bdqn.aop..*.*(..))",throwing = "e")
    public void afterThorwing(JoinPoint jp,Throwable e){
        logger.info("異常加強,執行類"+jp.getTarget()+"裏面的"+jp.getSignature().getName()+
                "方法拋出異常:"+e.getMessage());
    }
    //最終加強:不管是否有異常,都會執行,相似與finally,能夠或者是認爲是後置加強的升級版
    @After("execution(* com.bdqn.aop..*.*(..))")
    public void finalafter(JoinPoint jp){
        logger.info("最終加強:執行完類"+jp.getTarget()+"裏面的"+jp.getSignature().getName());
    }
    //環繞加強,集合了前置添加後置,而且更增強大、當執行方法發生異常後面的就不執行了
    //一、能夠修改方法的參數 二、也能夠修改方法的返回值( return result)
    @Around("execution(* com.bdqn.aop..*.*(..))")
    public Object around(ProceedingJoinPoint jp)throws Throwable{
        Object [] args=jp.getArgs();//獲取方法參數
        //能夠修改方法的參數
        //args = new Object[]{20,1};
        logger.info("環繞加強:方法爲:"+jp.getArgs());
        Object result=jp.proceed();//執行目標方法
        //也能夠修改方法的返回值
        //return 100;
        return result;
    }
}

使用spring整合junit4的方式寫測試類

package com.bdqn.test;

import com.bdqn.dao.StudentDao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:ApplicationContext.xml")
public class Testaop {
    @Autowired
    private StudentDao studentDao;
    @Test
    public  void testaop(){
        studentDao.add();
        studentDao.jian(3,1);
        System.out.println("執行了減法,結果爲:");
    }
}
相關文章
相關標籤/搜索