在一个方法前面和后面增加通知,不改变原来的方法,使程序的扩展性加大。
给Demo 的demo2方法前后加通知:
applicationContext.xml配置:
<!-- after 和 before类由Spring管理 ,因为要注入切面--> <bean id="myAfterAdvice" class="com.spring.advice.MyAfterAdvice"></bean> <bean id="myBeforeAdvice" class="com.spring.advice.MyBeforeAdvice"></bean> <!-- 配置切面 --> <aop:config > <aop:pointcut expression="execution(* com.spring.demo.Demo.demo2())" id="point"/> <aop:advisor advice-ref="myAfterAdvice" pointcut-ref="point"/> <aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="point"/> </aop:config> <!-- demo类由Spring管理,才能实现切面 --> <bean id="demo" class="com.spring.demo.Demo"></bean>
Demo类:
public class Demo { public void demo1() { System.out.println("demo1"); } public void demo2() { System.out.println("demo2"); } public void demo3() { System.out.println("demo3"); } }
test:
public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); Demo demo = applicationContext.getBean("demo",Demo.class); demo.demo1(); demo.demo2(); demo.demo3();
前置通知,要实现MethodBeforeAdvice接口(后置通知同理,实现AfterReturningAdvice接口):
public class MyBeforeAdvice implements MethodBeforeAdvice{ @Override public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { System.out.println("before advice"); } }
输出结果:
demo1
before advice
demo2
after adivce
demo3
前置通知和后置通知参数:
public class MyBeforeAdvice implements MethodBeforeAdvice{ @Override public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { //arg0是切点的方法名 System.out.println(arg0.getName()); //arg1是切点的参数 if(arg1.length>0) { System.out.println(arg1[0]); } //arg2是切点对象 System.out.println(arg2); System.out.println("before advice"); } } public class MyAfterAdvice implements AfterReturningAdvice{ @Override public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable { //arg0是切点方法的返回值 System.out.println(arg0.toString()); //arg1是切点方法 System.out.println(arg1.getName()); //arg2是切点方法的参数 if(arg2.length>0) { System.out.println(arg2[0]); } //arg3是切点对象 System.out.println(arg3); System.out.println("after adivce"); } }
*通配符的使用:
<aop:config> <!-- *代表通配,比如 (* com.spring.demo.Demo.*())代表匹配Demo类的所有无参方法 (* com.spring.demo.Demo.*(..))代表匹配Demo类的所有任意参数方法 (* com.spring.demo.*.*(..))代表匹配com.spring.demo包下所有类的所有的任意参数方法 *更多使用方法类似 --> <aop:pointcut expression="execution(* com.spring.demo.Demo.demo1(..))" id="point"/> <aop:advisor advice-ref="myAfterAdvice" pointcut-ref="point"/> <aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="point"/> </aop:config> <!-- demo类由Spring管理,才能实现切面 --> <bean id="demo" class="com.spring.demo.Demo"></bean>
给方法加异常通知(使用aop:aspect标签):
applicationContext.xml:
<!-- 自己定义一个异常通知类,必须交给Spring管理 --> <bean id="myException" class="com.spring.demo.MyException"></bean> <!-- 配置异常通知 --> <aop:config> <!-- 给Demor 的demo1方法配置异常通知 --> <aop:pointcut expression="execution(* com.spring.demo.Demo.demo1(..))" id="myPoint"/> <!-- 配置自己定义的异常通知类的id --> <aop:aspect ref="myException"> <!-- 配置自己定义的异常通知类的方法 --> <aop:after-throwing method="myThrowException" pointcut-ref="myPoint"/> </aop:aspect> </aop:config> <!-- 要加入异常通知的类必须由Spring管理 --> <bean id="demo" class="com.spring.demo.Demo"></bean>
自己定义的异常通知类:(当demo1方法出现异常时,会运行自定义的异常通知。注意:如果在demo1内使用cry,catch后
Spring不会知道程序出异常了,因为异常被cry,catch处理了)
public class MyException { public void myThrowException() { System.out.println("Throw Exception!!"); } }
给方法加异常通知(使用aop:aspect标签):
applicationContext.xml配置文件:
<!-- 自己定义一个异常通知类,必须交给Spring管理 --> <bean id="myException" class="com.spring.demo.MyException"></bean> <!-- 配置异常通知 --> <aop:config> <!-- 给Demor 的demo1方法配置异常通知 --> <aop:pointcut expression="execution(* com.spring.demo.Demo.demo1(..))" id="myPoint"/> <!-- 配置自己定义的异常通知类的id --> <aop:advisor advice-ref="myException" pointcut-ref="myPoint" /> </aop:config> <!-- 要加入异常通知的类必须由Spring管理 --> <bean id="demo" class="com.spring.demo.Demo"></bean>
自定义的异常通知对象:
//自定义的异常通知对象,实现ThrowAdvice接口,实现afterThrowing方法 public class MyException implements ThrowsAdvice{ //方法名必须是afterException,第一种只有一个异常对象 public void afterThrowing(Exception e){ System.out.println("Throw Exception!!"); } //第二种:方法名一样,参数不一样,第一个参数是切点方法,第二个参数是切点方法参数, //第三个参数是切点对象,第四个是异常对象 public void afterThrowing(Method m, Object[] args,Object target, Exception ex) { System.out.println(m.getName()); System.out.println(args.length); System.out.println(target); System.out.println("Throw Exception!!!!"); } }
环绕通知:
配置文件:
<!-- 自己定义的环绕通知类 --> <bean id="arround" class="com.spring.advice.AroundAdvice"></bean> <!-- 配置环绕通知 --> <aop:config> <!-- 给Demor 的demo1方法配置环绕通知 --> <aop:pointcut expression="execution(* com.spring.demo.Demo.demo1(..))" id="myPoint"/> <!-- 配置自己定义的环绕通知类的id --> <aop:advisor advice-ref="arround" pointcut-ref="myPoint" /> </aop:config> <!-- 要加入环绕通知的类必须由Spring管理 --> <bean id="demo" class="com.spring.demo.Demo"></bean>
环绕通知类:
//环绕通知,将前置和后置通知写在一起,环绕通知类需要实现MethodInterceptor接口 public class AroundAdvice implements MethodInterceptor{ @Override public Object invoke(MethodInvocation arg0) throws Throwable { //前置通知 System.out.println("before!!"); //通知完毕,执行方法 Object obj = arg0.proceed(); //后置通知 System.out.println("after"); return obj; } }
使用 aop:aspect配置前置,后置,异常通知:
<!-- 通知对象,由Spring管理 --> <bean id="myAdvice" class="com.spring.advice.MyAdvice"></bean> <aop:config> <!-- 无参数的方法配置通知 --> <aop:aspect ref="myAdvice"> <aop:pointcut expression="execution(* com.spring.demo.Demo.demo1())" id="myPoint"/> <aop:before method="before" pointcut-ref="myPoint"/> <!-- after一定会执行 --> <aop:after method="after" pointcut-ref="myPoint"/> <!-- after-returning 程序出异常的话不会执行 --> <aop:after-returning method="aftering" pointcut-ref="myPoint"/> <aop:after-throwing method="myThrow" pointcut-ref="myPoint"/> </aop:aspect> <!-- 有参数的方法配置通知 --> <aop:aspect ref="myAdvice"> <!-- args里有几个参数,arg-name里就必须有几个参数,而且名字必需一样 --> <aop:pointcut expression="execution(* com.spring.demo.Demo.demo2(String,int)) and args(name,index)" id="myPoint2"/> <aop:before method="beforeArgs" arg-names="name,index" pointcut-ref="myPoint2"/> </aop:aspect> </aop:config> <bean id="demo" class="com.spring.demo.Demo"></bean>
通知类:
//使用<aop:aspect>来配置前置、后置、异常通知 public class MyAdvice { //前置通知 public void before() { System.out.println("before"); } //后置通知 public void after() { System.out.println("after"); } public void aftering() { System.out.println("aftering"); } public void myThrow() { System.out.println("Exception!!"); } //带参数的前置通知 public void beforeArgs(String name,int index) { System.out.println("before="+name+"--"+index); } }
测试代码:
public class Test { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); Demo demo = applicationContext.getBean("demo",Demo.class); demo.demo1(); System.out.println("=================="); demo.demo2("Spring", 520); } }