Spring AOP API

x33g5p2x  于2021-03-14 发布在 其他  
字(6.8k)|赞(0)|评价(0)|浏览(515)

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"/>
下一篇:Spring AspectJ

相关文章