最近读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