1. 程式人生 > >Spring AOP三種方式定義增強

Spring AOP三種方式定義增強

一、通過實現(implements)的方式增強

BeforeLog:

package cn.log;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

public class BeforeLog implements MethodBeforeAdvice {
 /**
  * method 被呼叫的方法物件
  * args   被呼叫的方法的引數
  * target 被呼叫的方法的目標物件
  * */
	@Override
	public void before(Method method, Object[] args, Object target) throws Throwable {
		System.out.println("before---"+target.getClass().getName()+"的"+method.getName()+"方法被執行");
	}
}

AfterLog:

package cn.log;

import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;

public class AfterLog implements AfterReturningAdvice {
  /**
   * 目標方法執行後的通知
   * returnValue 返回值
   * method 被呼叫的方法物件
   * args 被呼叫的方法物件的引數
   * target 被呼叫的方法物件的目標物件
   * */
	@Override
	public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
		System.out.println("after---"+target.getClass().getName()+"的"+method.getName()+"被成功執行,返回值是"+returnValue);
	}

}
AroundLog:
package cn.log;

import java.lang.reflect.Method;
import java.util.Arrays;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class AroundLog implements MethodInterceptor {
	public Object invoke(MethodInvocation arg0) throws Throwable {
		Object target = arg0.getThis(); //獲取被代理的物件
		Method method = arg0.getMethod(); //獲取被代理的方法
		Object[] args = arg0.getArguments(); //獲取方法引數
		System.out.println("環繞---呼叫" + target + "的 " + method.getName() + "方法。方法入參:"+ Arrays.toString(args));
		try {	Object result = arg0.proceed();//呼叫目標方法,獲取返回值
		System.out.println("環繞---呼叫" + target + "的 " + method.getName() + "方法。"
				+ "方法返回值:" + result);
			return result;
		} catch (Throwable e) {
			System.out.println(method.getName() + " 方法發生異常" + e);        
			throw e;
		}
	}

}
ErrorLog:
package cn.log;

import org.aspectj.apache.bcel.classfile.Method;
import org.springframework.aop.ThrowsAdvice;
/**
 * 方法名必須是afterThrowing。方法的入參只有最後一個是必須的,前三個入參是可選的,但是前三個引數要麼都提供,要麼一個也不提供。正確的宣告方法舉例:
        afterThrowing(Method method, Object[] args, Object target, SQLException ex)
        afterThrowing(SQLException ex)
        afterThrowing(RuntimeException ex)
		錯誤的宣告方法舉例:
        catchThrowing(RuntimeException ex):方法名錯誤
        afterThrowing(Method method, RuntimeException ex):引數列表錯誤
 * */
public class ErrorLog implements ThrowsAdvice{
	
	public void afterThrowing(Method method, Object[] args, Object target,
			RuntimeException e) {
		System.out.println(method.getName() + " 方法發生異常:" + e);
	}
}
---------
UserService介面:
package cn.service;

public interface UserService {
  public void add();
  public String update(int i);
  public void delete();
  public void search();
}
UserServiceImpl:
package cn.service;

public class UserServiceImpl implements UserService {

	@Override
	public void add() {
		System.out.println("增加使用者");

	}

	@Override
	public String update(int i) {
		System.out.println("更新使用者");
		return "success";
	}

	@Override
	public void delete() {
		System.out.println("刪除使用者");

	}

	@Override
	public void search() {
		System.out.println("查詢使用者");

	}

}
beans.xml
<bean id="userService" class="cn.service.UserServiceImpl"/>
  <bean id="beforeLog" class="cn.log.BeforeLog"/>
  <bean id="afterLog" class="cn.log.AfterLog"/>
  <bean id="errorLog" class="cn.log.ErrorLog"/>
  <bean id="aroundLog" class="cn.log.AroundLog"/>
  
  <aop:config>
    <aop:pointcut expression="execution(* cn.service.UserServiceImpl.*(..))" id="pointcut"/>
    <aop:advisor advice-ref="aroundLog" pointcut-ref="pointcut"/>
    <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
    <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    <aop:advisor advice-ref="errorLog" pointcut-ref="pointcut"/>
  </aop:config>

--------------------

Test:
package test;

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

import cn.service.UserService;



public class Test {
public static void main(String[] args) {
	ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
   UserService userservice = (UserService)ac.getBean("userService");
   //userservice.delete();
   userservice.update(1);
}
}
輸出:



總結:

①:環繞增強在目標方法前後(環繞前、環繞後)都可以插入增強處理

②:環繞增強是spring中最強大的增強,Spring把目標方法的控制權全部給了它,可以獲取或者修改目標方法的引數和返回值,並且可以對方法進行異常處理和決定方法是否執行

注意一點:如果<aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>放在

<aop:advisor advice-ref="aroundLog" pointcut-ref="pointcut"/>之前,執行的順序會變得不一樣



這僅僅是before和around的環繞前有這樣的效果,after始終都是在方法執行後執行,然後再到around的環繞後執行。

二、非註解的自定義類實現aop增強

Log:
package cn.log;

/**
 * 自定義類實現aop
 * */

public class Log  {
   public void before()
   {
	   System.out.println("方法執行前---55566-----");
   }
   
   public void after()
   {
	   System.out.println("方法執行後--------");
   }
   
}
beans.xml
<bean id="userService" class="cn.service.UserServiceImpl"/>
  <bean id="log" class="cn.log.Log"/>
  
  
  <aop:config>
    <aop:aspect ref="log">
      <aop:pointcut expression="execution(* cn.service.UserServiceImpl.*(..))" id="pointcut"/>
      <aop:before method="before" pointcut-ref="pointcut"/>
      <aop:after method="after" pointcut-ref="pointcut"/>
     </aop:aspect>
  </aop:config>
除了before、after之外,還可以自定義around、after-returning、after-throwing


三、使用註解實現自定義aop增強

log:

package cn.log;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

/**
 * 自定義類實現aop
 * +++++++使用註解!!!
 * */

@Aspect
public class Log  {
	@Before("execution(* cn.service.UserServiceImpl.*(..))")
   public void before()
   {
	   System.out.println("方法執行前--------");
   }
   @After("execution(* cn.service.UserServiceImpl.*(..))")
   public void after()
   {
	   System.out.println("方法執行後--------");
   }
   @Around("execution(* cn.service.UserServiceImpl.*(..))")
   public void aroud(ProceedingJoinPoint jp) throws Throwable 
   {
	   System.out.println("環繞前");
	   System.out.println("簽名:"+jp.getSignature());
	 //  Object result = jp.proceed();
	   jp.proceed();
	   System.out.println("環繞後");
	 //  return result;
   }
}
beans.xml
<bean id="userService" class="cn.service.UserServiceImpl"/>
  <bean id="log" class="cn.log.Log"/>
  
 <aop:aspectj-autoproxy/>
Test:
public static void main(String[] args) {
	ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
   UserService userservice = (UserService)ac.getBean("userService");
   //userservice.add();
   userservice.delete();
}
輸出:




三種方式定義增強使用建議:

Spring在定義切面時提供了多種選擇,應根據專案的具體情況做出選擇:
1、通過介面實現增強處理是較低版本Spring AOP的做法,如果在一個使用低版本Spring AOP開發的專案上進行升級,
可以考慮使用<aop:advisor>複用已經存在的增強類;
2、如果專案採用JDK 5.0或以上版本,可以考慮使用@AspectJ註解方式,減少配置的工作量;
3、如果不願意使用註解或專案採用的JDK版本較低無法使用註解,則可以選擇使用<aop:aspect>配合普通JavaBean的形式。