1. 程式人生 > >Spring --12.Spring中AOP程式設計(XML方式)

Spring --12.Spring中AOP程式設計(XML方式)

1、AOP入門案例

1.1、建立工程並引入依賴

工程為com.day03

依賴如下:

<!--依賴-->
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
        </dependency>
        <!--log4j-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
        </dependency>
    </dependencies>

 

1.2、引入applicationContext.xml和log4j.properties

applicationContext.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: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">
    
    <!--配置相關類到applicationContext.xml-->
    <bean id="customerDao" class="com.day03.dao.Impl.CustomerDaoImpl"></bean>
    <!--配置切面類到applicationContext.xml-->
    <bean id="aspectXml" class="com.day03.aspect.AspectXml"></bean>

    <!--AOP配置-->
    <aop:config>
        <!--配置切入點-->
        <aop:pointcut id="pointCut1" expression="execution(* com.day03.dao.Impl.CustomerDaoImpl.save(..))" />

        <!--配置切面 告訴spring框架呼叫切面類中哪個方法來增強-->
        <aop:aspect ref="aspectXml">
            <aop:before method="writeLog" pointcut-ref="pointCut1" />
        </aop:aspect>
    </aop:config>
</beans>

log4j.properties

### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=D:/mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### set log levels - for more verbose logging change 'info' to 'debug' ###

log4j.rootLogger=debug, stdout, file

1.3、編寫CustomerDao.java介面和CustomerDaoImpl.java實現類

CustomerDao.java介面

package com.day03.dao;

public interface CustomerDao {

	public abstract void save();
	public abstract void delete();
	public abstract void update();
	public abstract void select();
}

CustomerDaoImpl.java

package com.day03.dao.Impl;
import com.day03.dao.CustomerDao;

public class CustomerDaoImpl implements CustomerDao {

	@Override
	public void save() {
		System.out.println("持久層:客戶儲存。。。。。。。");
	}

	@Override
	public void delete() {
		System.out.println("持久層、刪除使用者。。。。。");
	}

	@Override
	public void update() {
		System.out.println("持久層、更新使用者。。。。。。。。。");
	}

	@Override
	public void select() {
		System.out.println("持久層、查詢使用者..................");
	}

}

1.4、配置相關類到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">

    <!--配置相關類到applicationContext.xml-->
    <bean id="customerDao" class="com.day03.dao.Impl.CustomerDaoImpl"></bean>
</beans>

 

1.5、編寫切面類AsptectXml.java並配置切面類到Spring中

AsptectXml.java切面類

package com.day03.aspect;

import org.aspectj.lang.JoinPoint;

/**
 * @ Author     :ShaoWei Sun.
 * @ Date       :Created in 20:26 2018/11/12
 */
public class AspectXml {

    public void writeLog() {
        System.out.println("記錄日誌。。。。。。");
    }
}

applicationContext.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: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">

    <!--配置相關類到applicationContext.xml-->
    <bean id="customerDao" class="com.day03.dao.Impl.CustomerDaoImpl"></bean>
    <!--配置切面類到applicationContext.xml-->
    <bean id="aspectXml" class="com.day03.aspect.AspectXml"></bean>
</beans>

1.6、配置AOP

applicationContext.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: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">

    <!--配置相關類到applicationContext.xml-->
    <bean id="customerDao" class="com.day03.dao.Impl.CustomerDaoImpl"></bean>
    <!--配置切面類到applicationContext.xml-->
    <bean id="aspectXml" class="com.day03.aspect.AspectXml"></bean>

    <!--AOP配置-->
    <aop:config>
        <!--配置切入點-->
        <aop:pointcut id="pointCut1" expression="execution(* com.day03.dao.Impl.CustomerDaoImpl.save(..))" />

        <!--配置切面 告訴spring框架呼叫切面類中哪個方法來增強-->
        <aop:aspect ref="aspectXml">
            <aop:before method="writeLog" pointcut-ref="pointCut1" />
        </aop:aspect>
    </aop:config>
</beans>

1.7、測試類

TestAOP.java

package com.day03.test;

import com.day03.dao.CustomerDao;
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;

/**
 * @ Author     :ShaoWei Sun.
 * @ Date       :Created in 20:54 2018/11/12
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestAOP {

    @Autowired
    private CustomerDao customerDao;

    @Test
    public void test1(){
        customerDao.save();
    }
}

 

2、Spring中AOP通知型別

前置通知、後置通知、環繞通知、異常通知、最終通知

2.1、前置通知

應用: 許可權控制 (許可權不足,丟擲異常)、 記錄方法呼叫資訊日誌

2.2、後置通知

特點:在目標方法執行後,返回值後執行增強程式碼邏輯。

應用場景:與業務相關的,如ATM取款機取款後,自動下發簡訊。

2.3、環繞通知

特點:目標執行前後,都進行增強(控制目標方法執行)

應用場景:日誌、快取、許可權、效能監控、事務管理

增強程式碼的方法要求:

接受的引數:ProceedingJoinPoint(可執行的連線點)

返回值:Object返回值

丟擲Throwable異常。

說明:

ProceedingJoinPoint:表示正在執行的連線點,也就是目標方法

joinpoint.proceed表示呼叫目標方法

2.4、異常通知

作用:目的碼出現異常,通知執行。記錄異常日誌、通知管理員(簡訊、郵件)

應用場景:處理異常(一般不可預知),記錄日誌

2.5、最終通知

作用:不管目標方法是否發生異常,最終通知都會執行(類似於finally程式碼功能)

應用場景:釋放資源 (關閉檔案、 關閉資料庫連線、 網路連線、 釋放記憶體物件 )

案例:

CustomerDao.java介面

package com.day03.dao;

public interface CustomerDao {

	public abstract void save();
	public abstract Integer delete();
	public abstract Integer update(int a , int b);
	public abstract void list();
	public abstract void select();
}

CustomerDaoImpl.java實現類

package com.day03.dao.Impl;
import com.day03.dao.CustomerDao;

public class CustomerDaoImpl implements CustomerDao {


	@Override
	public void save() {
		System.out.println("持久層:客戶儲存。。。。。。。");
	}

	@Override
	public Integer delete() {
		System.out.println("持久層、刪除使用者。。。。。");
		return 100;
	}

	@Override
	public Integer update(int a, int b) {
		System.out.println("持久層、更新使用者。。。。。。。。。");
		Integer c = a + b;
		return c;
	}

	@Override
	public void list() {
		System.out.println("這是一個異常。。。。。");
		//int i = 10/0;
	}

	@Override
	public void select() {
		int i =10/0;
		System.out.println("持久層、查詢使用者..................");
	}

}

切面類:AspectXml.java

package com.day03.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

/**
 * @ Author     :ShaoWei Sun.
 * @ Date       :Created in 20:26 2018/11/12
 */
public class AspectXml {

    //入門案例
    public void writeLog() {
        System.out.println("記錄日誌。。。。。。");
    }


    //前置通知 許可權控制 、許可權不足、丟擲異常、
    public void before(JoinPoint jp) {
        String username = "rose";
        if (!"admin".equals(username)) {
            throw new RuntimeException("你沒有對"+jp.getTarget().getClass().getName()+"類中的"+jp.getSignature().getName()+"沒有訪問許可權");
        }
    }


    //後置通知方法 應用:ATM取款取款後、自動下發簡訊、引數result:被增強那個方法返回值
    public void afterReturning(JoinPoint jp, Object result){
        System.out.println("你取款"+result+"元");
    }


    //環繞通知方法 、應用、事務處理 proceedingJoinPoint 正在執行的連線點
    //joinPonint表示呼叫目標方法
    public Object around(ProceedingJoinPoint pjp){
        Object proceed = null;
        System.out.println("開啟事務");
        //獲取目標方法的引數
        Object[] args = pjp.getArgs();
        try {
             proceed = pjp.proceed(args);
            System.out.println("事務提交");
//            列印目標方法裡引數的結果值
            System.out.println(proceed);
        } catch (Throwable throwable) {
            System.out.println("事務回滾");
        }
        return proceed;
    }


    //異常丟擲通知
    //作用:目的碼出現異常、通知執行、記錄日誌、通知管理員
    public void afterThrowing(JoinPoint jp,Throwable ex){
        System.out.println("注意、在"+jp.getTarget().getClass().getName()+"類中"+jp.getSignature().getName()+"方法中發生異常"+ex.getMessage());
    }


    //最終通知:不管目標方法是否發生異常、最終通知都會執行、類似於finally程式碼功能、
    //應用:釋放資源、關閉檔案、關閉資料庫連線、網路連線、釋放記憶體物件
    public void after(JoinPoint jp){
        System.out.println("開始釋放資源、連線類方法為:"+jp.getTarget().getClass().getName()+"方法:"+jp.getSignature().getName() );
    }

}

applicationContext.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: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">

    <!--配置相關類到applicationContext.xml-->
    <bean id="customerDao" class="com.day03.dao.Impl.CustomerDaoImpl"></bean>
    <!--配置切面類到applicationContext.xml-->
    <bean id="aspectXml" class="com.day03.aspect.AspectXml"></bean>

    <!--AOP配置-->
    <aop:config>
        <!--配置切入點-->
        <aop:pointcut id="pointCut1" expression="execution(* com.day03.dao.Impl.CustomerDaoImpl.save(..))" />
        <aop:pointcut id="pointCut2" expression="execution(* com.day03.dao.Impl.CustomerDaoImpl.delete(..))"/>
        <aop:pointcut id="pointCut3" expression="execution(* com.day03.dao.Impl.CustomerDaoImpl.update(..))"/>
        <aop:pointcut id="pointCut4" expression="execution(* com.day03.dao.Impl.CustomerDaoImpl.list(..))"/>
        <aop:pointcut id="pointCut5" expression="execution(* com.day03.dao.Impl.CustomerDaoImpl.select(..))"/>
        <!--配置切面 告訴spring框架呼叫切面類中哪個方法來增強-->
        <aop:aspect ref="aspectXml">
            <aop:before method="before" pointcut-ref="pointCut1" />
            <aop:after-returning method="afterReturning" pointcut-ref="pointCut2" returning="result" />
            <aop:around method="around" pointcut-ref="pointCut3"/>
            <aop:after-throwing method="afterThrowing" pointcut-ref="pointCut4" throwing="ex"/>
            <aop:after method="after" pointcut-ref="pointCut5"/>
        </aop:aspect>
    </aop:config>
</beans>

TestAOP.java測試類

package com.day03.test;

import com.day03.dao.CustomerDao;
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;

/**
 * @ Author     :ShaoWei Sun.
 * @ Date       :Created in 20:54 2018/11/12
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestAOP {

    @Autowired
    private CustomerDao customerDao;

    //前置
    @Test
    public void test1(){
        customerDao.save();
    }
    //後置
    @Test
    public void test2(){
        customerDao.delete();
    }

    //環繞
    @Test
    public void test3(){
        customerDao.update(5,8);
    }

    //異常
    @Test
    public void test4(){
        customerDao.list();
    }
    //最終、不管目標方法是否發生異常、最終通知都執行
    @Test
    public void test5(){
        customerDao.select();
    }
}