Spring AOP头绪众多,先从基本观念入手。
Spring AOP基本要务
悄悄地我走了,正如我悄悄地来……
AOP是OOP之后编程思想的又一次变革。在AOP的编程模型中对象A正交地“横切”到对象B的生命周期当中,而B对此却浑然不知,这样以“Aspect”的方式提高了类的重用性、灵活性以及可维护性,毕竟不用对B再动手脚,只要让它做好自己的本职工作,额外的事情交给A来完成。动态代理初步实现了这一点,而Spring AOP提供的方式却更为丰富而灵活。
Spring AOP的几个基本点就是Advice、Target、Proxy。Spring AOP的实现基于动态代理,因此理解后者有助于理解前者。
坐而论道不如躬身实践,如下HelloSpeaker就是那个对Aspect浑然不知的傻小子,我们称为Target。为了验证后面的ThrowsAdvice,我故意在参数为空时抛出异常。

public class HelloSpeaker implements IHello ...{

public String say_hello(String msg) ...{

if (msg == null || msg.equals("")) ...{
throw new NullPointerException("The arg is null...");

} else ...{
System.out.println("hello," + msg + "!");
}
return "succeed";
}
}

IHello是从HelloSpeaker引出的接口,这也是HelloSpeaker和Aspect唯一相接的地方,正是凭借这个接口,Target被Aspect玩弄于股掌。

public interface IHello ...{
public String say_hello(String msg);
}

下面几个类就是所谓的Advice,Advice就是“横切”的具体行为,如提供日志服务、权限管理等,它们在各种AOP实现中被织入(Weave)主体业务中。
AfterReturningAdvice接口的afterReturning方法在Target方法之后运行;MethodBeforeAdvice接口的before方法在Target方法之前运行;MethodInterceptor的invoke方法更为霸道,除了可在前后修饰之外还决定Target方法的运行,这个做法就类似于动态代理了。
ThrowsAdvice接口有些特殊,并无接口方法,只要实现接口者提供afterThrowing方法,并在方法中提供Throwable参数,并且可选method、target、args等参数。另外该接口并不改变原有的异常处理流程。

public class LogAfterAdvice implements AfterReturningAdvice ...{


public void afterReturning(Object obj_res, Method method, Object[] args, Object target) throws Throwable ...{
String res = (String) obj_res;
System.out.println("method " + method.getName() + " ends,res..." + res);
}
}


public class LogAroundAdvice implements MethodInterceptor ...{


public Object invoke(MethodInvocation method_invocation) throws Throwable ...{
System.out.println("In method-intercept, before method");
Object res = null;

try ...{
res = method_invocation.proceed();

} finally ...{
System.out.println("In method-intercept, Method "
+ method_invocation.getMethod().getName() + " end.");
}
return res;
}
}



public class LogBeforeAdvice implements MethodBeforeAdvice ...{

public void before(Method method, Object[] args, Object target)

throws Throwable ...{
System.out.println("Before " + method.getName() + " starts");
}

}



public class LogExceptionAdvice implements ThrowsAdvice ...{

public void afterThrowing(Method method, Object[] args, Object target, Throwable e) ...{
System.out.println("Exception " + e + ":"
+ " occurs at method " + method.getName());
}
}

维系各个Advice和Target的纽带就是Proxy,在这里就是ProxyFactoryBean,定义在配置文件当中。在这个代理当中指定Target及其interface,指定了各类advice。
<bean id="logBeforeAdvice" class="onlyfun.caterpillar.aop.LogBeforeAdvice"/>
<bean id="logAfterAdvice" class="onlyfun.caterpillar.aop.LogAfterAdvice"/>
<bean id="logInterceptor" class="onlyfun.caterpillar.aop.LogAroundAdvice"/>
<bean id="logException" class="onlyfun.caterpillar.aop.LogExceptionAdvice"/>
<bean id="helloSpeaker" class="onlyfun.caterpillar.aop.HelloSpeaker"/>
<bean id="helloProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="onlyfun.caterpillar.aop.IHello"/>
<property name="target" ref="helloSpeaker"/>
<property name="interceptorNames">
<list>
<value>logBeforeAdvice</value>
<value>logAfterAdvice</value>
<value>logInterceptor</value>
<value>logException</value>
</list>
</property>
</bean>
</beans>

测试一下,用ApplicationContext提取配置文件,获得代理对象并转化为IHello接口,从接口调用方法,第一次传递非空串,第二次传递空串引发异常:

public class MainTest ...{

public static void main(String[] args) ...{
ApplicationContext context = new ClassPathXmlApplicationContext(
"beanaop-config.xml");
IHello helloProxy = (IHello) context.getBean("helloProxy");

try ...{
helloProxy.say_hello("Tommy");
helloProxy.say_hello(null);

} catch (Throwable t) ...{
System.out.println(t);
}
}
}

结果如下:
Before say_hello starts
In method-intercept, before method
hello,Tommy!
In method-intercept, Method say_hello end.
method say_hello ends,res...succeed
====================
Before say_hello starts
In method-intercept, before method
In ThrowsAdvice:Exceptionjava.lang.NullPointerException: The arg is null...: occurs at method say_hello
In method-intercept, Method say_hello end.
in main test:java.lang.NullPointerException: The arg is null...
一切如常。搞清了基本概念,后面或有变化不外如是。