AOP增强是指在目标类的连接点上织入一段代码。连接点由两个信息确定,一、方法表示的程序执行点;二、用相对点表示的方位。简单的来说,增强就是在目标类的方法执行前或者方法执行后拦截并加一段代码。一个类被AOP增强后,就产生了一个结果类,它是融合了原类和增强逻辑的代理类。
Spring支持5种类型的增强,按照增强在目标类方法的连接点位置,可以分为以下5类:
BeforeAdvice(前置增强)
BeforeAdvice类代表前置增强,因为Spring只支持方法级增强,所以MethodBeforeAdvice是目前可用的前置增强,表示在目标方法执行前实施增强。简单来说,就是在目标方法执行前拦截并执行一些代码。
AfterReturningAdvice(后置增强)
AfterReturningAdvice代表后置增强,表示在目标方法执行后实施增强。简单来说,就是在目标方法执行后执行一些代码。
MethodInterceptor(环绕增强)
MethodInterceptor代表环绕增强,表示在目标方法执行前后实施增强。简单来说,就是在目标方法执行前和后都会拦截并执行一些代码。
ThrowsAdvice(异常抛出增强)
ThrowsAdvice代表抛出异常增强,表示在目标方法抛出异常后实施增强。简单来说,就是在目标方法抛出异常的时候拦截并执行一些代码。
IntroductionInterceptor(引介增强)
IntroductionInterceptor代表引介增强,表示在目标类中添加一些新的方法和属性。
1.前置增强
前置增强是在目标方法调用前执行,下面定义一个Cat类,里面有两个方法,分别为eatIng和eatEed。一只不可爱的猫的情况:
1 2 3 4 5 6 7 8
| public class Cat { public void eatIng(String name){ System.out.println(" I'm eating"); } public void eatEed(String name){ System.out.println(" I'm finished"); } }
|
闷不做声,毫无感情。下面通过增强来让这只猫显得可爱一些。
增强类
MethodBeforeAdvice接口仅定义了唯一方法。method为目标类的方法;objects为目标类方法的入参;o为目标类实例。
1 2 3 4 5 6 7 8
| import org.springframework.aop.MethodBeforeAdvice; import java.lang.reflect.Method; public class Before implements MethodBeforeAdvice { public void before(Method method, Object[] objects, Object o) throws Throwable { String name=(String)objects[0]; System.out.print("瞄!瞄!瞄! I is "+name); } }
|
测试
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class BeforeTest { public static void main(String[] args) { Cat c=new Cat(); BeforeAdvice advice=new Before(); ProxyFactory pf=new ProxyFactory(); pf.setTarget(c); pf.addAdvice(advice); Cat c1=(Cat)pf.getProxy(); System.out.println("我是Before增强"); c1.eatIng("旺财"); c1.eatEed("旺财"); } }
|
下面通过xml配置声明一个代理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="target" class="org.zmd.model.Cat"/> <bean id="before" class="org.zmd.Advice.Before"/> <bean id="c" class="org.springframework.aop.framework.ProxyFactoryBean" p:interceptorNames="before" p:target-ref="target"/> </beans>
|
测试
1 2 3 4 5 6 7 8 9 10
| public class BeforeTest1 { public static void main(String[] args) { String path="Advice/Before.xml"; ApplicationContext con=new ClassPathXmlApplicationContext(path); Cat c= con.getBean("c",Cat.class); System.out.println("我是Before增强"); c.eatIng("旺财"); c.eatEed("旺财"); } }
|
上面两个测试的结果:
2.后置增强
后置增强是在目标类方法调用后执行。下面通过后置增强让猫显得更加可爱。
增强类
通过实现AfterReturningAdvice接口来定义增强的逻辑。o为目标实例方法返回的结果;method为目标类方法;objects为目标实例的方法的入参;o1为目标类实例。
1 2 3 4 5 6 7
| import org.springframework.aop.AfterReturningAdvice; import java.lang.reflect.Method; public class After implements AfterReturningAdvice { public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable { System.out.println("瞄!瞄!瞄! 谢谢老板的饭。"); } }
|
测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class AfterTest { public static void main(String[] args) { Cat c=new Cat(); BeforeAdvice before=new Before(); AfterReturningAdvice aftet=new After(); ProxyFactory pf =new ProxyFactory(); pf.setTarget(c); pf.addAdvice(before); pf.addAdvice(aftet); Cat c1=(Cat) pf.getProxy(); System.out.println("我是After增强"); c1.eatIng("旺财"); c1.eatEed("旺财"); } }
|
XML配置
1 2 3 4 5 6 7 8 9 10 11 12
| <?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="target" class="org.zmd.model.Cat"/> <bean id="after" class="org.zmd.Advice.After"/> <bean id="before" class="org.zmd.Advice.Before"/> <bean id="c" class="org.springframework.aop.framework.ProxyFactoryBean" p:target-ref="target" p:interceptorNames="after,before"/> </beans>
|
测试结果:
3.环绕增强
环绕增强的作用已经很明显了,环绕增强允许在目标类方法调用前后织入横切逻辑,它综合实现了前置、后置增强两者的功能。
增强类
1 2 3 4 5 6 7 8 9 10 11 12 13
| import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation;
public class Interceptor implements MethodInterceptor { public Object invoke(MethodInvocation methodInvocation) throws Throwable { Object [] o=methodInvocation.getArguments(); String name=(String)o[0]; System.out.print("瞄!瞄!瞄! I is "+name); Object ob=methodInvocation.proceed(); System.out.println("瞄!瞄!瞄! 谢谢老板的饭。"); return ob; } }
|
XML配置
1 2 3 4 5 6 7 8 9 10 11
| <?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="target" class="org.zmd.model.Cat"/> <bean id="in" class="org.zmd.Advice.Interceptor"/> <bean id="c" class="org.springframework.aop.framework.ProxyFactoryBean" p:interceptorNames="in" p:target-ref="target"/> </beans>
|
测试:
4.异常抛出增强
定义Dog类,里面有两个抛出异常的方法。
1 2 3 4 5 6 7 8 9 10 11
| import java.sql.SQLException; public class Dog {
public void Hungry(String name) throws Exception{ throw new SQLException("我饿得都不认识你了!铲屎官"); }
public void Bad(String name){ throw new RuntimeException("我生病了!铲屎官!"); } }
|
增强类
1 2 3 4 5 6 7 8 9 10
| import org.springframework.aop.ThrowsAdvice; import java.lang.reflect.Method; public class Throw implements ThrowsAdvice { public void afterThrowing(Method method,Object [] args,Object target,Exception ex) throws Throwable{ System.out.println("**************"); System.out.println("函数名:"+method.getName()); System.out.println("抛出异常: 我是"+args[0]+" "+ex.getMessage()); System.out.println("成功增强异常"); } }
|
测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class ThrowTest { public static void main(String[] args) { Dog d=new Dog(); ProxyFactory pf=new ProxyFactory(); ThrowsAdvice t=new Throw(); pf.setTarget(d); pf.addAdvice(t); Dog d1=(Dog) pf.getProxy(); try { d1.Hungry("广生"); } catch (Exception e) { e.printStackTrace(); } d1.Bad("广生"); } }
|
结果: