史上最全面!Spring AOP介绍和用法详细示例

  1. Before Advice示例
  2. After Returning Advice的示例
  3. Around Advice示例
  4. After Throwing Advice的示例
给出了Spring1.2旧式AOP(基于dtd)实现的示例。
虽然它在spring 3中受支持, 但是Advice将Spring aop与我们将在下一页中学习的AspectJ一起使用。
spring1.2旧式aop实现中支持4种类型的Advice。
  1. 在Before Advice, 它在实际方法调用之前执行。
  2. 在After Advice, 它在实际方法调用之后执行。如果方法返回值, 则在返回值后执行。
  3. 在Advice周围, 它在实际方法调用之前和之后执行。
  4. 如果实际方法抛出异常, 则执行Throws Advice。
要了解Spring AOP的基本概念, 请访问上一页。 了解Advice界面的层次结构 让我们通过下面的图表了解Advice层次结构:
史上最全面!Spring AOP介绍和用法详细示例

文章图片
都是aop中的接口。
MethodBeforeAdvice接口扩展了BeforeAdvice接口。
AfterReturningAdvice接口扩展了AfterAdvice接口。
ThrowsAdvice接口扩展了AfterAdvice接口。
MethodInterceptor接口扩展了Interceptor接口。它在Around Advice使用。
1)MethodBeforeAdvice示例 创建一个包含实际业务逻辑的类。
档案:A.java
package com.srcmini; public class A { public void m(){System.out.println("actual business logic"); } }

现在, 创建实现MethodBeforeAdvice接口的顾问类。
文件:BeforeAdvisor.java
package com.srcmini; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; public class BeforeAdvisor implements MethodBeforeAdvice{ @Override public void before(Method method, Object[] args, Object target)throws Throwable { System.out.println("additional concern before actual logic"); } }

在xml文件中, 创建3个bean, 一个用于A类, 第二个用于Advisor类, 第三个用于ProxyFactoryBean类。
文件:applicationContext.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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> < bean id="obj" class="com.srcmini.A"> < /bean> < bean id="ba" class="com.srcmini.BeforeAdvisor"> < /bean> < bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"> < property name="target" ref="obj"> < /property> < property name="interceptorNames"> < list> < value> ba< /value> < /list> < /property> < /bean> < /beans>

了解ProxyFactoryBean类:
ProxyFactoryBean类由Spring Famework提供。它包含2个属性target和interceptorNames。 A类的实例将被视为目标对象, 顾问类的实例将被视为拦截器。你需要像上面给出的xml文件中那样将顾问程序对象作为列表对象传递。
ProxyFactoryBean类的编写如下:
public class ProxyFactoryBean{ private Object target; private List interceptorNames; //getters and setters }

现在, 让我们调用实际方法。
文件:Test.java
package com.srcmini; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; public class Test { public static void main(String[] args) { Resource r=new ClassPathResource("applicationContext.xml"); BeanFactory factory=new XmlBeanFactory(r); A a=factory.getBean("proxy", A.class); a.m(); } }

输出 实际逻辑之前的附加关注
在MethodBeforeAdvice中打印其他信息 我们可以打印其他信息, 例如方法名称, 方法参数, 目标对象, 目标对象类名称, 代理类等。
你只需要更改两个类BeforeAdvisor.java和Test.java。
文件:BeforeAdvisor.java
package com.srcmini; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; public class BeforeAdvisor implements MethodBeforeAdvice{ @Override public void before(Method method, Object[] args, Object target)throws Throwable { System.out.println("additional concern before actual logic"); System.out.println("method info:"+method.getName()+" "+method.getModifiers()); System.out.println("argument info:"); for(Object arg:args) System.out.println(arg); System.out.println("target Object:"+target); System.out.println("target object class name: "+target.getClass().getName()); } }

文件:Test.java
package com.srcmini; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; public class Test { public static void main(String[] args) { Resource r=new ClassPathResource("applicationContext.xml"); BeanFactory factory=new XmlBeanFactory(r); A a=factory.getBean("proxy", A.class); System.out.println("proxy class name: "+a.getClass().getName()); a.m(); } }

输出 代理类名称:com.srcmini.A $$ EnhancerByCGLIB $$ 409872b1在实际逻辑方法信息之前附加的关注点:m 1参数信息:target Object:com.srcmini.A@11dba45目标对象类名称:com.srcmini.A实际业务逻辑
2)AfterReturningAdvice示例 创建一个包含实际业务逻辑的类。
档案:A.java
与前面的示例相同。
现在, 创建实现AfterReturningAdvice接口的顾问类。
文件:AfterAdvisor.java
package com.srcmini; import java.lang.reflect.Method; import org.springframework.aop.AfterReturningAdvice; public class AfterAdvisor implements AfterReturningAdvice{ @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {System.out.println("additional concern after returning advice"); }}

如前面的示例中那样创建xml文件, 你只需要在这里更改Advisor类。
文件:applicationContext.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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> < bean id="obj" class="com.srcmini.A"> < /bean> < bean id="ba" class="com.srcmini.AfterAdvisor"> < /bean> < bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"> < property name="target" ref="obj"> < /property> < property name="interceptorNames"> < list> < value> ba< /value> < /list> < /property> < /bean> < /beans>

文件:Test.java
与前面的示例相同。
输出 After Returning Advice, 实际的业务逻辑需要额外关注
3)MethodInterceptor(AroundAdvice)示例 创建一个包含实际业务逻辑的类。
档案:A.java
与前面的示例相同。
现在, 创建实现MethodInterceptor接口的顾问程序类。
文件:AroundAdvisor.java
package com.srcmini; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; public class AroundAdvisor implements MethodInterceptor{ @Override public Object invoke(MethodInvocation mi) throws Throwable { Object obj; System.out.println("additional concern before actual logic"); obj=mi.proceed(); System.out.println("additional concern after actual logic"); return obj; }}

如前面的示例中那样创建xml文件, 你只需要在这里更改Advisor类。
文件:applicationContext.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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> < bean id="obj" class="com.srcmini.A"> < /bean> < bean id="ba" class="com.srcmini.AroundAdvisor"> < /bean> < bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"> < property name="target" ref="obj"> < /property> < property name="interceptorNames"> < list> < value> ba< /value> < /list> < /property> < /bean> < /beans>

文件:Test.java
与前面的示例相同。
输出 在实际逻辑之前附加关注实际业务逻辑在实际逻辑之后附加关注
4)ThrowsAdvice示例 创建一个包含实际业务逻辑的类。
文件:Validator.java
package com.srcmini; public class Validator { public void validate(int age)throws Exception{ if(age< 18){ throw new ArithmeticException("Not Valid Age"); } else{ System.out.println("vote confirmed"); } } }

现在, 创建实现ThrowsAdvice接口的顾问类。
文件:ThrowsAdvisor.java
package com.srcmini; import org.springframework.aop.ThrowsAdvice; public class ThrowsAdvisor implements ThrowsAdvice{ public void afterThrowing(Exception ex){ System.out.println("additional concern if exception occurs"); } }

如前面的示例一样, 创建xml文件, 你只需要更改Validator类和Advisor类。
文件:applicationContext.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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> < bean id="obj" class="com.srcmini.Validator"> < /bean> < bean id="ba" class="com.srcmini.ThrowsAdvisor"> < /bean> < bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"> < property name="target" ref="obj"> < /property> < property name="interceptorNames"> < list> < value> ba< /value> < /list> < /property> < /bean> < /beans>

文件:Test.java
package com.srcmini; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; public class Test { public static void main(String[] args) { Resource r=new ClassPathResource("applicationContext.xml"); BeanFactory factory=new XmlBeanFactory(r); Validator v=factory.getBean("proxy", Validator.class); try{ v.validate(12); }catch(Exception e){e.printStackTrace(); } } }

输出 【史上最全面!Spring AOP介绍和用法详细示例】java.lang.ArithmeticException:无效如果在com.srcmini.Validator $$ FastClassByCGLIB $$ 562915cf.invoke(< netned> )上的com.srcmini.Validator.validate(Validator.java:7)发生异常, 则还要额外考虑年龄.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)位于org.springframework.aop.framework.Cglib2AopProxy $ CglibMethodInvocation.invoke Joinpoint(Cglib2AopProxy.java:692)位于org.springframework.aop.framework.ReflectiveMethodInvocation。在org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor处继续(ReflectiveMethodInvocation.java:150)。在org.springframework.aop.framework.ReflectiveMethodInvocation上调用(ThrowsAdviceInterceptor.java:124)。在org.springframework.aop.framework.Cglib2AopProxy $ DynamicAdvisedInterceptor处继续(ReflectiveMethodInvocation.java:172)。在com.srcmini.Validator $$ EnhancerByCGLIB $$ 4230ed28.validate(< generated())在com.srcmini.Test.main(Test.java:15)处拦截(Cglib2AopProxy.java:625)

    推荐阅读