1.Pointcut(切入点)
实现:NameMatchMethodPointcut,根据方法名进行匹配
成员变量:mappedNames,匹配的方法名集合
eg:
<bean id="pointcutBean" class="org.springframework.apo.support.NameMatchMethodPointcut">
<property name="mappedNames">
<list>
<value>sa*</value>
</list>
</property>
</bean>
property是bean的属性,list表示property是一个集合
2.Brfore advice(一个简单的通知类型)
只是在进入方法钱被调用,不需要MethodInvocation对象
前置通知可以在连接点执行之前插入自定义行为,但不能改变返回值
public interface MeyhodeBeforeAdvice extends BeforeAdvic{
void before(Method m,Object[] args,Object target)throws Throwable;
}
public class CountingBeforeAdvice implements MethodBeforeAdvice{
private int count;
public void before(Method m,Object[] args,Object target)throws Throwable{
++count;
}
public int getCount(){
return count;
}
}
3.Throws advice(连接点抛出异常,在连接点返回后被调用)
如果throws-advice的方法抛出异常,那么他将覆盖原来的异常
接口org.springframework.aop.ThrowsAdvice不包含任何方法,仅仅是一个声明,实现类需要实现以下方法:void afterThrowing([Method,agrs,target],ThrowableSubclass);
public void afterThrowing(Exception ex);
public void afterThrowing(RemoteException ex);
public void afterThrowing(Method method,Object[] args,Object target,Exception ex);
public void afterThrowing(Method method,Object[] args,Object target,ServletException ex);
eg:
public static class CombineThrowsAdvic implements ThrowsAdvic{
public void afterThrowing(RemoteException ex)throws Throwable{
}
public void afterThrowing(Method method,Object[] args,Object target,ServletException ex){
}
}
4.After Returning advice(后置通知)
后置通知必须实现org.springframework.aop.AfterReturningAdvice接口
eg:
public class CountingAfterReturningAdvice implements AfterReturningAdvice{
private int count;
public void afterReturning(Object returnValue,Method m,Object[] args,Object target)throws Throwable{
++count;
}
public int getCount(){
return count;
}
}
可以访问返回值(但不能进行修改)、被调用的方法、方法的参数和目标
如果抛出异常,将会抛出拦截器链,替换返回值
5.Interception around advice
spring的切入点模型使得切入点可以独立与advice重用,以针对不同的advice可以使用相同切入点
public interface MethodInterceptor extends Interceptor{
Object invoke(MethodInvocation invocation)throws Throwable;
}
public class DebugInterceptor implements MethodInterceptor{
public Object invoke(MethodInvocation invocation)throws Throwable{
System.out.println("Before: invocation=[" + invocation + "]");
Object rval = invocation.proceed();
System.out.println("Invocation returned");
return rval;
}
}
6.Introduction advice(拦截通知)
需要IntroductionAdvisor和IntroductionInterceptor
仅适合用于类,不能和任何切入点一起使用
public interface IntroductionInterceptor extends MethodInterceptor{
boolean implementsInterface(Class intf);
}
public interface IntroductionAdvisor extends Advisor,IntroductionInfo{
ClassFilter getClassFilter();
void validateInterfaces() throws IllegalArgumentException;
}
public interface IntroductionInfo{
Class[] getInterfaces();
}
一个Spring test suite的例子
如果调用locked()方法,希望所有的setter方法抛出LockedException异常(如使物体不可变,AOP典型例子)
需要一个完成繁重任务的IntroductionInterceptor,这种情况下,可以使用org.springframework.aop.support.DelegatingIntroductionInterceptor
public interface Lockable{
void lock();
void unlock();
boolean locked();
}
public class LockMixin extends DelegatingIntroductionInterceptor implements Locked{
private boolean locked;
public void lock(){
this.locked = true;
}
public void unlock(){
yhis locked = false;
}
public boolean locked(){
return this.locked;
}
public Object invoke(MethodInvocation invocation)throws Throwable{
if(locked() && invocation.getMethod().getName().indexOf("set") == 0){
throw new LockedException();
}
return super.invoke(invocation);
}
}
总结:
Advisor是仅包含一个切入点表达式关联的单个通知方面
除了introductions,advisor可以用于任何通知
org.springframework.aop.support.DefaultPointcutAdvisor是最常用的advisor类,它可以与MethodInterceptor,BeforeAdvice或者ThrowsAdvice一起使用
它可以混合在Spring同一个AOP代理的advisor和advice
ProxyFactoryBean
创建Spring AOP 代理基本方法使用org.springframework.aop.ProxyFactoryBean
这可以完全控制切入点和advice以及他们顺序
使用ProxyFactoryBean或者其它IoC相关类来创建AOP代理的最重要好处是通知和切入点也可以由IoC来管理
被代理类没有实现任何接口,使用CGLIB代理,否则JDK代理
通过设置proxyTargetClass为true,可以强制使用CGLIB
如果目标类实现一个或者多个接口,那么创建代理的类型将依赖ProxyFactoryBean的配置
如果ProxyFactoryBean的proxyInterfaces属性被设置为一个或者多个全限定接口名,基于JDK的代理被创建
如果ProxyFactoryBean的proxyInterfaces属性没有被设置,但目标类实现一个或者多个接口,那么ProxyFactoryBean将自动检测到这个目标类已经实现了至少一个接口,创建一个基于JDK的代理
eg:
<bean id="personTarget" class="com.mycompany.PersonImpl>
<property name="name" value="Tony"/>
<property name="age" value="51"/>
</bean>
<bean id="myAdvisor" class="com.mycompany.MyAdvisor">
<property name="someProperty" value="Custom string property value"/>
</bean>
<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor">
</bean>
<bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
<proprty name="proxyInterfaces" value="com.mycompany.person"/>
<property name="target" ref="personTarget"/>
<property name="interceptorNames">
<list>
<value>myAdvisor</value>
<value>debugInterceptor</value>
</list>
</property>
</bean>
<bean id="personUser" class="com.mycompany.PersonUser">
<property name="person"><ref bean="person"/></property>
</bean>
使用匿名内部bean来隐藏目标和代理之间的区别
<bean id="myAdvisor" class="com.mycompany.MyAdvisor">
<property name="someProperty" value="Custom string property value"/>
</bean>
<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor">
</bean>
<bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
<proprty name="proxyInterfaces" value="com.mycompany.person"/>
<property name="target">
<bean class="com.mycompany.PersonImpl">
<property name="name" value="Tony"/>
<property name="agr" value="51"/>
</bean>
</property>
<property name="interceptorNames">
<list>
<value>myAdvisor</value>
<value>debugInterceptor</value>
</list>
</property>
</bean>
Proxying classes
CGLIB代理的工作原理是在运行时生成目标类的子类,Spring配置这个生成的子类委托方法调用到原来的目标
子类是用来实现Decorator模式,植入通知
CGLIB的代理对用户是透明,但要注意:
1.final方法不能被通知,因为它们不能被覆盖
2.不用把CGLIB添加到classpath中,在Spring3.2中,CGLIB被重新包装并包含Spring核心JAR(即基于CGLIB的AOP就像JDK动态代理一样“开箱即用”)
使用gobal advisors
用* 做通配,匹配所有拦截器加入通知链
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="servic"/>
<property name="interceptorNames">
<list>
<value>global*</value>
</list>
</property>
</bean>
<bean id="global_debug" class="org.springframework.aop.framework.DebugInterceptor"/>
<bean id="global_performance" class="org.springframework.aop.framework.PerformanceMonitorInterceptor"/>
内容来源于网络,如有侵权,请联系作者删除!