Spring AOP源码分析(三)Spring AOP中的一些基本接口及其概念

本文章对一些SpringAOP的接口设计进行下介绍,主要是区分三者的关系,AOP联盟、Aspectj、SpringAOP所做的工作。 
主要内容: 
(1)Advice接口设计 
(2)MethodInterceptor接口设计 
(3)Advisor和Pointcut接口设计 
第一个:Advice接口设计 
Advice:AOP联盟定义的通知接口,即拦截到相应的方法后执行的动作。 
先看下它的类图: 

 

(1)BeforeAdvice、AfterAdvice:SpringAOP自定义的通知,用于拦截的方法之前或者之后,继承了AOP联盟的通知接口Advice。 
(2)MethodBeforeAdvice、AfterReturningAdvice:仍然是SpringAOP自己的接口设计 
MethodBeforeAdvice:继承了BeforeAdvice,但是BeforeAdvice只有这一个子类,即目前的SpringAOP只能实现对方法的拦截,不能实现对字段的拦截这种更精细的拦截,而Aspectj本身是支持这种拦截的。 
引入了接口方法: 
void before(Method method, Object[] args, Object target) throws Throwable;即在调用target的method方法之前我们可以做一些事情。 
AfterReturningAdvice:继承了AfterAdvice,引入了接口方法: 
void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;必然比上面的before方法多了一个返回值Object returnValue,使得我们可以对返回值进行操作和修改。 
(3)AspectJMethodBeforeAdvice、AspectJAfterReturningAdvice、AspectJAfterThrowingAdvice、AspectJAfterAdvice、:上面的接口设计好了,就需要来实现它,这几个类都是借助于Aspectj来完成上述的功能。 

AspectJAfterThrowingAdvice:直接实现的是AfterAdvice,它对在它之后执行的拦截器或者目标方法的负责,若抛出异常则执行它,不抛则不执行。 
AspectJAfterAdvice:则是不关心返回值,只要在后面执行就好了。 

第二个:MethodInterceptor接口设计 
再来看下MethodInterceptor这一重要接口,所有的advice都要最终转化成MethodInterceptor,它的invoke接口方法包含了拦截器要执行的内容及执行的顺序。 
如下: 

 

MethodInterceptor:是AOP联盟定义的接口,引入重要方法Object invoke(MethodInvocation invocation) throws Throwable;MethodInvocation invocation则像由一个个MethodInterceptor组成的链条(后面会进行说明),每次执行MethodInterceptor的invoke方法实现一个拦截,同时要把链条给它,以便继续执行下一个MethodInterceptor。 

(1)AspectJAfterAdvice:在mi.proceed()之后执行,如下: 

?


1

2

3

4

5

6

7

8

public Object invoke(MethodInvocation mi) throws Throwable {

        try {

            return mi.proceed();

        }

        finally {

            invokeAdviceMethod(getJoinPointMatch(), null, null);

        }

    }

AspectJAfterThrowingAdvice:在mi.proceed()抛出异常时执行如下: 

?


1

2

3

4

5

6

7

8

9

10

11

12

@Override

    public Object invoke(MethodInvocation mi) throws Throwable {

        try {

            return mi.proceed();

        }

        catch (Throwable t) {

            if (shouldInvokeOnThrowing(t)) {

                invokeAdviceMethod(getJoinPointMatch(), null, t);

            }

            throw t;

        }

    }

AspectJAroundAdvice:在mi.proceed()执行过程中执行,如: 

?


1

2

3

4

5

6

7

8

9

public Object invoke(MethodInvocation mi) throws Throwable {

        if (!(mi instanceof ProxyMethodInvocation)) {

            throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);

        }

        ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;

        ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);

        JoinPointMatch jpm = getJoinPointMatch(pmi);

        return invokeAdviceMethod(pjp, jpm, null, null);

    }

这种是环绕通知,在我们自定义的方法中可以决定是否继续执行mi.proceed(),如自定义的环绕通知 

?


1

2

3

4

5

6

7

8

public Object doAround(ProceedingJoinPoint pjp) throws Throwable { 

        long time = System.currentTimeMillis(); 

//决定是否继续链的执行

        Object retVal = pjp.proceed(); 

        time = System.currentTimeMillis() - time; 

        System.out.println("process time: " + time + " ms"); 

        return retVal; 

    }

(2)MethodBeforeAdviceInterceptor:对于上面的MethodBeforeAdvice只定义了要执行的动作,没有指定在什么时候执行,所以就需要MethodBeforeAdviceInterceptor来指定。如下: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {

 

    private MethodBeforeAdvice advice;

 

    public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {

        Assert.notNull(advice, "Advice must not be null");

        this.advice = advice;

    }

 

    @Override

    public Object invoke(MethodInvocation mi) throws Throwable {

        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );

        return mi.proceed();

    }

 

}

MethodBeforeAdviceInterceptor包含了一个MethodBeforeAdvice通知,在invoke方法中指定了该通知的执行顺序,即在mi.proceed()之前执行。 
对于AfterReturningAdviceInterceptor同理,如下: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {

 

    private final AfterReturningAdvice advice;

 

 

    /**

     * Create a new AfterReturningAdviceInterceptor for the given advice.

     * @param advice the AfterReturningAdvice to wrap

     */

    public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {

        Assert.notNull(advice, "Advice must not be null");

        this.advice = advice;

    }

 

    @Override

    public Object invoke(MethodInvocation mi) throws Throwable {

        Object retVal = mi.proceed();

        this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());

        return retVal;

    }

 

}

使得AfterReturningAdvice在mi.proceed()之后执行。 

总结:对于advice构建成MethodInterceptor,分两种情况 
(1)advice本身就实现了MethodInterceptor,如AspectJAfterAdvice、AspectJAfterThrowingAdvice、AspectJAroundAdvice。 
(2)那些没有实现MethodInterceptor的advice,如MethodBeforeAdvice、AfterReturningAdvice,则会进一步转换成MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor。这一过程又是采用适配器模式,适配器模式还是很常见的,所以要学会然后好好利用,如下面所示: 

AdvisorAdapter接口:根据advice来生成不同的MethodInterceptor 

?


1

2

3

4

5

6

7

public interface AdvisorAdapter {

 

    boolean supportsAdvice(Advice advice);

 

    MethodInterceptor getInterceptor(Advisor advisor);

 

}

这里的Advisor包含Advice,待会再给出接口说明。 
目前的AdvisorAdapter接口的实现者有三个:AfterReturningAdviceAdapter、MethodBeforeAdviceAdapter、ThrowsAdviceAdapter 
AfterReturningAdviceAdapter:支持Advice为AfterReturningAdvice如下 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

class AfterReturningAdviceAdapter implements AdvisorAdapter, Serializable {

 

    @Override

    public boolean supportsAdvice(Advice advice) {

        return (advice instanceof AfterReturningAdvice);

    }

 

    @Override

    public MethodInterceptor getInterceptor(Advisor advisor) {

        AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice();

        return new AfterReturningAdviceInterceptor(advice);

    }

 

}

如果Advisor包含的Advice为AfterReturningAdvice,则构建一个AfterReturningAdviceInterceptor(advice)作为MethodInterceptor。 
其他的同理,不再分析。 

第三个:Advisor和Pointcut接口设计 
Advisor的类图如下: 

 
Advisor接口本身只含有Advice,而PointcutAdvisor则是将Pointcut和Advice组合了起来。 
IntroductionAdvisor后面则详细介绍。 

Pointcut接口设计: 

 
Pointcut有两个属性,ClassFilter、MethodMatcher,一个用来过滤类,一个用来过滤方法。 
然后再看下Pointcut的实现类ComposablePointcut: 

?


1

2

3

4

5

6

public class ComposablePointcut implements Pointcut, Serializable {

 

    private ClassFilter classFilter;

 

    private MethodMatcher methodMatcher;

}

因为有时候ClassFilter、MethodMatcher 并不止一个,所以需要多个,也就是ComposablePointcut应该设计成List<ClassFilter>的形式,但是这样设计的话,又没法实现Pointcut接口的ClassFilter getClassFilter()方法,即到底返回哪一个ClassFilter,没法更好的描述。所以ComposablePointcut就只有一个ClassFilter,但是它实现了多个ClassFilter的功能,在Spring框架里,这种形式与写法也非常常见,所以我们应该好好学学。 
拿ClassFilter来说明: 
它有一个子类UnionClassFilter,这个UnionClassFilter里面含有一个ClassFilter[] filters数组,来存放所有的ClassFilter,如下: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

private static class UnionClassFilter implements ClassFilter, Serializable {

 

        private ClassFilter[] filters;

 

        public UnionClassFilter(ClassFilter[] filters) {

            this.filters = filters;

        }

 

        @Override

        public boolean matches(Class<?> clazz) {

            for (ClassFilter filter : this.filters) {

                if (filter.matches(clazz)) {

                    return true;

                }

            }

            return false;

        }

//略

}

UnionClassFilter更像是一个ClassFilter集合,但它也实现了ClassFilter接口,具体的实现内容则是由内部的ClassFilter[] filters数组来实现。ComposablePointcut就会使用这种形式的UnionClassFilter。可以有不断的ClassFilter往ComposablePointcut增添,但是最终只返回一个UnionClassFilter,实现Pointcut接口时只用返回UnionClassFilter即可。 
UnionClassFilter不仅具有集合的功效又实现了所需的ClassFilter功能。 

ExpressionPointcut接口继承了Pointcut,引入了我们常用的Pointcut表达式,最终的实现类AspectJExpressionPointcut则又是引入AspectJ来实现。 

时间: 2024-10-03 23:54:38

Spring AOP源码分析(三)Spring AOP中的一些基本接口及其概念的相关文章

Spring源码分析:实现AOP(转载)

这两天一直在读spring1.2的AOP实现源码,AOP实现原理说起来很简单,对于实现业务接口的对象使用java代理机制实现,而对于一般的类使用cglib库实现,但spring的实现还是比较复杂的,不过抓住了本质去看代码就容易多了.发现一篇04年写的<spring源码分析:实现AOP>,倒是不用自己再写了,04年的时候已经有很多人研读过spring的源码,而那时的我还在学校,对java半懂不懂的状态,就算到现在也不敢说真的懂了,继续学习.努力.文章如下:     我的问题        为了完

Spring AOP源码分析(八)SpringAOP要注意的地方

SpringAOP要注意的地方有很多,下面就举一个,之后想到了再列出来:  (1)SpringAOP对于最外层的函数只拦截public方法,不拦截protected和private方法,另外不会对最外层的public方法内部调用的其他方法也进行拦截,即只停留于代理对象所调用的方法.如下案例:  B类有两个public方法,foo1()和foo2(),foo1内部调用了foo2,简单如下:  ? 1 2 3 4 5 6 7 8 public void foo2() {          Syste

Spring AOP源码分析(七)ProxyFactoryBean介绍

这篇文章里面就要说说Spring自己的AOP,搞清楚哪种方式是Spring自己实现的AOP,哪种方式是Spring引入aspectj的AOP.  Spring自己的AOP实现在于ProxyFactoryBean.先看下使用案例(仍和之前的案例是一样的):接口AService.实现类AServiceImpl.通知MyBeforeAdvice  ? 1 2 3 4 5 6 public interface AService {       public void fooA(String _msg);

Spring事务源码分析(一)Spring事务入门

有时为了保证一些操作要么都成功,要么都失败,这就需要事务来保证.  传统的jdbc事务如下:  ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @Test     public void testAdd(){         Connection con=null;         try {             con=DriverManager.getConnection(url , username

QEMU1.3.0的源码分析三:user model之linux

从源码目录来看,user model有两块内容bsd-user和linux-user.我主要研究了下linux-user这种情况. 首先要提一下通常容易关注的焦点,linux-user下的函数入口点:/源码目录/linux-user/main.c中的 Line:3388    int main(int argc, char **argv, char **envp). 找到了入口函数,就可以根据这个main函数中的调用关系来看看这个情况下的主要执行流程和动作了. int main(int argc

Spring AOP源码分析(四)Spring AOP的JDK动态代理

本篇文章将会介绍上一个例子中的源码执行情况,从中熟悉整个SpringAOP的一些概念和接口设计.  首先整个SpringAOP的分两大过程.  第一个过程:根据xml文件或者注解中配置的拦截信息,生成相应的代理对象,这个代理对象包含了对应的拦截器.  第二个过程:执行所拦截的方法时,就是调用代理对象的执行逻辑,完成各种拦截.  本文章先对第二个过程进行源码解析.  对第一个过程先做简单概述,如果拦截的类的对应方法是接口方法,则使用JDK的Proxy进行代理对象的创建否则使用CGLIB进行代理对象

Spring AOP源码分析(五)Spring AOP的Cglib代理

上一篇文章介绍了Spring AOP的JDK动态代理的过程,这一篇文章就要介绍下Spring AOP的Cglib代理过程,仍然是使用上一篇文章的工程案例.  JDK动态代理是由JdkDynamicAopProxy来生成代理对象的,Cglib则是由CglibAopProxy来生成代理对象的.JdkDynamicAopProxy.CglibAopProxy实现了AopProxy接口,如下:  ? 1 2 3 4 5 6 7 public interface AopProxy {       Obje

spring cloud源码分析-zuul路由的部分源码解析

版本:spring-boot:1.5.3.RELEASE:spring cloud:Dalston.RELEASE(1.3.0.RELEASE) 路由定位器 配置所在jar包:spring-cloud-netflix-core-1.3.0.RELEASE.jar 顶层接口:RouteLocator 可刷新的路由:RefreshableRouteLocator extends RouteLocator 路由处理器:CompositeRouteLocator implements Refreshab

springboot源码分析14-ApplicationContextInitializer原理Springboot中PropertySource注解多环境支持以及原理

摘要:Springboot中PropertySource注解的使用一文中,详细讲解了PropertySource注解的使用,通过PropertySource注解去加载指定的资源文件.然后将加载的属性注入到指定的配置类,@value以及@ConfigurationProperties的使用.但是也遗留一个问题,PropertySource注解貌似是不支持多种环境的动态切换?这个问题该如何解决呢?我们需要从源码中看看他到底是否支持. 首先,我们开始回顾一下上节课说的PropertySource注解的