首页 > 代码库 > Spring源码阅读:使用标准AOP的API模拟Spring AOP + AspectJ的设计与实现

Spring源码阅读:使用标准AOP的API模拟Spring AOP + AspectJ的设计与实现

在上一篇博客中,提到了标准AOP与Spring AOP。这一篇就来把他们模拟出来。

在模拟之前,还需要提及的是,在Spring框架中,对于AOP的支持:

Spring 支持的AOP

 

AspectJ是另外一个有名的AOP框架,Spring也集成AspectJ,同时Spring AOP与AspectJ有一定程度的集成,这样一来Spring中就支持两种AOP:1)Spring AOP、2)AspectJ。而使用AOP的方式却又三种:

    1)完全使用Spring AOP

    2)完全使用AspectJ(分为注解方式、XML配置方式,这与Spring IOC有关)

    3)使用SpringAOP与AspectJ集成(其中AspectJ的配置分注解和XML两种)

 这些内容在Spring官方提供的参考文档中写的清清楚楚的。

 

采用AOP标准接口来模拟SpringAOP与AspectJ注解集成

 

注解也是自定义的,不是使用AspectJ的。

 

设计:

先看看标准AOP的API:

 

这是AOP的标准API,由AOP联盟制定,定义在aopalliance.jar中。

 

左侧:Advice代表建议,Interceptor就是一种Advice。Interceptor可以分为多种:构造拦截器,方法拦截器,字段拦截器。

右侧:JoinPoint代表连接点,其实就是执行的方法。Invocation就代表对target方法的调用,它把这个调用抽象成接口Invocation。Invocation与Interceptor呈对应关系。

 

既然AOP联盟定义了接口,我们就需要对其进行实现处理:

 

Advice的加入:可以在Interceptor的Invoke方法中加入,也可以在Invocation的proceed方法中加入。

处理方式可以参照J2EE的Filter和Struts2的ActionInvocation,因为它们都是采用这种机制。

@Before, @After 是两个自定义注解,模拟AspectJ注解。

 

 

接下来是使用JDK动态代理产生代理的设计:

 

代码实现:

1)AbstractMethodInterceptor,在AOP标准接口MethodInterceptor上扩展了两个方法。并实现了invoke方法。

package com.fjn.aop.core;import org.aopalliance.intercept.MethodInterceptor;import org.aopalliance.intercept.MethodInvocation;public abstract class AbstractMethodInterceptor implements MethodInterceptor{    public final Object invoke(MethodInvocation invocation) throws Throwable {        Object result=invocation.proceed();        return result;    }            public abstract void beforeAdvice();        public abstract void afterAdvice();    }
View Code

 

2)DefaultMethodInvocation,是对AOP标准接口MethodInvocation的实现。

package com.fjn.aop.core;import java.lang.reflect.AccessibleObject;import java.lang.reflect.Method;import java.util.List;import org.aopalliance.intercept.MethodInvocation;import com.fjn.aop.annotation.After;import com.fjn.aop.annotation.Before;import com.fjn.aop.bean.DefaultProxy;/** * 方法调用的具体实现 * @author fjn * */public class DefaultMethodInvocation implements MethodInvocation{    List<AbstractMethodInterceptor> interceptors;    private DefaultProxy proxy;    private Method method;    private Object target;    private Object[] args;    int index=0;    private boolean executed=false;        public DefaultMethodInvocation(DefaultProxy proxy, Method method, Object target, Object[] args, List<AbstractMethodInterceptor> interceptorChain){        this.interceptors=interceptorChain;        this.method=method;        this.target=target;        this.args=args;        this.proxy=proxy;    }        public Object proceed() throws Throwable {        AbstractMethodInterceptor interceptor=null;        Object result=null;        if(interceptors.size()>0 && index<interceptors.size()){            interceptor=interceptors.get(index++);            if(new AdviceMatcher(interceptor, this).match(Before.class,"beforeAdvice")){                interceptor.beforeAdvice();     //     执行前置建议            }            proceed();    //    执行下一个拦截器        }        // 执行真正的方法调用        if(!executed){            executed=true;            try {                result=method.invoke(target, args);            } catch (RuntimeException e) {                System.out.println(e.getMessage());            }        }        if(index>0){            interceptor=interceptors.get(--index);            if(new AdviceMatcher(interceptor, this).match(After.class,"afterAdvice")){                interceptor.afterAdvice();    //     执行后置建议            }        }                return result;    }    public Object getThis() {        return target;    }    public AccessibleObject getStaticPart() {        return null;    }    public Method getMethod() {        return method;    }        public DefaultProxy getProxy(){        return proxy;    }        public Object[] getArguments() {        return args;    }}
View Code

 

3)AdviceMatcher,在拦截器处理时,要判断要执行的方法是否可以被拦截器拦截。

package com.fjn.aop.core;import java.lang.reflect.Method;import org.aopalliance.intercept.MethodInvocation;import com.fjn.aop.annotation.After;import com.fjn.aop.annotation.Before;/** * method 与 PointCut 匹配器 * 支持的方法名表达式有: *  1)*xxx, 以*开头 *  2)xxx*, 以*结尾 *  3)*    所有 *  4)没有*,指定方法名 *   * @author fjn */@SuppressWarnings("rawtypes")public class AdviceMatcher {    private AbstractMethodInterceptor interceptor;    private MethodInvocation invocation;    AdviceMatcher(AbstractMethodInterceptor interceptor, MethodInvocation invocation){        this.interceptor=interceptor;        this.invocation=invocation;    }            public boolean match(Class adviceAnnotationType, String joinPoint){        // 要执行的方法        String methodName=invocation.getMethod().getName();        try {            Method adviceMethod=interceptor.getClass().getDeclaredMethod(joinPoint, new Class[]{});            if(adviceAnnotationType==Before.class){                Before before=adviceMethod.getAnnotation(Before.class);                if(before==null) return false;                String pointcut=before.expression();                return beforeOrAfterMatch(pointcut, methodName);            }else            if(adviceAnnotationType==After.class){                After after=adviceMethod.getAnnotation(After.class);                if(after==null) return false;                String pointcut=after.expression();                return beforeOrAfterMatch(pointcut, methodName);            }                    } catch (SecurityException e) {            e.printStackTrace();        } catch (NoSuchMethodException e) {            e.printStackTrace();            return false;        }        return true;    }    /**     * 支持的方法名表达式有:     *  1)*xxx, 以*开头     *  2)xxx*, 以*结尾     *  3)*    所有     *  4)没有*,指定方法名     *       * @param pointcut     * @param methodName     * @return     */    private boolean beforeOrAfterMatch(String pointcut, String methodName){        int indexOfStar=pointcut.indexOf("*");        if(indexOfStar!=-1){// 方法名中有*号            if(indexOfStar==0){// 以*开头                if("*".equals(pointcut)){// 只有*                    return true;                }                else{                    return methodName.endsWith(pointcut.substring(1));                }            }else {// 以*结尾,中间有*也算以*结尾                return methodName.startsWith(pointcut.substring(0, indexOfStar));            }        }else{            return methodName.equals(pointcut);        }    }}
View Code

 

4)两个模拟AspectJ的注解:@Before,@After

package com.fjn.aop.annotation;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(value={ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface After{    String expression() default "";}package com.fjn.aop.annotation;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(value={ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface Before {    String expression() default "";}
View Code

 

这两个注解,其实是借鉴了AspectJ的注解,但是又不想完全使用,因为与AspectJ的注解有:

    @Aspect:声明切面

    @PointCut:声明切点,设置表达式

    @Before、@After、@Around等,这些是Advice,是要引用@PointCut中的表达式的,所以为了简便,只是自定定义了两个注解,并且拥有的@PointCut定义匹配表单式的作用。

 

================================================================

 

这个分割线以上的是AOP,下面代码是通过代理相关的设计:

 

5)默认的代理DefaultProxy设计:

package com.fjn.aop.bean;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.ArrayList;import java.util.List;import com.fjn.aop.core.AbstractMethodInterceptor;import com.fjn.aop.core.DefaultMethodInvocation;public class DefaultProxy implements InvocationHandler{    Object target;    List<AbstractMethodInterceptor> interceptorChain=new ArrayList<AbstractMethodInterceptor>();        public DefaultProxy(Object target, List<AbstractMethodInterceptor> interceptorChain){        this.target=target;        if(interceptorChain!=null && interceptorChain.size()>0){            this.interceptorChain.addAll(interceptorChain);        }    }        public final Object invoke(Object proxy, Method method, Object[] args)            throws Throwable {        DefaultMethodInvocation methodInvocation=new DefaultMethodInvocation(this, method, target, args, interceptorChain);        return methodInvocation.proceed();    }        public Object getProxy(){        Object proxy=null;        try {            proxy=Proxy.newProxyInstance(DefaultProxy.class.getClassLoader(), target.getClass().getInterfaces(), this);        } catch (Exception e) {            e.printStackTrace();        }        return proxy;    }        public Object getTarget(){        return target;    }    }
View Code

在invoke()内部会与AOP衔接起来。

 

6)模拟ProxyBeanFactory:

package com.fjn.aop.bean;import java.util.List;import com.fjn.aop.core.AbstractMethodInterceptor;import com.fjn.aop.exception.NotFoundInterfaceException;@SuppressWarnings("rawtypes")/** * 单例的ProxyBeanFactory * @author Administrator * */public class ProxyBeanFactory {    private ProxyBeanFactory(){}        private static ProxyBeanFactory beanFactory=null;        public synchronized static ProxyBeanFactory getBeanFactory(){        if (beanFactory==null) {            beanFactory=new ProxyBeanFactory();        }        return beanFactory;    }        /**     *      * @param targetClazz 创建指定类target实例     * @param chain 系统的拦截器链     * @return     */    public Object createProxy(Class targetClazz,List<AbstractMethodInterceptor> chain){        Object proxyBean=null;        if(targetClazz.getInterfaces().length==0){            throw new NotFoundInterfaceException(targetClazz);        }        try {            Object target=targetClazz.newInstance();            proxyBean=new DefaultProxy(target, chain).getProxy();            } catch (InstantiationException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        }        return proxyBean;    }        public Object createProxy(Object target,List<AbstractMethodInterceptor> chain){        Object proxyBean=null;        if(target.getClass().getInterfaces().length==0){            throw new NotFoundInterfaceException(target.getClass());        }        proxyBean=new DefaultProxy(target, chain).getProxy();        return proxyBean;    }}
View Code

 

可以根据Target.class,也可以根据target对象,来创建代理动态代理对象,返回值就是动态代理对象。

参数中的List< AbstractMethodInterceptor> 就相当于系统中配置好的那些拦截器。

 

==============================================================

 

测   试

有了这些以后,基本上就成型了,现在可以做测试了:

 

Target设计:

    因为使用的Java动态代理,所以必须得为Target设计接口。

package com.fjn.aop;public interface TargetInterface {    void helloAop(String str);    void noUseAop(String str);}package com.fjn.aop;import com.fjn.aop.TargetInterface;/** * Target可以是Service层,也可以是DAO层 * @author fjn */public class Target implements TargetInterface{        public void helloAop(String str) {        System.out.println("hello, "+str+ ", welcome you use aop in your application");    }        public void noUseAop(String str){        System.out.println("hello, "+str+ ", the method has‘t use AOP .");    }}
View Code

 

 

接下来设计两个拦截器,要作为系统拦截器配置:

LoggingInterceptor:

package com.fjn.aop.interceptor;import com.fjn.aop.annotation.After;import com.fjn.aop.annotation.Before;import com.fjn.aop.core.AbstractMethodInterceptor;public class LoggingInterceptor extends AbstractMethodInterceptor{    @Before(expression="hello*")    public void beforeAdvice(){        System.out.println("Logging: before advice invoked ...");    }    @After(expression="*Aop")    public void afterAdvice(){        System.out.println("Logging: after advice invoked ...");    }    }
View Code

这个类中的两个建议说明:

beforeAdvice,只能匹配到方法名是以hello开头的。

afterAdvice,只能匹配到方法名以Aop结尾的。

 

AnotherInterceptor:

package com.fjn.aop.interceptor;import com.fjn.aop.annotation.After;import com.fjn.aop.annotation.Before;import com.fjn.aop.core.AbstractMethodInterceptor;public class AnotherInterceptor extends AbstractMethodInterceptor{    @Override    @After(expression="*")    public void afterAdvice() {        System.out.println("another: after");    }        @Override    @Before(expression="*")    public void beforeAdvice() {        System.out.println("another: before");    }}
View Code

*表示所有方法都匹配。所以系统中如果使用这个拦截器,所有的方法调用时,都要用到这 两个advice。

 

 

现在就可以写测试用例了:

package com.fjn.aop;import java.util.ArrayList;import java.util.List;import com.fjn.aop.bean.ProxyBeanFactory;import com.fjn.aop.core.AbstractMethodInterceptor;import com.fjn.aop.interceptor.AnotherInterceptor;import com.fjn.aop.interceptor.LoggingInterceptor;public class Client {    public static void main(String[] args) {        // 初始化配置的拦截器链。        // 这里【相当于】Spring的在XML文件中配置AOP或者在拦截器上指定@AspectJ        List<AbstractMethodInterceptor> interceptorChain=new ArrayList<AbstractMethodInterceptor>();        interceptorChain.add(new LoggingInterceptor());        interceptorChain.add(new AnotherInterceptor());                // 这里相当于Spring的通过IOC创建的代理Bean        TargetInterface target=(TargetInterface)ProxyBeanFactory.getBeanFactory().createProxy(Target.class, interceptorChain);                // 我们在使用Spring时,只需要写下面的代码就可以了:        target.helloAop("zhang san");        System.out.println("--------------------------");        target.noUseAop("zhang san");        System.out.println("--------------------------");        target.helloAop("zhang san");            }}

 

上面的程序执行结果:

 

Logging: before advice invoked ...another: beforehello, zhang san, welcome you use aop in your applicationanother: afterLogging: after advice invoked ...--------------------------another: beforehello, zhang san, the method has‘t use AOP .another: afterLogging: after advice invoked ...--------------------------Logging: before advice invoked ...another: beforehello, zhang san, welcome you use aop in your applicationanother: afterLogging: after advice invoked ...

 

 

程序执行的流程如下:

1-3 :获取target的代理对象,中间过程使用的是JDK的动态代理。

4-16:target.xxMethod执行其实就是在Proxy的invoke方法内部调用MethodInvocation.proceed()的过程。

而proceed执行就是一个拦截器连执行的过程。

 

以上,就是模拟的SpringAOP流程了。