基于注解的方式
cfg.xml中
1 <!-- 通过注释的方式来实现AOP所以要扫描包 --> 2 <context:component-scan base-package="spring_aop_helloworld"></context:component-scan> 3 <!-- 要把切面自动生成代理写上 --> 4 <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
要在计算器的每个方法的开始和结束时打印日志文件
首先计算器类被配置成bean,然后
Logging.java
1 package spring_aop_helloworld; 2 3 import java.util.Arrays; 4 5 import org.aspectj.lang.JoinPoint; 6 import org.aspectj.lang.ProceedingJoinPoint; 7 import org.aspectj.lang.annotation.After; 8 import org.aspectj.lang.annotation.AfterReturning; 9 import org.aspectj.lang.annotation.AfterThrowing; 10 import org.aspectj.lang.annotation.Around; 11 import org.aspectj.lang.annotation.Aspect; 12 import org.aspectj.lang.annotation.Before; 13 import org.aspectj.lang.annotation.Pointcut; 14 import org.springframework.core.annotation.Order; 15 import org.springframework.stereotype.Component; 16 17 @Order(2) 18 @Aspect 19 @Component 20 public class Logging { 21 //以这种方式实现重用,不用每次都写execution(* spring_aop_helloworld.Calculator.*(int,int)) 22 @Pointcut(value="execution(* spring_aop_helloworld.Calculator.*(int,int))") 23 public void getExpression(){} 24 25 /** 26 * 前置通知,在执行* spring_aop_helloworld.Calculator.*(int,int)(使用了AspectJ表达式)前执行此方法 27 * 28 * JoinPoint j传入参数 29 * j.getSignature().getName()获取方法名 30 * j.getArgs()获取参数数组 31 * */ 32 @Before(value="getExpression()") 33 public void before(JoinPoint j){ 34 System.out.println("Before通知"+j.getSignature().getName()+":"+Arrays.asList(j.getArgs()) ); 35 } 36 37 /** 38 * 后置通知,在执行后执行此方法,不管这个方法有没有异常,能不能执行 39 * */ 40 @After(value="execution(* spring_aop_helloworld.Calculator.*(int,int))") 41 public void after(JoinPoint j){ 42 System.out.println("After通知"+j.getSignature().getName()+":"+Arrays.asList(j.getArgs())); 43 } 44 45 /** 46 * 返回通知,在方法返回结果之后执行 47 * returning="result"通过参数中和其名字相同的参数传入可以得到被代理方法的返回值 48 * */ 49 @AfterReturning(value="execution(* spring_aop_helloworld.Calculator.*(int,int))",returning="result") 50 public void afterReturning(JoinPoint j,Object result){ 51 System.out.println("AfterReturning通知:"+j.getSignature().getName()+":"+Arrays.asList(j.getArgs())+":"+result); 52 } 53 54 /** 55 * 异常通知,在方法抛出异常之后执行,若没有异常则不执行 56 * throwing="e"通过参数中和其名字相同的参数传入发生的异常。 57 * 也可以只在指定异常抛出后通知 58 * */ 59 @AfterThrowing(value="execution(* spring_aop_helloworld.Calculator.*(int,int))",throwing="e") 60 public void afterEhroeing(JoinPoint j,Exception e){ 61 System.out.println("AfterThrowing通知:"+j.getSignature().getName()+":"+Arrays.asList(j.getArgs())+":"+e); 62 } 63 64 /** 65 * 环绕通知 66 * */ 67 @Around(value="execution(* spring_aop_helloworld.Calculator.*(int,int))") 68 public Object around(ProceedingJoinPoint p){ 69 String methodName = p.getSignature().getName(); 70 Object o = null; 71 72 try { 73 System.out.println("-->等同前置通知"); 74 o = (int) p.proceed(); 75 System.out.println("-->等同返回通知"); 76 } catch (Throwable e) { 77 // throw new RuntimeException(e); 78 System.out.println("-->等同异常通知"); 79 } 80 System.out.println("-->等同后置通知"); 81 return o; 82 } 83 }
验证器类
package spring_aop_helloworld; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** * Order(1)代表切面被调用的优先级,数字越小越先调用 * Aspect 表示这是一个切面 * Component 表示这是一个组件,IOC容器可以扫描到 * */ @Order(1) @Aspect @Component public class Validation { //spring_aop_helloworld.Logging.getExpression()返回要代理的方法,实现重用 @Before(value="spring_aop_helloworld.Logging.getExpression()") public void before_validation(JoinPoint j){ System.out.println("0000验证前置"+j.getSignature().getName()); } }
基于配置文件的方式
cfg.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-4.0.xsd"> <bean id="calculatorImpl" class="spring_aop_xml.CalculatorImpl"></bean> <bean id="logging" class="spring_aop_xml.Logging"></bean> <bean id="validation" class="spring_aop_xml.Validation"></bean> <aop:config> <aop:pointcut expression="execution(* spring_aop_xml.Calculator.*(int, int))" id="expression"/> <aop:aspect ref="logging" order="2"> <aop:before method="before" pointcut-ref="expression"/> <aop:after method="after" pointcut-ref="expression"/> <aop:after-returning method="afterReturning" pointcut-ref="expression" returning="result"/> <aop:after-throwing method="afterthrowing" pointcut-ref="expression" throwing="e"/> <aop:around method="around" pointcut-ref="expression"/> </aop:aspect> <aop:aspect ref="validation" order="1"> <aop:before method="before_validation" pointcut-ref="expression"/> </aop:aspect> </aop:config> </beans>
验证器类和日志文件类都和基于注解的一样,只不过去掉注解。
传统的代理方法实现面向切面编程
package spring_aop_old; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class CalculatorProxy { private Calculator c; //通过构造器传入被代理的对象 public CalculatorProxy(Calculator c) { this.c = c; } //获取代理对象 public Object getInstance(){ Object proxy = null; InvocationHandler handler = new InvocationHandler() { /** * 当想要运行被代理对象的相关方法时,代理对象通过调用invoke来调用被代理对象的方法 * * Object proxy是getInstance()返回的代理对象 * Method method被代理对象的方法 * Object[] args被代理对象的方法中的参数 * */ @Override public Object invoke(Object proxy, Method method, Object[] args) { Object result = null; System.out.println("之前..类似前置"); try { result = method.invoke(c, args); } catch (Exception e) { System.out.println("异常..类似异常"); } System.out.println("之后..类似后置"); return result; } }; proxy = Proxy.newProxyInstance(c.getClass().getClassLoader(), new Class[]{Calculator.class}, handler); return proxy; } }
package spring_aop_old; public class TestAOPHello { public static void main(String[] args) { Calculator c = (Calculator) new CalculatorProxy(new CalculatorImpl()).getInstance(); System.out.println(c.add(1, 2)); System.out.println(c.div(10, 0)); } }
时间: 2024-10-07 05:30:00