Quotes: http://hi.baidu.com/cliff77/blog/item/e83a7b036ccbf18dd53f7c3f.html
有两种代理方式:
1)JAVA动态代理,只适用于接口。它是一种标准的JAVA特性,可提供卓越的性能
2)适用于目标对象没有任何实现接口的情况,而且这类接口无法引入(例如遗留代码)。它基于使用CGLIB库的运行时字节码生成
五种拦截类型
Spring只支持方法拦截,也就是说,只能在方法的前后进行拦截,而不能在属性前后进行拦截。
1)目标方法调用前(before),必须实现MethodBeforeAdvice接口,实现其中的before方法。对方法的执行有两种影响,一是可更改传入的参数,二是通过抛出异常跳过方法的执行。
public class LogBeforeAdvice implements MethodBeforeAdvice{
public void before(Method m,Object[] args,Object target) throws Throwable{
System.out.println("开始处理数据");
}}
2)目标方法调用后(after),必须实现AfterReturningAdvice接口,实现其中的afterReturning方法。此类通知无法更改传入的参数,也无法影响方法的调用,只能在方法返回时做些附加动作。
public class LogAfterAdvice implements AfterReturningAdvice{
public void afterReturning(Method m,Object[] args,Object target) throws Throwable{
System.out.println("处理数据结束");
}}
3)目标方法调用前后(around),必须实现 MethodInterceptor接口,实现其中的invoke方法。可以更改目标方法的参数列表及返回值,也可以阻止该方法的执行。前后拦截是唯一可 以控制目标方法是否被真正调用的拦截类型,也可以控制返回对象。而前置拦截或后置拦截不能控制,它们不能影响目标方法的调用和返回。
public class LogInterceptor implements MethodInterceptor{
public object invoke(MethodInvocation invocation) throws Throwable{
System.out.println("开始处理数据");
Object rval=invocation.proceed();
System.out.println("处理数据结束");
return rval;
}}
4)目标方法抛出异常(throw),即在目标类方法抛出异常时织入通知。异 常通知接口没有定义任何方法,如果想捕获方法抛出的通知,可以定义若干 afterThrowing() 方法,AOP框架将根据此函数中的异常类型,捕获目标类方法抛出的该类型异常及其子类型(除非有捕获其子类型的 afterThrowing()) 方法。
public class LogThrowAdvice implements ThrowsAdvice{
public void afterThrowing(RemoteException ex) throws Throwable{
System.out.println("处理数据抛出异常" +ex);
}}
5)引入通知(Introduction),此类通知区别于上述4种,其特点在于能在目标类织入新的方法及属性。
切入点的定义相当于更加细化地规定了哪些方法被哪些拦截器所拦截,而并非所有的方法都被所有的拦截器所拦截。在ProxyFactoryBean的属性
中,interceptorNames属性的对象也由拦截(Advice)变成了引入通知(Advisor),正是在Advisor中详细定义了切入点
(PointCut)和拦截(Advice)的对应关系,比如常见的基于名字的切入点匹配
(NameMatchMethodPointcutAdvisor类)和基于正则表达式的切入点匹配(RegExpPointcutAdvisor类)。
这些切入点都属于”静态切入点“,因为他们只在代理创建的时候被创建一次,而不是每次运行都创建。
实例(Before通知)
1. 直接采用proxy方式实现AOP
1)FooInterface.java(接口) 2)FooImpl.java(实现类)
package cliff;
public interface FooInterface {
public void printFoo();
public void dummyFoo();
}
package cliff;
public class FooImpl implements FooInterface{
public void dummyFoo() { System.out.println("dummy foo");}
public void printFoo() { System.out.println("print foo"); }
}
3)PrintBeforeAdvice.java(拦截器)
package cliff;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class PrintBeforeAdvice implements MethodBeforeAdvice{
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
System.out.println("In PrintBeforeAdvice");
}
}
4)AOPTest.java(测试类)
package cliff;
import org.springframework.aop.framework.ProxyFactory;
public class AOPTest {
public static void main(String[] args) {
FooImpl fooImpl = new FooImpl();
PrintBeforeAdvice myAdvice=new PrintBeforeAdvice();
ProxyFactory proxyFactory=new ProxyFactory(fooImpl);
proxyFactory.addAdvice(myAdvice);
FooInterface myInterface=(FooInterface)proxyFactory.getProxy();
myInterface.printFoo();
myInterface.dummyFoo();
}
}
2.依赖注入方式
1)2)3)的程序一样
4)bean.xml(配置文件)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC '//-SPRING//DTD BEAN//EN'
'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
<description>The AOP application context </description>
<bean id="fooTarget" class="cliff.FooImpl" />
<bean id="MyAdvice" class="cliff.PrintBeforeAdvice" />
<bean id="foo" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"> <!--接口-->
<value>cliff.FooInterface</value>
</property>
<property name="target"> <!--实现类-->
<ref local="fooTarget" />
</property>
<property name="interceptorNames"> <!--拦截器-->
<list>
<value>MyAdvice</value>
</list>
</property>
</bean>
</beans>
5)AOPTestWithXML.java(测试类)
package cliff;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class AOPTestWithXML {
public static void main(String[] args) {
ApplicationContext context=new FileSystemXmlApplicationContext("src/bean.xml");
FooInterface foo=(FooInterface)context.getBean("foo");
foo.dummyFoo();
foo.printFoo();
}
}