1.AOP底層是基於反射的
a)先來一個代理接口:
1 ackage com.laola.arthimetic; 2 3 import org.springframework.stereotype.Component; 4 5 public interface Arthimetic { //這個接口就是用來接受代理對象的 6 int add(int i,int j); 7 int sub(int i,int j); 8 int mul(int i,int j); 9 int div(int i,int j); 10 }
b) 實現類:
package com.laola.arthimetic; import org.springframework.stereotype.Component; @Component public class ArthimeticImpl implements Arthimetic{ //實現此接口 @Override public int add(int i, int j) { return i+j; } @Override public int sub(int i, int j) { return i-j; } @Override public int mul(int i, int j) { return i*j; } @Override public int div(int i, int j) { return i/j; } }
2.日志消息類
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.stereotype.Component; import java.sql.SQLOutput; import java.util.Arrays; import java.util.List; //注意這里的注解我是沒有用的 @Aspect @Component public class LogAspect { // 切面的before方法 public void logbefore(JoinPoint joinPoint){ String name=joinPoint.getSignature().getName(); List<Object> args= Arrays.asList(joinPoint.getArgs()); System.out.println(name+" begin"+args); } //切面的after方法 public void logafter(JoinPoint joinPoint){ String name=joinPoint.getSignature().getName(); System.out.println(name+" end"); }
//切面的returing方法 public void logreturing(JoinPoint joinPoint,Object r){ String name=joinPoint.getSignature().getName(); System.out.println(name+" returing "+r); }
//切面的throwing方法 public void aftethrowing(JoinPoint joinPoint,Exception e) { String name=joinPoint.getSignature().getName(); System.out.println(name+" throwing "+e); } }
3.測試類
import com.laola.arthimetic.Arthimetic; import com.laola.arthimetic.ArthimeticImpl; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class test { //雖然注解比較方便,但有時候jdk或者其他插件版本更新會有切面注解失效等問題的存在,為了省去找解決辦法的時間,還是使用bean配置文件 public static void main(String[] args) { ApplicationContext ctx= new ClassPathXmlApplicationContext("beans.xml");
//接口代理 Arthimetic arthimetic=(Arthimetic) ctx.getBean("arthimeticImpl"); int r=arthimetic.div(12,0); System.out.println(r); } }
4.beans.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" 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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd " > <!-- 1.注冊bean和切面--> <bean id="arthimeticImpl" class="com.laola.arthimetic.ArthimeticImpl"></bean> <bean id="logaspect" class="LogAspect"></bean> <!-- 2.開始配置--> <aop:config> <!-- 創建一個共有切入點,這樣就不用頻繁的使用 "execution(* com.laola.arthimetic.Arthimetic.*(..))"了 --> <aop:pointcut id="pointcut" expression="execution(* com.laola.arthimetic.Arthimetic.*(..))"/> <!-- 3.創建切面--> <aop:aspect ref="logaspect" order="1"> <!-- 4.切面方式 --> <aop:before method="logbefore" pointcut-ref="pointcut"/> <aop:after method="logafter" pointcut-ref="pointcut" /> <aop:after-returning method="logreturing" pointcut-ref="pointcut" returning="r"/> <aop:after-throwing method="aftethrowing" pointcut-ref="pointcut" throwing="e"/> </aop:aspect> </aop:config> </beans>
這里面有些命名空間沒用到,沒啥影響。
5.總結
a. 如果使用idea編寫Spring,有些包是沒有下載的,比如aspectj-weaver這個jar包,有時候采用注解方式會發現提示中沒有@Aspect以及它以下的子注解,所以這個包單獨下載或者從本地導入。
b. 一般我們使用配置文件這種形式出錯率會少,雖然效率相對較慢,但若這種情況發生在idea上,不會是個大問題,因為它有很好的提示功能。
c. 另外要注意切面的每個細節屬性,不然容易報錯。
d. 為了減少多次service層的公有方法的代碼調用量,一般用pointcut來創建切入點,使用expression=execution(* com.laola.arthimetic.Arthimetic.*(..))"來完成公有方法的調用
e. 另外遇到注解括號內有(name和value兩個屬性的二選一的,最好選擇value)