最近读Spring in action后,感觉这本书并没有其描绘的那么轻松幽默,相反很多地方还陷入了迷潭。记得以前上学的时候,读的一本《Spring 2.0技术手册》挺简单的。哎,不过越是不容易的事情越要挑战下,不是吗?
按照作者的思想,假想有一个Performer表演者。它的定义如下所示:
package SpringIdol; public interface Performer { public void performer(); }
其某一个实现类:
package SpringIdol; public class Juggle implements Performer { public int bagger=3; public Juggle() { super(); } public Juggle(int bagger) { super(); this.bagger = bagger; } @Override public void performer() { System.out.println("Juggle :"+bagger); } public int getBagger() { return bagger; } public void setBagger(int bagger) { this.bagger = bagger; } }
定义了观众类,并且在performer表演(执行performer)前后做一些规定性的动作。
表演前落座,关手机,演出完鼓掌,不满意(有异常的时候)要求退票。
下面就是这个类的定义:
package SpringIdol; public class Audience { public Audience(){ } public void takeSeats(){ System.out.println("I can seat"); } public void turnOffTheirPhone(){ System.out.println("I have turn off phone"); } public void applaud(){ System.out.println("clap clap clap"); } public void demandRefund(){ System.out.println("No,I want our money back"); } }
下面编写通知类。通知类就是当触发被切入类的切面时所执行的函数,分为触发前执行,触发后执行,以及前后都执行。类的定义如下所示 :
package SpringIdol; //事后返回 import java.lang.reflect.Method; import org.springframework.aop.AfterReturningAdvice; //事前执行 import org.springframework.aop.MethodBeforeAdvice; //抛出后 import org.springframework.aop.ThrowsAdvice; public class AudienceAdvice implements AfterReturningAdvice, MethodBeforeAdvice, ThrowsAdvice { public AudienceAdvice() { } @Override public void afterReturning(Object paramObject1, Method paramMethod, Object[] paramArrayOfObject, Object paramObject2) throws Throwable { // 在方法的执行后执行鼓掌函数 audience.applaud(); } public void before(Method paramMethod, Object[] paramArrayOfObject, Object paramObject) throws Throwable { // 在执行前,执行落座和关手机两件事 audience.takeSeats(); audience.turnOffTheirPhone(); }; // 约定的方法之一,用于抛出异常时执行 public void afterThrowing(Throwable throwable) { // 在异常的抛出处,执行退票事件 audience.demandRefund(); } private Audience audience; public Audience getAudience() { return audience; } public void setAudience(Audience audience) { this.audience = audience; } }
这里的audience将来会通过依赖注入来完成实例化。
接下来就到了最关键的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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd" > <!-- 定义观众 --> <bean id="audience" class="SpringIdol.Audience"/> <!-- 定义主动织入切面的 --> <bean id="audienceAdvice" class="SpringIdol.AudienceAdvice"> <property name="audience" ref="audience"></property> </bean> <!-- 繁琐的定义PointCut织入规则 --> <bean id="performancePointCut" class="org.springframework.aop.support.JdkRegexpMethodPointcut"> <property name="pattern" value=".*performer"></property> </bean> <bean id="audienceAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"> <!-- 定义通知事件 --> <property name="advice" ref="audienceAdvice"></property> <!-- 定义织入规则 --> <property name="pointcut" ref="performancePointCut"></property> </bean> <!-- 简便的定义PointCut --> <!-- ProxyFactoryBean --> <bean id="dukeTarget" class="SpringIdol.PoticJuggle"> <constructor-arg value="15"></constructor-arg> </bean> <bean id="duke" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="dukeTarget"/> <property name="interceptorNames" value="audienceAdvisor"/> <property name="proxyInterfaces" value="SpringIdol.Performer"/> </bean> </beans>
注意最后面的代理类,它在代理多个类(不同的演出者时)将会有非常大的作用。
编写一个测试类来测试下:
package Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import SpringIdol.Performer; public class TestAOP { public static void main(String... args){ ApplicationContext context=new ClassPathXmlApplicationContext("SpringAop.xml"); Performer performer = (Performer)context.getBean("duke"); performer.performer(); } }
执行结果如下所:
I can seat I have turn off phone Juggle :15 clap clap clap