1. 程式人生 > >spring(二)面向切面的AOP代理

spring(二)面向切面的AOP代理

面向切面程式設計,就是在不改變原始碼的基礎上,增加新的功能,對程式碼進行增強處理,代理模式。

關注兩件事:在什麼位置,執行什麼功能。由Spring AOP完成織入工作,日誌、異常處理、事務控制等。

增強處理主要有:

  • 前置增強  before  在切入點前邊執行
  • 後置增強  after-returning   在切入點後邊執行,如果有異常,就不執行
  • 最終增強 after      在切入點後邊執行,無論怎樣都會執行,
  • 環繞增強 round    最強大的增強,封裝了目標物件,對其進行控制。
  • 異常丟擲增強  after-throwing  發生異常執行

首先新增需要的架包: aopalliance-1.0.jar;aspectjweaver-1.6.9.jar;spring-aop-3.2.13.RELEASE.jar

一、配置aop

1. 定義包含增強方法的javaBean

package aop;

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

public class AopLogger {
	private static final Logger log = Logger.getLogger(AopLogger.class);
	public void before(JoinPoint jp){
		log.info("=====>前置增強: 呼叫 "+jp.getTarget()+"的"+jp.getSignature().getName()+" 方法,方法入參:"+jp.getArgs().toString());
	}
	public void after(JoinPoint jp){
		log.info("=====>最終增強:呼叫 "+jp.getTarget()+"的"+jp.getSignature().getName()+" 方法");
	}
	public void afterReturning(JoinPoint jp,Object result){
		log.info("=====>後置增強帶返回值:呼叫 "+jp.getTarget()+"的"+jp.getSignature().getName()+" 方法,返回值:"+result);

	}
	public void afterException(JoinPoint jp,Exception e){
		log.info("=====>異常丟擲增強 "+ jp.getSignature().getName() + "丟擲異常"+e);
	}
	public void around(ProceedingJoinPoint jp) throws Throwable{
		//環繞增強得到了目標方法的控制權,可以獲取、修改目標方法的引數和返回值,封裝了目標物件,達到點對點的控制
		log.info("=====>環繞增強執行 ");            //相當於前置增強  
		try{
			Object result = jp.proceed();      
			log.info("\n=====> 環繞增強結果 :"+result); //相當於後置增強
		}catch(Throwable e){
			log.info("=====>環繞增強丟擲異常:"+e);    //相當於異常丟擲增強
			throw e;
		}finally{
			log.info("=====>環繞增強最後 ");   //相當於最終增強
		}
		
	}
}

spring 會自動注入JoinPoint 例項。

2..建立目標物件

package aop;

public class PointDemo {
	public String method1(String name){
		System.out.println("======> 執行 method1, name is : "+name);
		return name;
	}
}

method1作為切入點

3. 配置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:p="http://www.springframework.org/schema/p"
	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-3.2.xsd">
<!--注入例項  -->	
<bean id="pointDemo" class="aop.PointDemo"></bean>	
<bean id="aopLogger" class="aop.AopLogger"></bean>
<aop:config>
	<!--1. 定義一個切入點  -->
	<aop:pointcut expression="execution(public * method1(..))" id="pointCut"/>
	<!-- 2. 引用包含增強方法的Bean -->
	<aop:aspect ref="aopLogger">
		<aop:before method="before" pointcut-ref="pointCut"/><!--前置增強  -->
		<aop:after method="after" pointcut-ref="pointCut"/><!-- 最終曾強  不論是否發生異常都執行-->
		<aop:after-returning method="afterReturning" pointcut-ref="pointCut" returning="result"/><!-- 帶返回值的後置增強  有異常就不執行了 -->	
		<aop:after-throwing method="afterException" pointcut-ref="pointCut" throwing="e"/> <!-- 異常丟擲增強 -->
		<aop:around method="around" pointcut-ref="pointCut"/>
	</aop:aspect>
</aop:config>
</beans>		
	

有關aop的配置都放在<aop: config> 標籤內;配置切入點的標籤<aop: pointcut>的expression屬性有多種表示式:

  • public * method1(String name);    匹配所有返回值型別
  • public  void * (name);  匹配所有方法名
  • public void method1(..);  “..”匹配所有型別返回值;
  • * com.*.*(..);      匹配com包下所有的類的方法;
  • * com..*.*(..);    匹配com包及其子包所有類的方法

4. 測試

package aop;

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

public class Test {
	public static void main(String[] args) {
		ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext1.xml");
		PointDemo pd = (PointDemo)ac.getBean("pointDemo");
		pd.method1("張三");
	}
}

講環繞增強註釋掉的結果:

INFO - =====>前置增強: 呼叫 [email protected]的method1 方法,方法入參:[Ljava.lang.Object;@6e171cd7 ======> 執行 method1, name is : 張三 INFO - =====>最終增強:呼叫 [email protected]的method1 方法 INFO - =====>後置增強帶返回值:呼叫 [email protected]的method1 方法,返回值:張三

加上環繞增強的結果:

INFO - =====>前置增強: 呼叫 [email protected]的method1 方法,方法入參:[Ljava.lang.Object;@52e6fdee INFO - =====>環繞增強執行  INFO -  =====> 環繞增強結果 :張三 ======> 執行 method1, name is : 張三 INFO - =====>環繞增強最後  INFO - =====>後置增強帶返回值:呼叫 [email protected]的method1 方法,返回值:null INFO - =====>最終增強:呼叫 [email protected]的method1 方法 

可以看到,後置增強返回值為null,所以環繞增強最好別和其他的一起用。

5. 改造 目標類,使其發生異常,測試異常丟擲增強;

package aop;

public class PointDemo {
	public String method1(String name){
		System.out.println("======> 執行 method1, name is : "+name);
		String str="";
		System.out.println(str.equals(""));
		return name;
	}
}

 測試異常:

INFO - =====>前置增強: 呼叫 [email protected]的method1 方法,方法入參:[Ljava.lang.Object;@52e6fdee INFO - =====>環繞增強執行  ======> 執行 method1, name is : 張三INFO - =====>環繞增強丟擲異常:java.lang.NullPointerException INFO - =====>環繞增強最後 

INFO - =====>異常丟擲增強 method1丟擲異常java.lang.NullPointerException INFO - =====>最終增強:呼叫 [email protected]的method1 方法 Exception in thread "main" java.lang.NullPointerException     at aop.PointDemo.method1(PointDemo.java:7)     at aop.PointDemo$$FastClassBySpringCGLIB$$93985287.invoke(<generated>)

丟擲了異常。