實例:Spring AOP實現異常處理和記錄程序執行時間(Java動態代理、CGLIB代理、自動代理、ProxyFactoryBean代理)

該實例用於在一個系統的所有方法執行過程中出現異常時,把異常信息都記錄下來,另外記錄每個方法的執行時間。用兩個業務邏輯說明上述功能,並且一個使用Java的動態代理,一個用CGLIB代理。

  • (1)定義負責異常處理的Advice爲ExceptionHandler.java
  • (2)定義負責記錄時間的Advice爲TimeHandler.java
  • (3)編寫實現業務邏輯的接口的類LogicInterface.java
  • (4)LogicInterface類的實現Logic1.java,其將使用Java的動態代理
  • (5)編寫另一個沒有接口的業務邏輯Logic2.java,其將使用CGLIB代理
  • (6)使用自動代理定義配置文件config.xml
  • (7)測試自動代理 TestAop.java
  • (8)使用ProxyFactoryBean代理定義配置文件config.xml
  • (9)測試 TestAop.java

(1)首先編寫異常處理類、執行時間類和業務邏輯類

import java.lang.reflect.Method;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.springframework.aop.ThrowsAdvice;
//定義負責異常處理的Advice爲ExceptionHandler.java
public class ExceptionHandler implements ThrowsAdvice {//Throw通知,遇到異常時輸出
	private Logger logger = Logger.getLogger(this.getClass().getName());
	public void afterThrowing(Method method, Object[] args, Object target, Throwable subclass) throws Throwable{
		logger.log(Level.INFO, args[0] + " 執行 " + method.getName() + " 時有異常拋出..." + subclass);
	}
}
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
//定義負責記錄時間的Advice爲TimeHandler.java
public class TimeHandler implements MethodInterceptor {//Interceptor Around通知,前後都輸出
	private Logger logger = Logger.getLogger(this.getClass().getName());
	@Override
	public Object invoke(MethodInvocation methodInvocation) throws Throwable {
		long procTime = System.currentTimeMillis();
		logger.log(Level.INFO, methodInvocation.getArguments()[0] + " 開 始 執 行 " + methodInvocation.getMethod() + " 方法");
		try {
			Object result = methodInvocation.proceed();
			return result;
		} finally {
			// 計算執行時間
			procTime = System.currentTimeMillis() - procTime;
			logger.log(Level.INFO, "執行 " + methodInvocation.getMethod().getName() + " 方法共用了 " + procTime + " 毫秒");
		}
	}
}
//編寫實現業務邏輯的接口的類LogicInterface.java
//該接口主要用來實現使用Spring AOP的動態代理機制
public interface LogicInterface {
	public void doInsert(String name);
	public void doUpdate(String name);
	public void doDelete(String name);
}
import com.gc.impl.LogicInterface;
//LogicInterface類的實現Logic1.java,其將使用Java的動態代理
public class Logic1 implements LogicInterface {

	@Override
	public void doInsert(String name) {
		System.out.println("執行具體負責新增的業務邏輯...");
		for(int i = 0;i < 100000000; i++) {
			//模擬執行時間
		}
	}

	@Override
	public void doUpdate(String name) {
		System.out.println("執行具體負責修改的業務邏輯...");
		for(int i = 0;i < 200000000; i++) {
			//模擬執行時間
		}
	}
	
	@Override
	public void doDelete(String name) {
		System.out.println("執行具體負責刪除的業務邏輯...");
		for(int i = 0;i < 300000000; i++) {
			i = i / 0;//模擬異常發生
		}
	}
}
//編寫另一個沒有接口的業務邏輯Logic2.java,其將使用CGLIB代理
public class Logic2 {
	public void doInsert(String name) {
		System.out.println("執行具體負責新增的業務邏輯...");
		for(int i = 0;i < 100000000; i++) {
			//模擬執行時間
		}
	}

	public void doUpdate(String name) {
		System.out.println("執行具體負責修改的業務邏輯...");
		for(int i = 0;i < 200000000; i++) {
			//模擬執行時間
		}
	}

	public void doDelete(String name) {
		System.out.println("執行具體負責刪除的業務邏輯...");
		for(int i = 0;i < 300000000; i++) {
			i = i / 0;//模擬異常發生
		}
	}
}

(2)自動代理:這裏主要查看使用接口和不使用接口的區別

<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
	<bean id="logic1" class="com.gc.action.Logic1"/>
	<bean id="logic2" class="com.gc.action.Logic2"/>
	<!--設置爲自動代理-->
	<bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
	<!--負責記錄有異常發生時的信息-->
	<bean id="exceptionHandler" class="com.gc.action.ExceptionHandler"/>
	<bean id="exceptionHandlerAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
      	<property name="advice">
            <ref bean="exceptionHandler"/>
        </property>
        <!--對指定類的任何方法有效-->
        <property name="patterns">
            <value>.*.*</value>
        </property>
	</bean>

	<!--負責記錄方法的記錄信息-->
	<bean id="timeHandler" class="com.gc.action.TimeHandler"/>
	<bean id="timeHandlerAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
      	<property name="advice">
            <ref bean="timeHandler"/>
        </property>
        <!--對指定類的任何方法有效-->
        <property name="patterns">
            <value>.*.*</value>
        </property>
	</bean>
</beans>

java動態代理,使用接口測試logic1:

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

import com.gc.action.Logic2;
import com.gc.impl.LogicInterface;
//java動態代理測試logic1
public class TestAop {
	public static void main(String[] args) {
		ApplicationContext actx = new FileSystemXmlApplicationContext("exception_config.xml");
		LogicInterface logic = (LogicInterface)actx.getBean("logic1");
		try {
			logic.doInsert("張三");
			logic.doUpdate("李四");
			logic.doDelete("王五");
		} catch (Exception e) {
		}
	}
}

結果
[ INFO ] 2020-04-21 11:16:43 [main] com.gc.action.TimeHandler  - 張三 開 始 執 行 public abstract void com.gc.impl.LogicInterface.doInsert(java.lang.String) 方法
執行具體負責新增的業務邏輯...
[ INFO ] 2020-04-21 11:16:43 [main] com.gc.action.TimeHandler  - 執行 doInsert 方法共用了 20 毫秒
[ INFO ] 2020-04-21 11:16:43 [main] com.gc.action.TimeHandler  - 李四 開 始 執 行 public abstract void com.gc.impl.LogicInterface.doUpdate(java.lang.String) 方法
執行具體負責修改的業務邏輯...
[ INFO ] 2020-04-21 11:16:43 [main] com.gc.action.TimeHandler  - 執行 doUpdate 方法共用了 2 毫秒
[ INFO ] 2020-04-21 11:16:43 [main] com.gc.action.TimeHandler  - 王五 開 始 執 行 public abstract void com.gc.impl.LogicInterface.doDelete(java.lang.String) 方法
執行具體負責刪除的業務邏輯...
[ INFO ] 2020-04-21 11:16:43 [main] com.gc.action.TimeHandler  - 執行 doDelete 方法共用了 1 毫秒
[ INFO ] 2020-04-21 11:16:43 [main] com.gc.action.ExceptionHandler  - 王五 執行 doDelete 時有異常拋出...java.lang.ArithmeticException: / by zero

CGLIB代理,不使用接口測試logic2:

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

import com.gc.action.Logic2;
import com.gc.impl.LogicInterface;
//CGLIB代理測試logic2
public class TestAop {
	public static void main(String[] args) {
		ApplicationContext actx = new FileSystemXmlApplicationContext("exception_config.xml");
		Logic2 logic = (Logic2)actx.getBean("logic2");
		try {
			logic.doInsert("張三");
			logic.doUpdate("李四");
			logic.doDelete("王五");
		} catch (Exception e) {
		}
	}
}

結果
[ INFO ] 2020-04-21 11:16:43 [main] com.gc.action.TimeHandler  - 張三 開 始 執 行 public abstract void com.gc.impl.LogicInterface.doInsert(java.lang.String) 方法
執行具體負責新增的業務邏輯...
[ INFO ] 2020-04-21 11:16:43 [main] com.gc.action.TimeHandler  - 執行 doInsert 方法共用了 20 毫秒
[ INFO ] 2020-04-21 11:16:43 [main] com.gc.action.TimeHandler  - 李四 開 始 執 行 public abstract void com.gc.impl.LogicInterface.doUpdate(java.lang.String) 方法
執行具體負責修改的業務邏輯...
[ INFO ] 2020-04-21 11:16:43 [main] com.gc.action.TimeHandler  - 執行 doUpdate 方法共用了 2 毫秒
[ INFO ] 2020-04-21 11:16:43 [main] com.gc.action.TimeHandler  - 王五 開 始 執 行 public abstract void com.gc.impl.LogicInterface.doDelete(java.lang.String) 方法
執行具體負責刪除的業務邏輯...
[ INFO ] 2020-04-21 11:16:43 [main] com.gc.action.TimeHandler  - 執行 doDelete 方法共用了 1 毫秒
[ INFO ] 2020-04-21 11:16:43 [main] com.gc.action.ExceptionHandler  - 王五 執行 doDelete 時有異常拋出...java.lang.ArithmeticException: / by zero

(3)使用ProxyFactoryBean代理定義配置文件config.xml

<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
	<bean id="logic1" class="com.gc.action.Logic1"/>
	<bean id="logic2" class="com.gc.action.Logic2"/>
	<!--設置爲自動代理-->
	
	<!--負責記錄有異常發生時的信息-->
	<bean id="exceptionHandler" class="com.gc.action.ExceptionHandler"/>
	<bean id="exceptionHandlerAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
      	<property name="advice">
            <ref bean="exceptionHandler"/>
        </property>
        <!--對指定類的任何方法有效-->
        <property name="patterns">
            <value>.*.*</value>
        </property>
	</bean>

	<!--負責記錄方法的記錄信息-->
	<bean id="timeHandler" class="com.gc.action.TimeHandler"/>
	<bean id="timeHandlerAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
      	<property name="advice">
            <ref bean="timeHandler"/>
        </property>
        <!--對指定類的任何方法有效-->
        <property name="patterns">
            <value>.*.*</value>
        </property>
	</bean>

    <!--logic1只輸出執行時間timeHandler-->
	<bean id="logic1Proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="proxyInterfaces">
			<value>com.gc.impl.LogicInterface</value>
		</property>
		<property name="target">
			<ref bean="logic1"/>
		</property>
		<!--指定代理的類-->
		<property name="interceptorNames">
			<list>
				<value>timeHandlerAdvisor</value>
			</list>
		</property>
	</bean>

    <!--logic2只輸出異常信息exceptionHandler-->
	<bean id="logic2Proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="proxyTargetClass">
			<value>true</value>
		</property>
		<property name="target">
			<ref bean="logic2"/>
		</property>
		<!--指定代理的類-->
		<property name="interceptorNames">
			<list>
				<value>exceptionHandler</value>
			</list>
		</property>
	</bean>
</beans>

logic1只執行時間日誌輸出,不執行異常日誌輸出:

​import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

import com.gc.action.Logic2;
import com.gc.impl.LogicInterface;
//java動態代理測試logic1
public class TestAop {
	public static void main(String[] args) {
		ApplicationContext actx = new FileSystemXmlApplicationContext("exception_config.xml");
		LogicInterface logic = (LogicInterface)actx.getBean("logic1Proxy");
		try {
			logic.doInsert("張三");
			logic.doUpdate("李四");
			logic.doDelete("王五");
		} catch (Exception e) {
		}
	}
}

結果
[ INFO ] 2020-04-21 11:38:23 [main] com.gc.action.TimeHandler  - 張三 開 始 執 行 public abstract void com.gc.impl.LogicInterface.doInsert(java.lang.String) 方法
執行具體負責新增的業務邏輯...
[ INFO ] 2020-04-21 11:38:23 [main] com.gc.action.TimeHandler  - 執行 doInsert 方法共用了 22 毫秒
[ INFO ] 2020-04-21 11:38:23 [main] com.gc.action.TimeHandler  - 李四 開 始 執 行 public abstract void com.gc.impl.LogicInterface.doUpdate(java.lang.String) 方法
執行具體負責修改的業務邏輯...
[ INFO ] 2020-04-21 11:38:23 [main] com.gc.action.TimeHandler  - 執行 doUpdate 方法共用了 1 毫秒
[ INFO ] 2020-04-21 11:38:23 [main] com.gc.action.TimeHandler  - 王五 開 始 執 行 public abstract void com.gc.impl.LogicInterface.doDelete(java.lang.String) 方法
執行具體負責刪除的業務邏輯...
[ INFO ] 2020-04-21 11:38:23 [main] com.gc.action.TimeHandler  - 執行 doDelete 方法共用了 0 毫秒

logic2只執行異常日誌輸出,不執行時間日誌輸出:

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

import com.gc.action.Logic2;
import com.gc.impl.LogicInterface;
//CGLIB代理測試logic2
public class TestAop {
	public static void main(String[] args) {
		ApplicationContext actx = new FileSystemXmlApplicationContext("exception_config.xml");
		Logic2 logic = (Logic2)actx.getBean("logic2Proxy");
		try {
			logic.doInsert("張三");
			logic.doUpdate("李四");
			logic.doDelete("王五");
		} catch (Exception e) {
		}
	}
}

結果
執行具體負責新增的業務邏輯...
執行具體負責修改的業務邏輯...
執行具體負責刪除的業務邏輯...
[ INFO ] 2020-04-21 11:45:10 [main] com.gc.action.ExceptionHandler  - 王五 執行 doDelete 時有異常拋出...java.lang.ArithmeticException: / by zero

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章