Spring中的AOP面向切面编程

AOP从理论到实践(一) 
Spring中的面向切面编程
spring IOC 和 AOP 依赖注入和 面向切面编程 

Spring AOP源码分析(拦截器调用的实现)


AOP从理论到实践(一) 

标签: springaop面向切面
  118人阅读  评论(5)  收藏  举报
  分类:
 
 

背景:

AOP(Aspect-Oriented Programming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。简单地说,AOP就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。

实现原理:

AOP 代理其实是由 AOP 框架动态生成的一个对象,该对象可作为目标对象使用。AOP 代理包含了目标对象的全部方法,但 AOP 代理中的方法与目标对象的方法存在差异:AOP 方法在特定切入点添加了增强处理,并回调了目标对象的方法。纵观 AOP 编程,其中需要程序员参与的只有 3 个部分:定义普通业务组件定义切入点,一个切入点可能横切多个业务组件。定义增强处理,增强处理就是在 AOP 框架为普通业务组件织入的处理动作。 
以上三部分重点就是定义切入点和增强处理,不难发现spring AOP的实现原理就是:AOP 框架负责动态地生成 AOP 代理类,这个代理类的方法则由 Advice 和回调目标对象的方法所组成。

从历史到现代

写死代码

我们每研究一个技术,总是会从最简单,最常用的例子开始,下面看看这个例子: 
接口:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">package com.service;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">interface</span> Greeting {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> sayHello(String name);
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>

实现类:

<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">package</span> com.serviceImp;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> com.service.Greeting;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">GreetingImpl</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Greeting</span> {</span>

    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">sayHello</span>(String name) {
        before();
        after();
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">before</span>(){
        System.out.print(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Before"</span>);;
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">after</span>(){
        System.out.println(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"After"</span>);
    }
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li></ul>

before() 与 after() 方法写死在 sayHello() 方法体中了,这样的代码的味道非常不好。如果哪位仁兄大量写了这样的代码,肯定要被你的架构师骂个够呛。

比如:我们要统计每个方法的执行时间,以对性能作出评估,那是不是要在每个方法的一头一尾都做点手脚呢?

再比如:我们要写一个 JDBC 程序,那是不是也要在方法的开头去连接数据库,方法的末尾去关闭数据库连接呢?

这样的代码只会把程序员累死,把架构师气死!

一定要想办法对上面的代码进行重构,首先给出三个解决方案:

静态代理:

在上面的基础上添加代理类:

<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">package</span> com.serviceImp;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> com.service.Greeting;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">GreetingProxy</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Greeting</span> {</span>

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> GreetingImpl greetingImpl;

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">GreetingProxy</span>(GreetingImpl greetingImpl){
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.greetingImpl=greetingImpl;
    }
    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">sayHello</span>(String name) {
        before();
        greetingImpl.sayHello(name);
        after();

    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">before</span>(){
        System.out.println(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Before"</span>);
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">after</span>(){
        System.out.println(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"After"</span>);
    }

}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li></ul>

客户端调用:

<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> com.service.Greeting;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> com.serviceImp.GreetingImpl;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> com.serviceImp.GreetingProxy;


<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Client</span> {</span>

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">main</span>(String[] args) {
        Greeting greetingProxy=<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> GreetingProxy(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> GreetingImpl());
        greetingProxy.sayHello(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"jack"</span>);
    }

}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul>

问题: 
但是如果这样没增加一个类就增加一个代理类,岂不是有n个类等着我们去添加呢?可不可以用一个代理类呢?于是我们想到了jdk动态代理

jdk动态代理:

<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">package</span> com.jdkProxy;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.lang.reflect.InvocationHandler;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.lang.reflect.Method;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.lang.reflect.Proxy;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">JDKDynamicProxy</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">InvocationHandler</span>{</span>

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> Object target;

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">JDKDynamicProxy</span>(Object target){
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.target=target;
    }

    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@SuppressWarnings</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"unchecked"</span>)
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <T>T <span class="hljs-title" style="box-sizing: border-box;">getProxy</span>(){
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>(T)Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>);
    }

    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Object <span class="hljs-title" style="box-sizing: border-box;">invoke</span>(Object proxy, Method method, Object[] args)
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Throwable {
        before();
        Object result=method.invoke(target, args);
        after();
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> result;
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">before</span>(){
        System.out.println(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Before"</span>);
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">after</span>(){
        System.out.println(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"After"</span>);
    }

}
</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li></ul>

客户端:

<code class="hljs actionscript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"><span class="hljs-keyword" style="box-sizing: border-box;">import</span> com.jdkProxy.JDKDynamicProxy;</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"><span class="hljs-keyword" style="box-sizing: border-box;">import</span> com.service.Greeting;</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"><span class="hljs-keyword" style="box-sizing: border-box;">import</span> com.serviceImp.GreetingImpl;</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"><span class="hljs-keyword" style="box-sizing: border-box;">import</span> com.serviceImp.GreetingProxy;</span>


<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Client</span> {</span>

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> main(String[] args) {
        Greeting greetingProxy=<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> JDKDynamicProxy(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> GreetingImpl()).getClass();
        greetingProxy.sayHello(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"jack"</span>);
    }

}
</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul>

问题:jdk代理只能代理有接口的,因此可以说,如果要用jdk动态代理的,我们所有的类都必须有接口,但是在实际中并不是这样的,因此我们引用了另一种方式:CGLib动态代理

CGLib动态代理

<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">package</span> com.CGLibProxy;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.lang.reflect.Method;


<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> net.sf.cglib.proxy.Enhancer;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> net.sf.cglib.proxy.MethodInterceptor;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> net.sf.cglib.proxy.MethodProxy;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">CGLibDynamicProxy</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">MethodInterceptor</span>{</span>

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> CGLibDynamicProxy instance=<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> CGLibDynamicProxy();
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-title" style="box-sizing: border-box;">CGLibDynamicProxy</span>(){

    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> CGLibDynamicProxy <span class="hljs-title" style="box-sizing: border-box;">getInstance</span>(){
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> instance;
    }
    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@SuppressWarnings</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"unchecked"</span>)
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <T>T <span class="hljs-title" style="box-sizing: border-box;">getProxy</span>(Class<T> cls){
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> (T) Enhancer.create(cls,<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>);
    }
    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Object <span class="hljs-title" style="box-sizing: border-box;">intercept</span>(Object target, Method method, Object[] arg2,
            MethodProxy proxy) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Throwable {
        before();
        Object result=proxy.invokeSuper(target, arg2);
        after();
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> result;
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">before</span>(){
        System.out.println(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Before"</span>);
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">after</span>(){
        System.out.println(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"After"</span>);
    }

}
</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li></ul>

客户端调用:

<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">import <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">com</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.CGLibProxy</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.CGLibDynamicProxy</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
import <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">com</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.jdkProxy</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.JDKDynamicProxy</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
import <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">com</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.service</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Greeting</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
import <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">com</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.serviceImp</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.GreetingImpl</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
import <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">com</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.serviceImp</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.GreetingProxy</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>


public class Client {

    public static void main(String[] args) {
        Greeting greetingProxy=CGLibDynamicProxy<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getInstance</span>()<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getProxy</span>(GreetingImpl<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.class</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
        greetingProxy<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.sayHello</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"jack"</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
    }

}
</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>

到此,这样实现是否就足够优雅了呢?不同的方法使用的场景不同,每种方法都有属于自己的那个舞台~

Spring中的AOP

  1668人阅读  评论(10)  收藏  举报
  分类:
 

    在上一篇博客中,我们讲了spring的IOC,下面,我们继续讲解Spring的另一个核心AOP

AOP:

    在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP也是Action Oriented Programming 的缩写,意为:面向切面编程,是函数式编程的一种衍生范型。AOP在其他领域也有其他含义。

AOP的详解:

    还是老规矩,站在巨人的肩膀上,看看其他人对AOP的理解:

    手动模拟AOP

    深入浅出Spring(三)AOP详解

动态代理——JDK和CGlib

为什么需要CGlib

    以上两个例子都是应用JDK动态代理实现的AOP,但是,我们知道Spring给我们提供了两种实现代理的方式,一种是JDK的动态代理,还有一种是CGlib的动态代理,那么,为什么要提供CGlib代理呢?

    使用JDK创建代理有一个限制,即它只能为接口创建代理实例,这一点我们可从Proxy的接口newProxyInstance(CIassLoader loader,Class[] interfaces,InvocationHandIer h)的方法签名中就看得很清楚:第二个入参interfaces就是需要代理实例实现的接口列表。虽然而向接口编程的思想被很多大师级人物(包括RodJohnson)推崇,但在实际开发中,许多开发者也对此深感困惑:难道对一个简单业务表的操作也需要老老实实地创建5个类(领域对象类、Dao接口,Dao实现类,Service接口和service实现类)吗?难道不能直接通过实现类构建程序吗?对于这个问题,我们很难给出一个孰好孰劣的准确判断,但我们确实发现有很多不使用接口的项目也取得了非常好的效果(包括大家所熟悉的SpringSide开源项目)。

    对于没有通过接口定义业务方法的类,如何动态创建代理实例呢?JDK的代理技术显然己经黔驴技穷,CGLib作为一个替代者,填补了这个空缺。

CGLib实现动态代理

    CGLib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,并顺势织入横切逻辑。

    因为和JDK动态代理原理一样,所以这里简单的写一下代理类的实现:

[html]  view plain  copy
  1. packagecom.proxy.spring;  
  2. importjava.lang.reflect.Method;  
  3. importnet.sf.cglib.proxy.Enhancer;  
  4. importnet.sf.cglib.proxy.MethodInterceptor;  
  5. importnet.sf.cglib.proxy.MethodProxy;  
  6.    
  7. publicclass CglibProxy implements MethodInterceptor {  
  8.    
  9.     private Enhancer enhancer = new Enhancer();  
  10.      
  11.     public Object getProxy(Class clazz){  
  12.         enhancer.setSuperclass(clazz);  
  13.         enhancer.setCallback(this);  
  14.         return enhancer.create();  
  15.     }  
  16.      
  17.     @Override  
  18.     public Object intercept(Object obj, Methodmethod, Object[] args,  
  19.             MethodProxy proxy) throws Throwable{  
  20.         System.out.println(obj.getClass().getName()+"."+method.getName());  
  21.         Objectresulet=proxy.invokeSuper(obj,args);  
  22.         System.out.println("========end===================");  
  23.         return resulet;  
  24.             }  
  25. }  


 JDK和CGlib的差异:

    JDK和CGlib除了在是否使用接口上的差异以外,在性能上也有一定的差异,理解这些差异,可以让我们更好的使用它们:

    JDK动态代理所创建的代理对象,在JDK1.3下,性能强差人意,虽然在高版本的JDK中,动态代理对象的性能得到了很大的提高,但是有研究表明,CGLib所创建的动态代理对象的性能依旧比JDK的所创建的代理对象的性能高不少(大概10倍)。但CGLib在创建代理对象时所花费的时间却比JDK动态代理多(大概8倍),所以对于singleton的代理对象或者具有实例池的代理因为无须频繁创建代理对象,所以比较适合用CGLib动态代理技术,反之适合用JDK动态代理技术,值得一提的是,由于CGLib采用动态创建子类的方式生成代理对象,所以不能对目标类中的final,private等方法进行代理。

Spring中的AOP

JDK和CGlib的一些缺陷

    但是,以上我们说来说去,一直在说动态代理,虽然动态代理实现了AOP,但是,我们想一下我们实际的应用,就会发现有很多问题,当然,Spring AOP就是基础这些问题创建的:

    1)目标类的所有方法都添加了性能监视横切逻辑,而有时,这并不是我们所期望的,我们可能只希望对业务类中的某些特定方法添加横切逻辑;

    2)我们通过硬编码的方式指定了织入横切逻辑的织入点,即在目标类业务方法的开始和结東前织入代码;

    3)我们手工编写代理实例的创建过程,为不同类创建代理时,需要分别编写相应的程序代码,无法做到通用。

 Spring的解决方案    

    以上三个问题,在AOP中占用重要的地位,因为SpringAOP的主要工作就是围绕以上三点展开;SpringAOP通过Pointcut(切点)指定在哪些类的哪些方法上织入横切逻辑,通过Advice(增强)描述横切逻辑和方法的具体织入点(方法前、方法后、方法的两端等)。此外,Spring通过Advisor(切面)将Pointcut和Advice两者组装起来。有了Advisor的信息,Spring就可以利用JDK或CGLib的动态代理技术采用统一的方式为目标Bean创建织入切面的代理对象了。

Spring中的AOP与IOC

    在Spring容器里,我们可以发现,Spring容器包含各种增强类,比如前置增强,后置增强,环绕增强等,还有各种切点,切面,以解决上述动态代理所存在的一些问题,其实如何解决这些问题我们暂且不研究(研究起来可能就不是一篇博客可以写得完的了),总之,Spring已经把这些类都已经写好了,现在要使用这些东西,比如我们需要在一个add方法前面插入验证,那么我们应该怎么做呢?如果我们没有接触过Spring,一定会这样想,那就在和之前使用JDK或者CGlib动态代理一样直接调用不就好了吗:

[html]  view plain  copy
  1. MyProxy hander = new MyProxy();   
  2.      Animal dog = (Animal)hander.createProxyInstance(new Dog());   
  3.      dog.run();   
  4.      dog.jump();   


这里我们很容易发现,代理已经和被代理的类耦合在一起了,这里我们就发现,我们伟大的IOC就需要出现来了,我们只需要把他们交给第三方来实现解耦合就可以了。

IOC和AOP如何是Spring变得强大

其实,最后这段话是我之前一直都没有想过的,因为之前一直在强调Spring的核心是IOC和AOP,只是在想IOC是什么?AOP是什么?从来没有把他们关联起来想,其实,从这里我们就可以看出,Spring的AOP其实是构建于IOC之上,和IoC浑然天成统一于Spring的容器之中,也就是说,如果没有Spring IOC,AOP是无法发挥他的强大的作用的,当然,如果没有Spring  AOP,IOC还是有很多问题无法解决,同时,我们在想一下Spring的其他技术,比如事务,我们应该对事务比较清楚,Spring的事务就是被AOP到Spring中的,当然,还有比如对比如JDBC、hibernate等的集成其实都是在Spring IOC的基础上开花结果的。其实如果这样想下去,Spring的学习,就变成使用IOC或者AOP对已经存在的类的整合,随便什么类,反正拿过来控制依赖注入一下,或者是当切进去就可以为我们所用了,如果从这个角度看Spring,是不是就发现Spring变得简单而强大了!

Spring中的面向切面编程

标签: spring编程aopreturningexceptionobject
  11861人阅读  评论(1)  收藏  举报
  分类:
 

一.  为什么要面向切面编程( Aspect Oriented Programming ),或者说为什么要用切面?

想象这样一个场景:一个项目起初开发的时候没有考虑日志功能,而是在最后想为每个业务方法加上记录日志的功能。

如果遇到这样的情况,是不是真的要重新编写每一个业务方法,给它们加上日志功能呢?

如果这样还不能说明面向切面编程的必要性,那么在考虑一个场景:一个项目由两个项目组完成,A 组负责的是业务方法,B 组负责的是加一些日志、安全、事务、缓存等额外功能,B 组拿到的是A 组已经编译好了的类文件,这时再想修改源代码很显然是不显示的了。而面向切面编程就可以解决这样的问题。

 

面向切面编程(简称AOP )的目标:

1.      把横切关注点从业务逻辑中分离,独立模块化

2.      在不改变现有代码的前提下,动态的添加功能

 

二.spring 框架中如何使用AOP ?

       方法一:Spring 经典的AOP 实现

1.      实现MethodInceptor 接口,在其invoke() 方法中定义行为(Advice )

2.      使用ProxyFactoryBean 生成代理

<bean id="factoryBean"

class="org.springframework.aop.framework.ProxyFactoryBean">

       <property name="target" ref=” 目标对象”></property>

              <property name="interceptorNames">

               <list> 切面列表</list>

        </property>

</bean>

       方法二:利用Spring 提供的自动代理生成器

自动代理生成器其实是在方法一的基础上再次封装,为我们提供了更强大的功能,同时操作也更方便。

特点:完全基于XML 配置;能够使用AspectJ 的切点表达式。

示例:

1.      配置文件中添加aop 命名空间,完整的根节点定义如下:

<beans

xmlns="http://www.springframework.org/schema/beans"

xmlns:aop="http://www.springframework.org/schema/aop"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.0.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

                     </beans>

2. 添加如下配置:

  <aop:config>

<aop:pointcut id="pc"

  expression="within( 选择要切的类)"/>

                            <aop:aspect ref=" 切面">

                            <aop:before pointcut-ref="pc" method=" 切面中的方法"/>

                            </aop:aspect>

</aop:config>

                     除了aop:before 外,还有多种Advice

                     before 表示 切面在切点之前;

                     after-returning 表示 切点方法执行完毕成功返回后执行切面方法;

                     after-throwing 表示 切点方法抛出异常时执行切面方法;

                     after 表示 无论切点方法是否成功返回,都执行切面方法;

around 表示 切点方法执行期间执行切面方法,也就是自定义执行顺

序。

around 对方法有如下要求:

1, 返回类型Object

2, 参数ProceedingJoinPoint

3,throws Throwable

 

              AspectJ 切点表达式:

                     within: 匹配类内的所有方法(必须是实现类,不能是接口)

                     如 :within(first.Singer)

                     execution: 匹配指定的方法

                     execution(void perform()) 匹配项目下所有该方法

                     execution(void first.Singer.perform()) 匹配具体到某个类的该方法

                     execution(* first.Artist.perform()) 不考虑返回值类型

                     execution(* first.Artist.perform(..)) 不考虑返回值类型和参数列表

                     execution(* first.Aritst.perform(*,*)) 参数必须是两个

                     execution(* first.Artist.perform(..,Java.lang.String))

                     execution(* find*(..)) 所有方法名符合findXxx 的方法

                     execution(* com.tarena.service.StoreService.*(..)) 该类中所有方法

                     execution(* com.tarena.service.*.*(..)) 该包中所有类的所有方法

                     execution(* com.tarena..*.*(..)) 该包及其子包中所有类的所有方法

                  条件运算符:not and or

                     within(first.service.StoreService) or       execution(* first.dao.*.*(..))

三.切面方法中如何获得切点信息?

around 对方法要求有参数ProceedingJoinPoint ,所以可以很容易的获得切点对象的相关信息。那么after, before 等其他的切面类型对方法没有这样的要求,该怎么获得切点信息呢?

对于这些方法,可以直接为其添加JoinPoint 参数,这样就可以获得

       方法对象,参数列表,目标对象,代理对象 的信息。

返回值和异常则可以直接接受,然后在配置中添加属性即可。例如:

方法签名为:public void after(JoinPoint jp, Object res, Exception e)

配置信息为:<aop:after-returning returning="res" …> 则在方法中可以直接使用切点方法返回的对象res ;同样 < aop:after-throwing throwing="e"…> ,在方法中也可以直接接收到异常对象。

使用Spring进行面向切面编程(AOP)

简介

面向切面编程AOP)提供另外一种角度来思考程序结构,通过这种方式弥补了面向对象编程(OOP)的不足。 除了类(classes)以外,AOP提供了 切面。切面对关注点进行模块化,例如横切多个类型和对象的事务管理。 (这些关注点术语通常称作 横切(crosscutting) 关注点。)

Spring的一个关键的组件就是 AOP框架。 尽管如此,Spring IoC容器并不依赖于AOP,这意味着你可以自由选择是否使用AOP,AOP提供强大的中间件解决方案,这使得Spring IoC容器更加完善。

Spring中所使用的AOP:

  • 提供声明式企业服务,特别是为了替代EJB声明式服务。 最重要的服务是 声明性事务管理(declarative transaction management) , 这个服务建立在Spring的抽象事务管理(transaction abstraction)之上。

  • 允许用户实现自定义的切面,用AOP来完善OOP的使用。

这样你可以把Spring AOP看作是对Spring的一种增强,它使得Spring可以不需要EJB就能提供声明式事务管理;或者也可以使用Spring AOP框架的全部功能来实现自定义的切面。

本章首先 介绍了AOP的概念,无论你打算采用哪种风格的切面声明,这个部分都值得你一读。 本章剩下的部分将着重于Spring 2.0对AOP的支持; 下一章 提供了关于Spring 1.2风格的AOP概述,也许你已经在其他书本,文章以及已有的应用程序中碰到过这种AOP风格。

如果你只打算使用通用的声明式服务或者预先打包的声明式中间件服务,例如缓冲池(pooling), 那么你不必不直接使用Spring AOP,而本章的大部分内容也可以直接跳过。  6.1.1. AOP概念

首先让我们从定义一些重要的AOP概念开始。这些术语不是Spring特有的。 不幸的是,Spring术语并不是特别的直观;如果Spring使用自己的术语,将会变得更加令人困惑。

  • 切面(Aspect): 一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。 在Spring AOP中,切面可以使用通用类(基于模式的风格) 或者在普通类中以 @Aspect 注解(@AspectJ风格)来实现。

  • 连接点(Joinpoint): 在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。 在Spring AOP中,一个连接点 总是 代表一个方法的执行。 通过声明一个 org.aspectj.lang.JoinPoint 类型的参数可以使通知(Advice)的主体部分获得连接点信息。

  • 通知(Advice): 在切面的某个特定的连接点(Joinpoint)上执行的动作。通知有各种类型,其中包括“around”、“before”和“after”等通知。 通知的类型将在后面部分进行讨论。许多AOP框架,包括Spring,都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链。

  • 切入点(Pointcut): 匹配连接点(Joinpoint)的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时)。 切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法。

  • 引入(Introduction): (也被称为内部类型声明(inter-type declaration))。声明额外的方法或者某个类型的字段。 Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。 例如,你可以使用一个引入来使bean实现 IsModified 接口,以便简化缓存机制。

  • 目标对象(Target Object): 被一个或者多个切面(aspect)所通知(advise)的对象。也有人把它叫做 被通知(advised)对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个 被代理(proxied) 对象。

  • AOP代理(AOP Proxy): AOP框架创建的对象,用来实现切面契约(aspect contract)(包括通知方法执行等功能)。 在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。 注意:Spring 2.0最新引入的基于模式(schema-based)风格和@AspectJ注解风格的切面声明,对于使用这些风格的用户来说,代理的创建是透明的。

  • 织入(Weaving): 把切面(aspect)连接到其它的应用程序类型或者对象上,并创建一个被通知(advised)的对象。 这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。 Spring和其他纯Java AOP框架一样,在运行时完成织入。

通知的类型:

  • 前置通知(Before advice): 在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。

  • 返回后通知(After returning advice): 在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。

  • 抛出异常后通知(After throwing advice): 在方法抛出异常退出时执行的通知。

  • 后通知(After (finally) advice): 当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。

  • 环绕通知(Around Advice): 包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。

环绕通知是最常用的一种通知类型。大部分基于拦截的AOP框架,例如Nanning和JBoss4,都只提供环绕通知。

跟AspectJ一样,Spring提供所有类型的通知,我们推荐你使用尽量简单的通知类型来实现需要的功能。 例如,如果你只是需要用一个方法的返回值来更新缓存,虽然使用环绕通知也能完成同样的事情, 但是你最好使用After returning通知而不是环绕通知。 用最合适的通知类型可以使得编程模型变得简单,并且能够避免很多潜在的错误。 比如,你不需要调用 JoinPoint(用于Around Advice)的 proceed() 方法,就不会有调用的问题。

在Spring 2.0中,所有的通知参数都是静态类型,因此你可以使用合适的类型(例如一个方法执行后的返回值类型)作为通知的参数而不是使用一个对象数组。

切入点(pointcut)和连接点(join point)匹配的概念是AOP的关键,这使得AOP不同于其它仅仅提供拦截功能的旧技术。 切入点使得定位通知(advice)可独立于OO层次。 例如,一个提供声明式事务管理的around通知可以被应用到一组横跨多个对象中的方法上(例如服务层的所有业务操作)。

6.1.2. Spring AOP的功能和目标

Spring AOP用纯Java实现。它不需要专门的编译过程。Spring AOP不需要控制类装载器层次,因此它适用于J2EE web容器或应用服务器。

Spring目前仅支持使用方法调用作为连接点(join point)(在Spring bean上通知方法的执行)。 虽然可以在不影响到Spring AOP核心API的情况下加入对成员变量拦截器支持,但Spring并没有实现成员变量拦截器。 如果你需要把对成员变量的访问和更新也作为通知的连接点,可以考虑其它语法的Java语言,例如AspectJ。

Spring实现AOP的方法跟其他的框架不同。Spring并不是要尝试提供最完整的AOP实现(尽管Spring AOP有这个能力), 相反的,它其实侧重于提供一种AOP实现和Spring IoC容器的整合,用于帮助解决在企业级开发中的常见问题。

因此,Spring AOP通常都和Spring IoC容器一起使用。 Aspect使用普通的bean定义语法(尽管Spring提供了强大的“自动代理(autoproxying)”功能): 与其他AOP实现相比这是一个显著的区别。有些事使用Spring AOP是无法轻松或者高效的完成的,比如说通知一个细粒度的对象。 这种时候,使用AspectJ是最好的选择。不过经验告诉我们: 于大多数在J2EE应用中遇到的问题,只要适合AOP来解决的,Spring AOP都没有问题,Spring AOP提供了一个非常好的解决方案。

Spring AOP从来没有打算通过提供一种全面的AOP解决方案来取代AspectJ。 我们相信无论是基于代理(proxy-based )的框架比如说Spring亦或是full-blown的框架比如说是AspectJ都是很有价值的,他们之间的关系应该是互补而不是竞争的关系。 Spring 2.0可以无缝的整合Spring AOP,IoC 和AspectJ,使得所有的AOP应用完全融入基于Spring的应用体系。 这样的集成不会影响Spring AOP API或者AOP Alliance API;Spring AOP保留了向下兼容性。接下来的一章会详细讨论Spring AOP API。

6.1.3. Spring的AOP代理

Spring缺省使用J2SE 动态代理(dynamic proxies)来作为AOP的代理。这样任何接口都可以被代理。

Spring也支持使用CGLIB代理. 对于需要代理类而不是代理接口的时候CGLIB代理是很有必要的。 如果一个业务对象并没有实现一个接口,默认就会使用CGLIB。 此外,面向接口编程 也是一个最佳实践,业务对象通常都会实现一个或多个接口。

此外,还可以强制的使用CGLIB:我们将会在以后讨论这个问题,解释问什么你会要这么做。

在Spring 2.0之后,Spring可能会提供多种其他类型的AOP代理,包括了完整的生成类。这不会影响到编程模型。

6.2. @AspectJ支持

如果你使用Java 5的话,推荐使用Spring提供的@AspectJ切面支持,通过这种方式声明Spring AOP中使用的切面。 "@AspectJ"使用了Java 5的注解,可以将切面声明为普通的Java类。 AspectJ 5发布的 AspectJ project 中引入了这种@AspectJ风格。 Spring 2.0 使用了和AspectJ 5一样的注解,使用了AspectJ 提供的一个库来做切点(pointcut)解析和匹配。 但是,AOP在运行时仍旧是纯的Spring AOP,并不依赖于AspectJ 的编译器或者织入器(weaver)。

使用AspectJ的编译器或者织入器(weaver)的话就可以使用完整的AspectJ 语言,我们将在 Section 6.7, “在Spring应用中使用AspectJ” 中讨论这个问题。  6.2.1. 启用@AspectJ支持

为了在Spring配置中使用@AspectJ aspects,你必须首先启用Spring对基于@AspectJ aspects的配置支持,自动代理(autoproxying)基于通知是否来自这些切面。 自动代理是指Spring会判断一个bean是否使用了一个或多个切面通知,并据此自动生成相应的代理以拦截其方法调用,并且确认通知是否如期进行。

通过在你的Spring的配置中引入下列元素来启用Spring对@AspectJ的支持:

<aop:aspectj-autoproxy/>

我们假使你正在使用 Appendix A, XML Schema-based configuration 所描述的schema支持。 关于如何在aop的命名空间中引入这些标签,请参见 Section A.2.6, “The aop schema”

如果你正在使用DTD,你仍旧可以通过在你的application context中添加如下定义来启用@AspectJ支持:

<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />

你需要在你的应用程序的classpath中引入两个AspectJ库:aspectjweaver.jar 和 aspectjrt.jar。 这些库可以在AspectJ的安装包(1.5.1或者之后的版本)中的 lib 目录里找到,或者也可以在Spring依赖库的 lib/aspectj 目录下找到。

6.2.2. 声明一个切面

在启用@AspectJ支持的情况下,在application context中定义的任意带有一个@Aspect切面(拥有 @Aspect 注解)的bean都将被Spring自动识别并用于配置在Spring AOP。 以下例子展示了为了完成一个不是非常有用的切面所需要的最小定义:

下面是在application context中的一个常见的bean定义,这个bean指向一个使用了 @Aspect 注解的bean类:

   
   
< bean  id ="myAspect"  class ="org.xyz.NotVeryUsefulAspect" >     <!--  configure properties of aspect here as normal  --> </ bean >

下面是 NotVeryUsefulAspect 类定义,使用了 org.aspectj.lang.annotation.Aspect 注解。

 

package org.xyz;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public  class NotVeryUsefulAspect  {

}


切面(用 @Aspect 注解的类)和其他类一样有方法和字段定义。他们也可能包括切入点,通知和引入(inter-type)声明。

6.2.3. 声明一个切入点(pointcut)

回想一下,切入点决定了连接点关注的内容,使得我们可以控制通知什么执行。 Spring AOP只支持Spring bean方法执行连接点。所以你可以把切入点看做是匹配Spring bean上的方法执行。 一个切入点声明有两个部分:一个包含名字和任意参数的签名,还有一个切入点表达式,该表达式决定了我们关注那个方法的执行。 在@AspectJ中,一个切入点实际就是一个普通的方法定义提供的一个签名,并且切入点表达式使用 @Pointcut注解来表示。 这个方法的返回类型必须是 void。 如下的例子定义了一个切入点'transfer',这个切入点匹配了任意名为"transfer"的方法执行:

   
   
@Pointcut("execution(* transfer(..))")      private  void transfer()  {}

切入点表达式,也就是 @Pointcut 注解的值,是正规的AspectJ 5切入点表达式。 如果你想要更多了解AspectJ的 切入点语言,请参见AspectJ 编程指南(如果要了解基于Java 5的扩展请参阅 AspectJ 5 开发手册) 或者其他人写的关于AspectJ的书,例如Colyer et. al.著的《Eclipse AspectJ》或者Ramnivas Laddad著的《AspectJ in Action》。

6.2.3.1. 支持的切入点指定者

Spring AOP 支持在切入点表达式中使用如下的AspectJ切入点指定者:

  • execution - 匹配方法执行的连接点,这是你将会用到的Spring的最主要的切入点指定者。

  • within - 限定匹配特定类型的连接点(在使用Spring AOP的时候,在匹配的类型中定义的方法的执行)。

  • this - 限定匹配特定的连接点(使用Spring AOP的时候方法的执行),其中bean reference(Spring AOP 代理)是指定类型的实例。

  • target - 限定匹配特定的连接点(使用Spring AOP的时候方法的执行),其中目标对象(被代理的appolication object)是指定类型的实例。

  • args - 限定匹配特定的连接点(使用Spring AOP的时候方法的执行),其中参数是指定类型的实例。

  • @target - 限定匹配特定的连接点(使用Spring AOP的时候方法的执行),其中执行的对象的类已经有指定类型的注解。

  • @args - 限定匹配特定的连接点(使用Spring AOP的时候方法的执行),其中实际传入参数的运行时类型有指定类型的注解。

  • @within - 限定匹配特定的连接点,其中连接点所在类型已指定注解(在使用Spring AOP的时候,所执行的方法所在类型已指定注解)。

  • @annotation - 限定匹配特定的连接点(使用Spring AOP的时候方法的执行),其中连接点的主题有某种给定的注解。

因为Spring AOP限制了连接点必须是方法执行级别的,pointcut designators的讨论也给出了一个定义,这个定义和AspectJ的编程指南中的定义相比显得更加狭窄。 除此之外,AspectJ它本身有基于类型的语义,在执行的连接点'this'和'target'都是指同一个对象,也就是执行方法的对象。 Spring AOP是一个基于代理的系统,并且严格区分代理对象本身(对应于'this')和背后的目标对象(对应于'target')
6.2.3.2. 合并切入点表达式

切入点表达式可以使用using '&&', '||' 和 '!'来合并.还可以通过名字来指向切入点表达式。 以下的例子展示了三种切入点表达式:anyPublicOperation(在一个方法执行连接点代表了任意public方法的执行时匹配); inTrading(在一个代表了在交易模块中的任意的方法执行时匹配) 和 tradingOperation(在一个代表了在交易模块中的任意的公共方法执行时匹配)。

    
    
@Pointcut("execution(public * *(..))")      private  void anyPublicOperation()  {}     @Pointcut("within(com.xyz.someapp.trading..*")      private  void inTrading()  {}     @Pointcut("anyPublicOperation() && inTrading()")      private  void tradingOperation()  {}

就上所示的,从更小的命名组件来构建更加复杂的切入点表达式是一种最佳实践。 当用名字来指定切入点时使用的是常见的Java成员可视性访问规则。 (比如说,你可以在同一类型中访问私有的切入点,在继承关系中访问受保护的切入点,可以在任意地方访问公共切入点。 成员可视性访问规则不影响到切入点的 匹配

在AspectJ 1.5.1中有一个bug (#140357)有时候可能会导致Spring所使用的AspectJ切入点解析失败, 即使用一个已命名的切入点来引用到另一个同类型的切入点的时候。 在AspectJ的开发中已经解决这个bug,可以在AspectJ的下载页面得到。在1.5.2发布时将会包含这一fix。 如果你遇到了这个问题,你可以去下载AspectJ的开发构建包,并且更新你的 aspectjweaver.jar,这是在AspectJ 1.5.2发布前的临时解决方案。
6.2.3.3. 共享常见的切入点(pointcut)定义

当开发企业级应用的时候,你通常会想要从几个切面来参考模块化的应用和特定操作的集合。 我们推荐定义一个“SystemArchitecture”切面来捕捉常见的切入点表达式。一个典型的切面可能看起来像下面这样:

 

package com.xyz.someapp;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public  class SystemArchitecture  {

  /**
   * A join point is in the web layer if the method is defined
   * in a type in the com.xyz.someapp.web package or any sub-package
   * under that.
   
*/

  @Pointcut("within(com.xyz.someapp.web..*)")
  public void inWebLayer() {}

  /**
   * A join point is in the service layer if the method is defined
   * in a type in the com.xyz.someapp.service package or any sub-package
   * under that.
   
*/

  @Pointcut("within(com.xyz.someapp.service..*)")
  public void inServiceLayer() {}

  /**
   * A join point is in the data access layer if the method is defined
   * in a type in the com.xyz.someapp.dao package or any sub-package
   * under that.
   
*/

  @Pointcut("within(com.xyz.someapp.dao..*)")
  public void inDataAccessLayer() {}

  /**
   * A business service is the execution of any method defined on a service
   * interface. This definition assumes that interfaces are placed in the
   * "service" package, and that implementation types are in sub-packages.
   *
   * If you group service interfaces by functional area (for example,
   * in packages com.xyz.someapp.abc.service and com.xyz.def.service) then
   * the pointcut expression "execution(* com.xyz.someapp..service.*.*(..))"
   * could be used instead.
   
*/

  @Pointcut("execution(* com.xyz.someapp.service.*.*(..))")
  public void businessService() {}

  /**
   * A data access operation is the execution of any method defined on a
   * dao interface. This definition assumes that interfaces are placed in the
   * "dao" package, and that implementation types are in sub-packages.
   
*/

  @Pointcut("execution(* com.xyz.someapp.dao.*.*(..))")
  public void dataAccessOperation() {}

}


示例中的切入点定义一个你可以在任何需要切入点表达式的地方可引用的切面。比如,为了使service层事务化,你可以写: 

< aop:config >
   < aop:advisor
      
pointcut ="com.xyz.someapp.SystemArchitecture.businessService()"
      advice-ref
="tx-advice" />
</ aop:config >

< tx:advice  id ="tx-advice" >
< tx:attributes >
     < tx:method  name ="*"  propagation ="REQUIRED" />
   </ tx:attributes >
</ tx:advice >



在 Section 6.3, “Schema-based AOP support” 中讨论 <aop:config> 和 <aop:advisor>标签。 在 Chapter 9, 事务管理 中讨论事务标签。

6.2.3.4. 示例

Spring AOP 用户可能会经常使用 execution pointcut designator。执行表达式的格式如下:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)

除了返回类型模式,名字模式和参数模式以外,所有的部分都是可选的。 返回类型模式决定了方法的返回类型必须依次匹配一个连接点。 你会使用的最频繁的返回类型模式是 *,它代表了匹配任意的返回类型。 一个全称限定的类型名将只会匹配返回给定类型的方法。名字模式匹配的是方法名。 你可以使用 * 通配符作为所有或者部分命名模式。 参数模式稍微有点复杂:() 匹配了一个不接受任何参数的方法, 而 (..) 匹配了一个接受任意数量参数的方法(零或者更多)。 模式 (*) 匹配了一个接受一个任何类型的参数的方法。 模式 (*,String) 匹配了一个接受两个参数的方法,第一个可以是任意类型,第二个则必须是String类型。 请参见AspectJ编程指南的 Language Semantics 部分。

下面给出一些常见切入点表达式的例子。

  • 任意公共方法的执行:

    execution(public * *(..))
  • 任何一个以“set”开始的方法的执行:

    execution(* set*(..))
  • AccountService 接口的任意方法的执行:

    execution(* com.xyz.service.AccountService.*(..))
  • 定义在service包里的任意方法的执行:

    execution(* com.xyz.service.*.*(..))
  • 定义在service包或者子包里的任意方法的执行:

    execution(* com.xyz.service..*.*(..))
  • 在service包里的任意连接点(在Spring AOP中只是方法执行) :

    within(com.xyz.service.*)
  • 在service包或者子包里的任意连接点(在Spring AOP中只是方法执行) :

    within(com.xyz.service..*)
  • 实现了 AccountService 接口的代理对象的任意连接点(在Spring AOP中只是方法执行) :

    this(com.xyz.service.AccountService)
    'this'在binding form中用的更多:- 请常见以下讨论通知的章节中关于如何使得代理对象可以在通知体内访问到的部分。
  • 实现了 AccountService 接口的目标对象的任意连接点(在Spring AOP中只是方法执行) :

    target(com.xyz.service.AccountService)
    'target'在binding form中用的更多:- 请常见以下讨论通知的章节中关于如何使得目标对象可以在通知体内访问到的部分。
  • 任何一个只接受一个参数,且在运行时传入的参数实现了 Serializable 接口的连接点 (在Spring AOP中只是方法执行)

    args(java.io.Serializable)
    'args'在binding form中用的更多:- 请常见以下讨论通知的章节中关于如何使得方法参数可以在通知体内访问到的部分。

    请注意在例子中给出的切入点不同于 execution(* *(java.io.Serializable)): args只有在动态运行时候传入参数是可序列化的(Serializable)才匹配,而execution 在传入参数的签名声明的类型实现了 Serializable 接口时候匹配。

  • 有一个 @Transactional 注解的目标对象中的任意连接点(在Spring AOP中只是方法执行)

    @target(org.springframework.transaction.annotation.Transactional)
    '@target' 也可以在binding form中使用:请常见以下讨论通知的章节中关于如何使得annotation对象可以在通知体内访问到的部分。
  • 任何一个目标对象声明的类型有一个 @Transactional 注解的连接点(在Spring AOP中只是方法执行)

    @within(org.springframework.transaction.annotation.Transactional)
    '@within'也可以在binding form中使用:- 请常见以下讨论通知的章节中关于如何使得annotation对象可以在通知体内访问到的部分。
  • 任何一个执行的方法有一个 @Transactional annotation的连接点(在Spring AOP中只是方法执行)

    @annotation(org.springframework.transaction.annotation.Transactional)
    '@annotation' 也可以在binding form中使用:- 请常见以下讨论通知的章节中关于如何使得annotation对象可以在通知体内访问到的部分。
  • 任何一个接受一个参数,并且传入的参数在运行时的类型实现了 @Classified annotation的连接点(在Spring AOP中只是方法执行)

    @args(com.xyz.security.Classified)
    '@args'也可以在binding form中使用:- 请常见以下讨论通知的章节中关于如何使得annotation对象可以在通知体内访问到的部分。

6.2.4. 声明通知

通知是跟一个切入点表达式关联起来的,并且在切入点匹配的方法执行之前或者之后或者之前和之后运行。 切入点表达式可能是指向已命名的切入点的简单引用或者是一个已经声明过的切入点表达式。

6.2.4.1. 前置通知(Before advice)

一个切面里使用 @Before 注解声明前置通知:

如果使用一个in-place 的切入点表达式,我们可以把上面的例子换个写法:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
@Before("execution(* com.xyz.myapp.dao.*.*(..))")
public void doAccessCheck() {
// ...
}
}
6.2.4.2. 返回后通知(After returning advice)

返回后通知通常在一个匹配的方法返回的时候执行。使用 @AfterReturning 注解来声明:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class AfterReturningExample {
@AfterReturning("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doAccessCheck() {
// ...
}
}
说明:你可以在同一个切面里定义多个通知,或者其他成员。我们只是在展示如何定义一个简单的通知。这些例子主要的侧重点是正在讨论的问题。

有时候你需要在通知体内得到返回的值。你可以使用以 @AfterReturning 接口的形式来绑定返回值:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class AfterReturningExample {
@AfterReturning(
pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
returning="retVal")
public void doAccessCheck(Object retVal) {
// ...
}
}

在 returning 属性中使用的名字必须对应于通知方法内的一个参数名。 当一个方法执行返回后,返回值作为相应的参数值传入通知方法。 一个 returning 子句也限制了只能匹配到返回指定类型值的方法。 (在本例子中,返回值是 Object 类,也就是说返回任意类型都会匹配)

6.2.4.3. 抛出后通知(After throwing advice)

抛出后通知在一个方法抛出异常后执行。使用 @AfterThrowing 注解来声明:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class AfterThrowingExample {
@AfterThrowing("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doRecoveryActions() {
// ...
}
}

你通常会想要限制通知只在某种特殊的异常被抛出的时候匹配,你还希望可以在通知体内得到被抛出的异常。 使用 throwing 属性不光可以限制匹配的异常类型(如果你不想限制,请使用 Throwable 作为异常类型),还可以将抛出的异常绑定到通知的一个参数上。

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class AfterThrowingExample {
@AfterThrowing(
pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
throwing="ex")
public void doRecoveryActions(DataAccessException ex) {
// ...
}
}

在 throwing 属性中使用的名字必须与通知方法内的一个参数对应。 当一个方法因抛出一个异常而中止后,这个异常将会作为那个对应的参数送至通知方法。 throwing 子句也限制了只能匹配到抛出指定异常类型的方法(上面的示例为 DataAccessException)。

6.2.4.4. 后通知(After (finally) advice)

不论一个方法是如何结束的,在它结束后(finally)后通知(After (finally) advice)都会运行。 使用 @After 注解来声明。这个通知必须做好处理正常返回和异常返回两种情况。通常用来释放资源。

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.After;
@Aspect
public class AfterFinallyExample {
@After("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doReleaseLock() {
// ...
}
}
6.2.4.5. 环绕通知(Around Advice)

最后一种通知是环绕通知。环绕通知在一个方法执行之前和之后执行。 它使得通知有机会既在一个方法执行之前又在执行之后运行。并且,它可以决定这个方法在什么时候执行,如何执行,甚至是否执行。 环绕通知经常在在某线程安全的环境下,你需要在一个方法执行之前和之后共享某种状态的时候使用。 请尽量使用最简单的满足你需求的通知。(比如如果前置通知(before advice)也可以适用的情况下不要使用环绕通知)。

环绕通知使用 @Around 注解来声明。通知的第一个参数必须是 ProceedingJoinPoint 类型。 在通知体内,调用 ProceedingJoinPoint的 proceed() 方法将会导致潜在的连接点方法执行。 proceed 方法也可能会被调用并且传入一个 Object[] 对象-该数组将作为方法执行时候的参数。

当传入一个 Object[] 对象的时候,处理的方法与通过AspectJ编译器处理环绕通知略有不同。 对于使用传统AspectJ语言写的环绕通知来说,传入参数的数量必须和传递给环绕通知的参数数量匹配(不是后台的连接点接受的参数数量),并且特定顺序的传入参数代替了将要绑定给连接点的原始值(如果你看不懂不用担心)。 Spring采用的方法更加简单并且更好得和他的基于代理(proxy-based),只匹配执行的语法相适用。 如果你适用AspectJ的编译器和编织器来编译为Spring而写的@AspectJ切面和处理参数,你只需要了解这一区别即可。 有一种方法可以让你写出100%兼容Spring AOP和AspectJ的,我们将会在后续的通知参数(advice parameters)的章节中讨论它。
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;
@Aspect
public class AroundExample {
@Around("com.xyz.myapp.SystemArchitecture.businessService()")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
// start stopwatch
Object retVal = pjp.proceed();
// stop stopwatch
return retVal;
}
}

方法的调用者得到的返回值就是环绕通知返回的值。 例如:一个简单的缓存切面,如果缓存中有值,就返回该值,否则调用proceed()方法。 请注意proceed可能在通知体内部被调用一次,许多次,或者根本不被调用。

6.2.4.6. 通知参数(Advice parameters)

Spring 2.0 提供了完整的通知类型 - 这意味着你可以在通知签名中声明所需的参数,(就像在以前的例子中我们看到的返回值和抛出异常一样)而不总是使用Object[]。 我们将会看到如何在通知体内访问参数和其他上下文相关的值。首先让我们看以下如何编写普通的通知以找出正在被通知的方法。

6.2.4.6.1. 访问当前的连接点

任何通知方法可以将第一个参数定义为 org.aspectj.lang.JoinPoint 类型 (环绕通知需要定义为 ProceedingJoinPoint 类型的, 它是 JoinPoint 的一个子类。) JoinPoint 接口提供了一系列有用的方法, 比如 getArgs()(返回方法参数)、getThis()(返回代理对象)、getTarget()(返回目标)、getSignature()(返回正在被通知的方法相关信息)和 toString()(打印出正在被通知的方法的有用信息)。

6.2.4.6.2. 传递参数给通知(Advice)

我们已经看到了如何绑定返回值或者异常(使用后置通知(after returning)和异常后通知(after throwing advice)。 为了可以在通知(adivce)体内访问参数,你可以使用 args 来绑定。 如果在一个参数表达式中应该使用类型名字的地方使用一个参数名字,那么当通知执行的时候对应的参数值将会被传递进来。 可能给出一个例子会更好理解。假使你想要通知(advise)接受某个Account对象作为第一个参数的DAO操作的执行,你想要在通知体内也能访问到account对象,你可以写如下的代码:

@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation() &&" +
"args(account,..)")
public void validateAccount(Account account) {
// ...
}

切入点表达式的 args(account,..) 部分有两个目的: 首先它保证了只会匹配那些接受至少一个参数的方法的执行,而且传入的参数必须是 Account 类型的实例, 其次它使得可以在通知体内通过 account 参数来访问那个account参数。

另外一个办法是定义一个切入点,这个切入点在匹配某个连接点的时候“提供”了一个Account对象, 然后直接从通知中访问那个命名的切入点。你可以这样写:

@Pointcut("com.xyz.myapp.SystemArchitecture.dataAccessOperation() &&" +
"args(account,..)")
private void accountDataAccessOperation(Account account) {}
@Before("accountDataAccessOperation(account)")
public void validateAccount(Account account) {
// ..
}

如果想要知道更详细的内容,请参阅 AspectJ 编程指南。

代理对象(this)、目标对象(target) 和注解(@within, @target, @annotation, @args)都可以用一种简单格式绑定。 以下的例子展示了如何使用 @Auditable 注解来匹配方法执行,并提取AuditCode。

首先是 @Auditable 注解的定义:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Auditable {
AuditCode value();
}

然后是匹配 @Auditable 方法执行的通知:

@Before("com.xyz.lib.Pointcuts.anyPublicMethod() && " +
"@annotation(auditable)")
public void audit(Auditable auditable) {
AuditCode code = auditable.value();
// ...
}
6.2.4.6.3. 决定参数名

绑定在通知上的参数依赖切入点表达式的匹配名,并借此在(通知(advice)和切入点(pointcut))的方法签名中声明参数名。 参数名 无法 通过Java反射来获取,所以Spring AOP使用如下的策略来决定参数名字:

  1. 如果参数名字已经被用户明确指定,则使用指定的参数名: 通知(advice)和切入点(pointcut)注解有一个额外的"argNames"属性,该属性用来指定所注解的方法的参数名 - 这些参数名在运行时是 可以 访问的。例子如下:

    @Before(
        value="com.xyz.lib.Pointcuts.anyPublicMethod() && " +
        "@annotation(auditable)",
        argNames="auditable")
        public void audit(Auditable auditable) {
        AuditCode code = auditable.value();
        // ...
        }
        
    如果一个@AspectJ切面已经被AspectJ编译器(ajc)编译过了,那么就不需要再添加 argNames 参数了,因为编译器会自动完成这一工作。
  2. 使用 'argNames' 属性有点不那么优雅,所以如果没有指定'argNames' 属性, Spring AOP 会寻找类的debug信息,并且尝试从本地变量表(local variable table)中来决定参数名字。 只要编译的时候使用了debug信息(至少要使用 '-g:vars' ),就可获得这些信息。 使用这个flag编译的结果是: (1)你的代码将能够更加容易的读懂(反向工程), (2)生成的class文件会稍许大一些(不重要的), (3)移除不被使用的本地变量的优化功能将会失效。 换句话说,你在使用这个flag的时候不会遇到任何困难。

  3. 如果不加上debug信息来编译的话,Spring AOP将会尝试推断参数的绑定。 (例如,要是只有一个变量被绑定到切入点表达式(pointcut expression)、通知方法(advice method)将会接受这个参数, 这是显而易见的)。 如果变量的绑定不明确,将会抛出一个 AmbiguousBindingException 异常。

  4. 如果以上所有策略都失败了,将会抛出一个 IllegalArgumentException 异常。

6.2.4.6.4. 处理参数

我们之前提过我们将会讨论如何编写一个 带参数的 的proceed()调用,使得不论在Spring AOP中还是在AspectJ都能正常工作。 解决方法是保证通知签名依次绑定方法参数。比如说:

@Around("execution(List<Account> find*(..)) &&" +
"com.xyz.myapp.SystemArchitecture.inDataAccessLayer() && " +
"args(accountHolderNamePattern)")
public Object preProcessQueryPattern(ProceedingJoinPoint pjp, String accountHolderNamePattern)
throws Throwable {
String newPattern = preProcess(accountHolderNamePattern);
return pjp.proceed(new Object[] {newPattern});
}

大多数情况下你都会这样绑定(就像上面的例子那样)。

6.2.4.7. 通知(Advice)顺序

如果有多个通知想要在同一连接点运行会发生什么?Spring AOP 的执行通知的顺序跟AspectJ的一样。 在“进入”连接点的情况下,最高优先级的通知会先执行(所以上面给出的两个前置通知(before advice)中,优先级高的那个会先执行)。 在“退出”连接点的情况下,最高优先级的通知会最后执行。(所以上面给出的两个前置通知(before advice)中,优先级高的那个会第二个执行)。 对于定义在相同切面的通知,根据声明的顺序来确定执行顺序。比如下面这个切面:

@Aspect
public class AspectWithMultipleAdviceDeclarations {
@Pointcut("execution(* foo(..))")
public void fooExecution() {}
@Before("fooExecution()")
public void doBeforeOne() {
// ..
}
@Before("fooExecution()")
public void doBeforeTwo() {
// ..
}
@AfterReturning("fooExecution()")
public void doAfterOne() {
// ..
}
@AfterReturning("fooExecution()")
public void doAfterTwo() {
//..
}
}

这样,假使对于任何一个名字为foo的方法的执行, doBeforeOnedoBeforeTwodoAfterOne 和 doAfterTwo 通知方法都需要运行。 执行顺序将按照声明的顺序来确定。在这个例子中,执行的结果会是:

doBeforeOne
doBeforeTwo
foo
doAfterOne
doAfterTwo

换言之,因为doBeforeOne先定义,它会先于doBeforeTwo执行,而doAfterTwo后于doAfterOne定义,所以它会在doAfterOne之后执行。 只需要记住通知是按照定义的顺序来执行的就可以了。 - 如果想要知道更加详细的内容,请参阅AspectJ编程指南。

当定义在 不同的 切面里的两个通知都需要在一个相同的连接点中运行,那么除非你指定,否则执行的顺序是未知的。 你可以通过指定优先级来控制执行顺序。在Spring中可以在切面类中实现 org.springframework.core.Ordered 接口做到这一点。 在两个切面中,Ordered.getValue() 方法返回值较低的那个有更高的优先级。

6.2.5. 引入(Introductions)

引入(Introductions)(在AspectJ中被称为inter-type声明)使得一个切面可以定义被通知对象实现一个给定的接口,并且可以代表那些对象提供具体实现。

使用 @DeclareParents注解来定义引入。这个注解被用来定义匹配的类型拥有一个新的父亲。 比如,给定一个接口 UsageTracked,然后接口的具体实现 DefaultUsageTracked 类, 接下来的切面声明了所有的service接口的实现都实现了 UsageTracked 接口。(比如为了通过JMX输出统计信息)。

@Aspect
public class UsageTracking {
@DeclareParents(value="com.xzy.myapp.service.*+",
defaultImpl=DefaultUsageTracked.class)
public static UsageTracked mixin;
@Before("com.xyz.myapp.SystemArchitecture.businessService() &&" +
"this(usageTracked)")
public void recordUsage(UsageTracked usageTracked) {
usageTracked.incrementUseCount();
}
}

实现的接口通过被注解的字段类型来决定。@DeclareParents 注解的 value 属性是一个AspectJ的类型模式:- 任何匹配类型的bean都会实现 UsageTracked 接口。 请注意,在上面的前置通知(before advice)的例子中,service beans 可以直接用作 UsageTracked 接口的实现。 如果需要编程式的来访问一个bean,你可以这样写:

UsageTracked usageTracked = (UsageTracked) context.getBean("myService");

6.2.6. 切面实例化模型

这是一个高级主题...

默认情况下,在application context中每一个切面都会有一个实例。 AspectJ 把这个叫做单个实例化模型(singleton instantiation model)。 也可以用其他的生命周期来定义切面:- Spring支持AspectJ的 perthis 和 pertarget 实例化模型 (现在还不支持percflow、percflowbelow 和 pertypewithin )。

一个"perthis" 切面的定义:在 @Aspect 注解中指定perthis 子句。 让我们先来看一个例子,然后解释它是如何运作的:

@Aspect("perthis(com.xyz.myapp.SystemArchitecture.businessService())")
public class MyAspect {
private int someState;
@Before(com.xyz.myapp.SystemArchitecture.businessService())
public void recordServiceUsage() {
// ...
}
}

这个perthis子句的效果是每个独立的service对象执行时都会创建一个切面实例(切入点表达式所匹配的连接点上的每一个独立的对象都会绑定到'this'上)。 service对象的每个方法在第一次执行的时候创建切面实例。切面在service对象失效的同时失效。 在切面实例被创建前,所有的通知都不会被执行,一旦切面对象创建完成,定义的通知将会在匹配的连接点上执行,但是只有当service对象是和切面关联的才可以。 如果想要知道更多关于per-clauses的信息,请参阅 AspectJ 编程指南。

'pertarget'实例模型的跟“perthis”完全一样,只不过是为每个匹配于连接点的独立目标对象创建一个切面实例。

6.2.7. 例子

现在你已经看到了每个独立的部分是如何运作的了,是时候把他们放到一起做一些有用的事情了!

因为乐观锁的关系,有时候business services可能会失败(有人甚至在一开始运行事务的时候就失败了)。如果重新尝试一下,很有可能就会成功。 对于business services来说,重试几次是很正常的(Idempotent操作不需要用户参与,否则会得出矛盾的结论) 我们可能需要透明的重试操作以避免让客户看见 OptimisticLockingFailureException 例外被抛出。 很明显,在一个横切多层的情况下,这是非常有必要的,因此通过切面来实现是很理想的。

因为我们想要重试操作,我们会需要使用到环绕通知,这样我们就可以多次调用proceed()方法。下面是简单的切面实现:

@Aspect
public  class OptimisticOperationExecutor  implements Ordered  {
private static final int DEFAULT_MAX_RETRIES = 2;
private int maxRetries = DEFAULT_MAX_RETRIES;
private int order = 1;
public void setMaxRetries(int maxRetries) {
this.maxRetries = maxRetries;
}

public int getOrder() {
return this.order;
}

public void setOrder(int order) {
this.order = order;
}

@Around("com.xyz.myapp.SystemArchitecture.businessService()")
public Object doOptimisticOperation(ProceedingJoinPoint pjp) throws Throwable {
int numAttempts = 0;
OptimisticLockingFailureException lockFailureException;
do {
numAttempts++;
try {
return pjp.proceed();
}

catch(OptimisticLockingFailureException ex) {
lockFailureException = ex;
}

}

while(numAttempts <= this.maxRetries);
throw lockFailureException;
}

}


请注意切面实现了 Ordered 接口,这样我们就可以把切面的优先级设定为高于事务通知(我们每次重试的时候都想要在一个全新的事务中进行)。 maxRetries 和 order 属性都可以在Spring中配置。 主要的动作在 doOptimisticOperation 这个环绕通知中发生。 请注意这个时候我们所有的 businessService() 方法都会使用这个重试策略。 我们首先会尝试处理,然后如果我们得到一个OptimisticLockingFailureException 意外,我们只需要简单的重试,直到我们耗尽所有预设的重试次数。

对应的Spring配置如下:

    
    
< aop:aspectj-autoproxy /> < bean  id ="optimisticOperationExecutor" class ="com.xyz.myapp.service.impl.OptimisticOperationExecutor" > < property  name ="maxRetries"  value ="3" /> < property  name ="order"  value ="100" /> </ bean >

为了改进切面,使之仅仅重试idempotent操作,我们可以定义一个 Idempotent 注解:

    
    
@Retention(RetentionPolicy.RUNTIME) public @ interface Idempotent  { // marker annotation }

并且对service操作的实现进行注解。 这样如果你只希望改变切面使得idempotent的操作会尝试多次,你只需要改写切入点表达式,这样只有 @Idempotent 操作会匹配:

@Around("com.xyz.myapp.SystemArchitecture.businessService() && " +
"@annotation(com.xyz.myapp.service.Idempotent)")
public Object doOptimisticOperation(ProceedingJoinPoint pjp) throws Throwable {
...
}

6.3. Schema-based AOP support

如果你无法使用Java 5,或者你比较喜欢使用XML格式,Spring2.0也提供了使用新的"aop"命名空间来定义一个切面。 和使用@AspectJ风格完全一样,切入点表达式和通知类型同样得到了支持,因此在这一节中我们将着重介绍新的 语法 和回顾前面我们所讨论的如何写一个切入点表达式和通知参数的绑定等等(Section 6.2, “@AspectJ支持”)。

使用本章所介绍的aop命名空间标签(aop namespace tag),你需要引入Appendix A, XML Schema-based configuration中提及的spring-aop schema。 参见Section A.2.6, “The aop schema”

在Spring的配置文件中,所有的切面和通知器都必须定义在 <aop:config> 元素内部。 一个application context可以包含多个<aop:config>。 一个 <aop:config> 可以包含pointcut,advisor和aspect元素,并且三者必须按照这样的顺序进行声明。

6.3.1. 声明一个切面

有了schema的支持,切面就和常规的Java对象一样被定义成application context中的一个bean。 对象的字段和方法提供了状态和行为信息,XML文件则提供了切入点和通知信息。

切面使用<aop:aspect>来声明,backing bean(支持bean)通过 ref 属性来引用:

<aop:config>
<aop:aspect id="myAspect" ref="aBean">
...
</aop:aspect>
</aop:config>
<bean id="aBean" class="...">
...
</bean>

切面的支持bean(上例中的"aBean")可以象其他Spring bean一样被容器管理配置以及依赖注入。

6.3.2. 声明一个切入点

切入点可以在切面里面声明,这种情况下切入点只在切面内部可见。切入点也可以直接在<aop:config>下定义,这样就可以使多个切面和通知器共享该切入点。

一个描述service层中表示所有service执行的切入点可以如下定义:

<aop:config>
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
</aop:config>

注意切入点表达式本身使用了 Section 6.2, “@AspectJ支持” 中描述的AspectJ 切入点表达式语言。 如果你在Java 5环境下使用基于schema的声明风格,可参考切入点表达式类型中定义的命名式切入点,不过这在JDK1.4及以下版本中是不被支持的(因为依赖于Java 5中的AspectJ反射API)。 所以在JDK 1.5中,上面的切入点的另外一种定义形式如下:

<aop:config>
<aop:pointcut id="businessService"
expression="com.xyz.myapp.SystemArchitecture.businessService()"/>
</aop:config>

假定你有 Section 6.2.3.3, “共享常见的切入点(pointcut)定义”中说描述的 SystemArchitecture 切面。

在切面里面声明一个切入点和声明一个顶级的切入点非常类似:

<aop:config>
<aop:aspect id="myAspect" ref="aBean">
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
...
</aop:aspect>
</aop:config>

当需要连接子表达式的时候,'&&'在XML中用起来非常不方便,所以关键字'and', 'or' 和 'not'可以分别用来代替'&&', '||' 和 '!'。

注意这种方式定义的切入点通过XML id来查找,并且不能定义切入点参数。在基于schema的定义风格中命名切入点支持较之@AspectJ风格受到了很多的限制。

6.3.3. 声明通知

和@AspectJ风格一样,基于schema的风格也支持5种通知类型并且两者具有同样的语义。

6.3.3.1. 通知(Advice)

Before通知在匹配方法执行前进入。在<aop:aspect>里面使用<aop:before>元素进行声明。

<aop:aspect id="beforeExample" ref="aBean">
<aop:before
pointcut-ref="dataAccessOperation"
method="doAccessCheck"/>
...
</aop:aspect>

这里 dataAccessOperation 是一个顶级(<aop:config>)切入点的id。 要定义内置切入点,可将 pointcut-ref 属性替换为 pointcut属性:

<aop:aspect id="beforeExample" ref="aBean">
<aop:before
pointcut="execution(* com.xyz.myapp.dao.*.*(..))"
method="doAccessCheck"/>
...
</aop:aspect>

我们已经在@AspectJ风格章节中讨论过了,使用命名切入点能够明显的提高代码的可读性。

Method属性标识了提供了通知的主体的方法(doAccessCheck)。这个方法必须定义在包含通知的切面元素所引用的bean中。 在一个数据访问操作执行之前(执行连接点和切入点表达式匹配),切面中的"doAccessCheck"会被调用。

6.3.3.2. 返回后通知(After returning advice)

After returning通知在匹配的方法完全执行后运行。和Before通知一样,可以在<aop:aspect>里面声明。例如:

<aop:aspect id="afterReturningExample" ref="aBean">
<aop:after-returning
pointcut-ref="dataAccessOperation"
method="doAccessCheck"/>
...
</aop:aspect>

和@AspectJ风格一样,通知主体可以接收返回值。使用returning属性来指定接收返回值的参数名:

<aop:aspect id="afterReturningExample" ref="aBean">
<aop:after-returning
pointcut-ref="dataAccessOperation"
returning="retVal"
method="doAccessCheck"/>
...
</aop:aspect>

doAccessCheck方法必须声明一个名字叫 retVal 的参数。 参数的类型强制匹配,和先前我们在@AfterReturning中讲到的一样。例如,方法签名可以这样声明:

public void doAccessCheck(Object retVal) {...
6.3.3.3. 抛出异常后通知(After throwing advice)

After throwing通知在匹配方法抛出异常退出时执行。在 <aop:aspect> 中使用after-throwing元素来声明:

<aop:aspect id="afterThrowingExample" ref="aBean">
<aop:after-throwing
pointcut-ref="dataAccessOperation"
method="doRecoveryActions"/>
...
</aop:aspect>

和@AspectJ风格一样,可以从通知体中获取抛出的异常。 使用throwing属性来指定异常的名称,用这个名称来获取异常:

<aop:aspect id="afterThrowingExample" ref="aBean">
<aop:after-throwing
pointcut-ref="dataAccessOperation"
thowing="dataAccessEx"
method="doRecoveryActions"/>
...
</aop:aspect>

doRecoveryActions方法必须声明一个名字为 dataAccessEx 的参数。 参数的类型强制匹配,和先前我们在@AfterThrowing中讲到的一样。例如:方法签名可以如下这般声明:

public void doRecoveryActions(DataAccessException dataAccessEx) {...
6.3.3.4. 后通知(After (finally) advice)

After (finally)通知在匹配方法退出后执行。使用 after 元素来声明:

<aop:aspect id="afterFinallyExample" ref="aBean">
<aop:after
pointcut-ref="dataAccessOperation"
method="doReleaseLock"/>
...
</aop:aspect>
6.3.3.5. 通知

Around通知是最后一种通知类型。Around通知在匹配方法运行期的“周围”执行。 它有机会在目标方法的前面和后面执行,并决定什么时候运行,怎么运行,甚至是否运行。 Around通知经常在需要在一个方法执行前或后共享状态信息,并且是线程安全的情况下使用(启动和停止一个计时器就是一个例子)。 注意选择能满足你需求的最简单的通知类型(i.e.如果简单的before通知就能做的事情绝对不要使用around通知)。

Around通知使用 aop:around 元素来声明。 通知方法的第一个参数的类型必须是 ProceedingJoinPoint 类型。 在通知的主体中,调用ProceedingJoinPointproceed() 方法来执行真正的方法。 proceed 方法也可能会被调用并且传入一个 Object[] 对象 - 该数组将作为方法执行时候的参数。 参见 Section 6.2.4.5, “环绕通知(Around Advice)” 中提到的一些注意点。

<aop:aspect id="aroundExample" ref="aBean">
<aop:around
pointcut-ref="businessService"
method="doBasicProfiling"/>
...
</aop:aspect>

doBasicProfiling 通知的实现和@AspectJ中的例子完全一样(当然要去掉注解):

public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
// start stopwatch
Object retVal = pjp.proceed();
// stop stopwatch
return retVal;
}
6.3.3.6. 通知参数

Schema-based声明风格和@AspectJ支持一样,支持通知的全名形式 - 通过通知方法参数名字来匹配切入点参数。 参见Section 6.2.4.6, “通知参数(Advice parameters)” 获取详细信息。

如果你希望显式指定通知方法的参数名(而不是依靠先前提及的侦测策略),可以通过 arg-names 属性来实现。示例如下:

<aop:before
pointcut="com.xyz.lib.Pointcuts.anyPublicMethod() and @annotation(auditable)"
method="audit"
arg-names="auditable"/>

The arg-names attribute accepts a comma-delimited list of parameter names.

arg-names属性接受由逗号分割的参数名列表。

6.3.3.7. 通知顺序

当同一个切入点(执行方法)上有多个通知需要执行时,执行顺序规则在 Section 6.2.4.7, “通知(Advice)顺序” 已经提及了。 切面的优先级通过切面的支持bean是否实现了Ordered接口来决定。

6.3.4. 引入

Intrduction (在AspectJ中成为inter-type声明)允许一个切面声明一个通知对象实现指定接口,并且提供了一个接口实现类来代表这些对象。

在 aop:aspect 内部使用 aop:declare-parents 元素定义Introduction。 该元素用于用来声明所匹配的类型有了一个新的父类型(所以有了这个名字)。 例如,给定接口 UsageTracked,以及这个接口的一个实现类 DefaultUsageTracked, 下面声明的切面所有实现service接口的类同时实现 UsageTracked 接口。(比如为了通过JMX暴露statistics。)

<aop:aspect id="usageTrackerAspect" ref="usageTracking">
<aop:declare-parents
types-matching="com.xzy.myapp.service.*+",
implement-interface="UsageTracked"
default-impl="com.xyz.myapp.service.tracking.DefaultUsageTracked"/>
<aop:before
pointcut="com.xyz.myapp.SystemArchitecture.businessService()
and this(usageTracked)"
method="recordUsage"/>
</aop:aspect>

The class backing the usageTracking bean would contain the method:

usageTracking bean的支持类可以包含下面的方法:

public void (UsageTracked usageTracked) {
usageTracked.incrementUseCount();
}

欲实现的接口由 implement-interface 属性来指定。 types-matching 属性的值是一个AspectJ类型模式:- 任何匹配类型的bean会实现 UsageTracked 接口。 注意在Before通知的例子中,srevice bean可以用作 UsageTracked 接口的实现。 如果编程形式访问一个bean,你可以这样来写:

UsageTracked usageTracked = (UsageTracked) context.getBean("myService");

6.3.5. 切面实例化模型

Schema-defined切面仅支持一种实例化模型就是singlton模型。其他的实例化模型或许在未来版本中将得到支持。

6.3.6. Advisors

"advisors"这个概念来自Spring1.2对AOP的支持,在AspectJ中是没有等价的概念。 advisor就像一个小的自包含的切面,这个切面只有一个通知。 切面自身通过一个bean表示,并且必须实现一个通知接口, 在 Section 7.3.2, “Spring里的通知类型” 中我们会讨论相应的接口。Advisors可以很好的利用AspectJ切入点表达式。

Spring 2.0 通过 <aop:advisor> 元素来支持advisor 概念。 你将会发现它大多数情况下会和transactional advice一起使用,transactional advice在Spring 2.0中有自己的命名空间。格式如下:

<aop:config>
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
<aop:advisor
pointcut-ref="businessService"
advice-ref="tx-advice"/>
</aop:config>
<tx:advice id="tx-advice">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>

和在上面使用的 pointcut-ref 属性一样,你还可以使用 pointcut 属性来定义一个内联的切入点表达式。

为了定义一个advisord的优先级以便让通知可以有序,使用 order 属性来定义 advisor的值 Ordered 。

6.3.7. 例子

让我们来看看在 Section 6.2.7, “例子” 提过乐观锁失败重试的例子,如果使用schema对这个例子进行重写是什么效果。

因为乐观锁的关系,有时候business services可能会失败(有人甚至在一开始运行事务的时候就失败了)。 如果重新尝试一下,很有可能就会成功。对于business services来说,重试几次是很正常的(Idempotent操作不需要用户参与,否则会得出矛盾的结论) 我们可能需要透明的重试操作以避免让客户看见 OptimisticLockingFailureException 例外被抛出。 很明显,在一个横切多层的情况下,这是非常有必要的,因此通过切面来实现是很理想的。

因为我们想要重试操作,我们会需要使用到环绕通知,这样我们就可以多次调用proceed()方法。 下面是简单的切面实现(只是一个schema支持的普通Java 类):

public class OptimisticOperationExecutor implements Ordered {
private static final int DEFAULT_MAX_RETRIES = 2;
private int maxRetries = DEFAULT_MAX_RETRIES;
private int order = 1;
public void setMaxRetries(int maxRetries) {
this.maxRetries = maxRetries;
}
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
public Object doOptimisticOperation(ProceedingJoinPoint pjp) throws Throwable {
int numAttempts = 0;
OptimisticLockingFailureException lockFailureException;
do {
numAttempts++;
try {
return pjp.proceed();
}
catch(OptimisticLockingFailureException ex) {
lockFailureException = ex;
}
}
while(numAttempts <= this.maxRetries);
throw lockFailureException;
}
}

请注意切面实现了 Ordered 接口,这样我们就可以把切面的优先级设定为高于事务通知(我们每次重试的时候都想要在一个全新的事务中进行)。 maxRetries 和 order 属性都可以在Spring中配置。 主要的动作在 doOptimisticOperation 这个环绕通知中发生。 请注意这个时候我们所有的 businessService() 方法都会使用这个重试策略。 我们首先会尝试处理,然后如果我们得到一个OptimisticLockingFailureException 异常,我们只需要简单的重试,直到我们耗尽所有预设的重试次数。

这个类跟我们在@AspectJ的例子中使用的是相同的,只是没有使用注解。

对应的Spring配置如下:

<aop:config>
<aop:aspect id="optimisticOperationRetry" ref="optimisticOperationExecutor">
<aop:pointcut id="idempotentOperation"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
<aop:around
pointcut-ref="idempotentOperation"
method="doOptimisticOperation"/>
</aop:aspect>
</aop:config>
<bean id="optimisticOperationExecutor"
class="com.xyz.myapp.service.impl.OptimisticOperationExecutor">
<property name="maxRetries" value="3"/>
<property name="order" value="100"/>
</bean>

请注意我们现在假设所有的bussiness services都是idempotent。如果不是这样,我们可以改写切面,加上 Idempotent 注解,让它只调用idempotent:

@Retention(RetentionPolicy.RUNTIME)
public @interface Idempotent {
// marker annotation
}

并且对service操作的实现进行注解。这样如果你只希望改变切面使得idempotent的操作会尝试多次,你只需要改写切入点表达式,这样只有 @Idempotent 操作会匹配:

  <aop:pointcut id="idempotentOperation"
expression="execution(* com.xyz.myapp.service.*.*(..)) and
@annotation(com.xyz.myapp.service.Idempotent)"/>

6.4. 混合切面类型

我们完全可以混合使用以下几种风格的切面定义:使用自动代理的@AspectJ 风格的切面,schema-defined <aop:aspect> 的切面,和用 <aop:advisor> 声明的advisor,甚至是使用Spring 1.2风格的代理和拦截器。 由于以上几种风格的切面定义的都使用了相同的底层机制,因此可以很好的共存。

6.5. 代理机制

Spring AOP部分使用JDK动态代理或者CGLIB来为目标对象创建代理。(建议尽量使用JDK的动态代理)

如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理。所有该目标类型实现的接口都将被代理。若该目标对象没有实现任何接口,则创建一个CGLIB代理。

如果你希望强制使用CGLIB代理,(例如:希望代理目标对象的所有方法,而不只是实现自接口的方法)那也可以。但是需要考虑以下问题:

  • 无法通知(advise)Final 方法,因为他们不能被覆写。

  • 你需要将CGLIB 2二进制发行包放在classpath下面,与之相较JDK本身就提供了动态代理

强制使用CGLIB代理需要将 <aop:config> 的 proxy-target-class 属性设为true:

<aop:config proxy-target-class="true">
...
</aop:config>

请注意这个属性的设置仅对 每一个<aop-config/> 有效; 你可能有多个 <aop-config/>,其中有的强制使用CGLIB代理,有的没有。

当需要使用CGLIB代理和@AspectJ自动代理支持,请按照如下的方式设置 <aop:aspectj-autoproxy> 的 proxy-target-class 属性:

<aop:aspectj-autoproxy proxy-target-class="true"/>

6.6. 编程方式创建@AspectJ代理

除了在配置文件中使用 <aop:config> 或者 <aop:aspectj-autoproxy> 来声明切面。 同样可以通过编程方式来创建代理通知(advise)目标对象。关于Spring AOP API的详细介绍,请参看下一章。这里我们重点介绍自动创建代理。

类 org.springframework.aop.aspectj.annotation.AspectJProxyFactory 可以为@AspectJ切面的目标对象创建一个代理。该类的基本用法非常简单,示例如下。请参看Javadoc获取更详细的信息。

// create a factory that can generate a proxy for the given target object
AspectJProxyFactory factory = new AspectJProxyFactory(targetObject);
// add an aspect, the class must be an @AspectJ aspect
// you can call this as many times as you need with different aspects
factory.addAspect(SecurityManager.class);
// you can also add existing aspect instances, the type of the object
// supplied must be an @AspectJ aspect
factory.addAspect(usageTracker);
// now get the proxy object...
MyInterfaceType proxy = factory.getProxy();

6.7. 在Spring应用中使用AspectJ

到目前为止本章讨论的一直是纯Spring AOP。 在这一节里面我们将介绍如何使用AspectJ compiler/weaver来代替Spring AOP或者作为它的补充,因为有些时候Spring AOP单独提供的功能也许并不能满足你的需要。

Spring提供了一个小巧的AspectJ aspect library (你可以在程序发行版本中单独使用 spring-aspects.jar 文件,并将其加入到classpath下以使用其中的切面)。 Section 6.7.1, “在Spring中使用AspectJ来为domain object进行依赖注入” 和 Section 6.7.2, “Spring中其他的AspectJ切面” 讨论了该库和如何使用该库。 Section 6.7.3, “使用Spring IoC来配置AspectJ的切面” 讨论了如何对通过AspectJ compiler织入的AspectJ切面进行依赖注入。 最后Section 6.7.4, “在Spring应用中使用AspectJ Load-time weaving(LTW)”介绍了使用AspectJ的Spring应用程序如何装载期织入(load-time weaving)。

6.7.1. 在Spring中使用AspectJ来为domain object进行依赖注入

Spring容器对application context中定义的bean进行实例化和配置。 同样也可以通过bean factory来为一个已经存在且已经定义为spring bean的对象应用所包含的配置信息。 spring-aspects.jar中包含了一个annotation-driven的切面,提供了能为任何对象进行依赖注入的能力。 这样的支持旨在为 脱离容器管理 创建的对象进行依赖注入。 Domain object经常处于这样的情形:它们可能是通过new 操作符创建的对象, 也可能是ORM工具查询数据库的返回结果对象。

包 org.springframework.orm.hibernate.support 中的类 DependencyInjectionInterceptorFactoryBean 可以让Spring为Hibernate创建并且配置prototype类型的domain object(使用自动装配或者确切命名的bean原型定义)。 当然,拦截器不支持配置你编程方式创建的对象而非检索数据库返回的对象。 其他framework也会提供类似的技术。仍是那句话,Be Pragramatic选择能满足你需求的方法中最简单的那个。 请注意前面提及的类 没有 随Spring发行包一起发布。 如果你希望使用该类,需要从Spring CVS Respository上下载并且自行编译。 你可以在Spring CVS respository下的 'sandbox' 目录下找到该文件。

@Configurable 注解标记了一个类可以通过Spring-driven方式来配置。 在最简单的情况下,我们只把它当作标记注解:

package com.xyz.myapp.domain;
import org.springframework.beans.factory.annotation;
@Configurable
public class Account {
...

当只是简单地作为一个标记接口来使用的时候,Spring将采用和该已注解的类型(比如Account类)全名 (com.xyz.myapp.domain.Account)一致的bean原型定义来配置一个新实例。 由于一个bean默认的名字就是它的全名,所以一个比较方便的办法就是省略定义中的id属性:

<bean class="com.xyz.myapp.domain.Account"
singleton="false">
<property name="fundsTransferService" ref="fundsTransferService"/>
...
</bean>

如果你希望明确的指定bean原型定义的名字,你可以在注解中直接定义:

package com.xyz.myapp.domain;
import org.springframework.beans.factory.annotation;
@Configurable("account")
public class Account {
...

Spring会查找名字为"account"的bean定义,并使用它作为原型定义来配置一个新的Account对象。

你也可以使用自动装配来避免手工指定原型定义的名字。 只要设置 @Configurable 注解中的autowire属性就可以让Spring来自动装配了: @Configurable(autowire=Autowire.BY_TYPE) 或者 @Configurable(autowire=Autowire.BY_NAME,这样就可以按类型或者按名字自动装配了。

最后,你可以设置 dependencyCheck 属性,通过设置,Spring对新创建和配置的对象的对象引用进行校验 (例如:@Configurable(autowire=Autowire.BY_NAME,dependencyCheck=true) )。 如果这个属性被设为true,Spring会在配置结束后校验除了primitives和collections类型的所有的属性是否都被赋值了。

仅仅使用注解并没有做任何事情。但当注解存在时,spring-aspects.jar中的 AnnotationBeanConfigurerAspect 就起作用了。 实质上切面做了这些:当初始化一个有 @Configurable 注解的新对象时,Spring按照注解中的属性来配置这个新创建的对象。 要实现上述的操作,已注解的类型必须由AspectJ weaver来织入 - 你可以使用一个 build-time ant/maven任务来完成 (参见AspectJ Development Environment Guide) 或者使用load-time weaving(参见 Section 6.7.4, “在Spring应用中使用AspectJ Load-time weaving(LTW)”)。

类 AnnotationBeanConfigurerAspect 本身也需要Spring来配置(获得bean factory的引用,使用bean factory配置新的对象)。 为此Spring AOP命名空间定义了一个非常方便的标签。如下所示,可以很简单的在application context配置文件包含这个标签中。

<aop:spring-configured/>

如果你使用DTD代替Schema,对应的定义如下:

<bean
class="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect"
factory-method="aspectOf"/>

在切面配置完成 之前 创建的@Configurable对象实例会导致在log中留下一个warning,并且任何对于该对象的配置都不会生效。 举一个例子,一个Spring管理配置的bean在被Spring初始化的时候创建了一个domain object。 对于这样的情况,你需要定义bean属性中的"depends-on"属性来手动指定该bean依赖于configuration切面。

<bean id="myService"
class="com.xzy.myapp.service.MyService"
depends-on="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect">
...
</bean>
6.7.1.1.  @Configurable object的单元测试

提供 @Configurable 支持的一个目的就是使得domain object的单元测试可以独立进行,不需要通过硬编码查找各种倚赖关系。 如果@Configurable 类型没有通过AspectJ织入, 则在单元测试过程中注解不会起到任何作用,测试中你可以简单的为对象的mock或者stub属性赋值,并且和正常情况一样的去使用该对象。 如果 @Configurable 类型通过AspectJ织入, 我们依然可以脱离容器进行单元测试,不过每次创建一个新的 @Configurable 对象时都会看到一个warning标示该对象不受Spring管理配置。

6.7.1.2. 多application context情况下的处理

AnnotationBeanConfigurerAspect 通过一个AspectJ singleton切面来实现对 @Configurable 的支持。 一个singleton切面的作用域和一个静态变量的作用域是一样的,例如,对于每一个classloader有一个切面来定义类型。 这就意味着如果你在一个classloader层次结构中定义了多个application context的时候就需要考虑在哪里定义 <aop:spring-configured/> bean和在哪个classpath下放置Srping-aspects.jar。

考虑一下典型的Spring web项目,一般都是由一个父application context定义大部分business service和所需要的其他资源,然后每一个servlet拥有一个子application context定义。 所有这些context共存于同一个classloader hierarchy下,因此对于全体context,AnnotationBeanConfigurerAspect 仅可以维护一个引用。 在这样的情况下,我们推荐在父application context中定义<aop:spring-configured/> bean: 这里所定义的service可能是你希望注入domain object的。 这样做的结果是你不能为子application context中使用@Configurable的domain object配置bean引用(可能你也根本就不希望那么做!)。

当在一个容器中部署多个web-app的时候,请确保每一个web-application使用自己的classloader来加载spring-aspects.jar中的类(例如将spring-aspects.jar放在WEB-INF/lib目录下)。 如果spring-aspects.jar被放在了容器的classpath下(因此也被父classloader加载),则所有的web application将共享一个aspect实例,这可能并不是你所想要的。

6.7.2. Spring中其他的AspectJ切面

除了 @Configurable 支持,spring-aspects.jar包含了一个AspectJ切面可以用来为那些使用了 @Transactional annotation 的类型和方法驱动Spring事务管理(参见 Chapter 9, 事务管理)。 提供这个的主要目的是有些用户希望脱离Spring容器使用Spring的事务管理。

对于AspectJ程序员,希望使用Spring管理配置和事务管理支持,不过他们不想(或者不能)使用注解,spring-aspects.jar也包含了一些抽象切面供你继承来提供你自己的切入点定义。 参见 AbstractBeanConfigurerAspect 和 AbstractTransactionAspect 的Javadoc获取更多信息。 作为一个例子,下面的代码片断展示了如何编写一个切面,然后通过bean原型定义中和类全名匹配的来配置domian object中所有的实例:

public aspect DomainObjectConfiguration extends AbstractBeanConfigurerAspect {
public DomainObjectConfiguration() {
setBeanWiringInfoResolver(new ClassNameBeanWiringInfoResolver());
}
/**
* The creation of a new bean (any object in the domain model)
*/
protected pointcut beanCreation(Object beanInstance) :
initialization(new(..)) &&
SystemArchitecture.inDomainModel() &&
this(beanInstance);
}

6.7.3. 使用Spring IoC来配置AspectJ的切面

当在Spring application中使用AspectJ的时候,很自然的会想到用Spring来管理这些切面。 AspectJ runtime自身负责切面的创建,这意味着通过Spring来管理AspectJ 创建切面依赖于切面所使用的AspectJ instantiation model(per-clause)。

大多数AspectJ切面都是 singleton 切面。 管理这些切面非常容易,和通常一样创建一个bean定义引用该切面类型就可以了,并且在bean定义中包含 factory-method="aspectOf" 这个属性。 这确保Spring从AspectJ获取切面实例而不是尝试自己去创建该实例。示例如下:

<bean id="profiler" class="com.xyz.profiler.Profiler"
factory-method="aspectOf">
<property name="profilingStrategy" ref="jamonProfilingStrategy"/>
</bean>

对于non-singleton的切面,最简单的配置管理方法是定义一个bean原型定义并且使用@Configurable支持,这样就可以在切面被AspectJ runtime创建后管理它们。

如果你希望一些@AspectJ切面使用AspectJ来织入(例如使用load-time织入domain object) 和另一些@AspectJ切面使用Spring AOP,而这些切面都是由Spring来管理的,那你就需要告诉Spring AOP @AspectJ自动代理支持那些切面需要被自动代理。 你可以通过在 <aop:aspectj-autoproxy> 声明中使用一个或多个 include。 每一个指定了一种命名格式,只有bean命名至少符合其中一种情况下才会使用Spring AOP自动代理配置:

<aop:aspectj-autoproxy>
<include name="thisBean"/>
<include name="thatBean"/>
</aop:aspectj-autoproxy>

6.7.4. 在Spring应用中使用AspectJ Load-time weaving(LTW)

Load-time weaving(LTW)指的是在虚拟机载入字节码文件时动态织入AspectJ切面。 关于LTW的详细信息,请查看 LTW section of the AspectJ Development Environment Guide。 在这里我们重点来看一下Java 5环境下Spring应用如何配置LTW。

LTW需要定义一个 aop.xml,并将其置于META-INF目录。 AspectJ会自动查找所有可见的classpath下的META-INF/aop.xml文件,并且通过定义内容的合集来配置自身。

一个基本的META-INF/aop.xml文件应该如下所示:

<!DOCTYPE aspectj PUBLIC
"-//AspectJ//DTD//EN"	"http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver>
<include within="com.xyz.myapp..*"/>
</weaver>
</aspectj>

'include'的内容告诉AspectJ那些类型需要被纳入织入过程。使用包名前缀并加上"..*"(表示该子包中的所有类型)是一个不错的默认设定。 使用include元素是非常重要的,不然AspectJ会查找每一个应用里面用到的类型(包括Spring的库和其它许多相关库)。通常你并不希望织入这些类型并且不愿意承担AspectJ尝试去匹配的开销。

希望在日志中记录LTW的活动,请添加如下选项:

<!DOCTYPE aspectj PUBLIC
"-//AspectJ//DTD//EN"	"http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver
options="-showWeaveInfo,
-XmessageHandlerClass:org.springframework.aop.aspectj.AspectJWeaverMessageHandler">
<include within="com.xyz.myapp..*"/>
</weaver>
</aspectj>

最后,如果希望精确的控制使用哪些切面,可以使用 aspects。 默认情况下所有定义的切面都将被织入(spring-aspects.jar包含了META-INF/aop.xml,定义了配置管理和事务管理切面)。 如果你在使用spring-aspects.jar,但是只希望使用配制管理切面而不需要事务管理的话,你可以像下面那样定义:

    
    
<! DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN"    "http://www.eclipse.org/aspectj/dtd/aspectj.dtd" > < aspectj > < aspects > < include  within ="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect" /> </ aspects > < weaver options ="-showWeaveInfo,-XmessageHandlerClass:org.springframework.aop.aspectj.AspectJWeaverMessageHandler" > < include  within ="com.xyz.myapp..*" /> </ weaver > </ aspectj >

在Java 5平台下,LTW可以通过虚拟机的参数来启用。

-javaagent:<path-to-ajlibs>/aspectjweaver.jar

6.8. 其它资源

更多关于AspectJ的信息可以查看 AspectJ home page

Eclipse AspectJ by Adrian Colyer et. al. (Addison-Wesley, 2005)全面介绍并提供了AspectJ语言参考。

AspectJ in Action by Ramnivas Laddad (Manning, 2003)是一本非常出色介绍AOP的书籍;全书着重介绍了AspectJ,但也对一些通用的AOP场景进行了比较深入的研究。

分类: Java

什么是控制反转IOC---Spring框架介绍(一)
 

Spring是一个开源的控制反转(Inversion of Control,IOC)  和面向切面(AOP)的容器框架。它的主要目的是简化企业开发。

概念里有两个关键词,很明显是IOC与AOP,弄明白了这两个概念,也就清楚了Spring的概念。

首先来看,什么是IOC。请看下面的业务层实现类PersonServiceBean类

public class PersonServiceBean{
 private PersonDao personDao = new PersonDaoBean();

 public void save(Person person){
   personDao save(person);
}

}

在上述类中,PersonDaoBean 是在应用内部创建及维护的。而所谓的控制反转就是应用本身不负责依赖对象的创建及维护。依赖对象的创建及维护是由外部容器负责的。这样控制权就有应用转移到了外部容器,控制权的转移就是所谓的控制反转。在这里外部容器就是我们的Spring容器。(接下来引入依赖注入的概念)

当我们把依赖对象交给外部容器负责创建,那么PersonServiceBean类可以修改成如下:
public class PersonServiceBean{
  private PersonDao personDao;
 
  public PersonServiceBean(PersonDao personDao){
    this.personDao=personDao;
 }
   public void save(Person person){
     ersonDao.save(person);
}
}
所谓依赖注入(Dependency Injection)就是指,在运行期,由外部容器动态地将依赖对象注入到组件中。

面向切面AOP编程---Spring框架介绍(二)

面向切面(AOP)的概念:Spring提供了面向切面编程的支持,允许通过分离应用的业务逻辑与系统级服务(例如事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。概念比较抽象,下面展示一个使用Spring框架进行AOP编程的案例。

要进行AOP编程,首先必须在Spring的配置文件中引入AOP命名空间(如下阴影部分代码所示)。

<beans xmlns="<a href=" http:="" www.springframework.org="" schema="" beans"="" target="_blank" style="word-wrap: break-word;">http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
        xmlns:aop="http://www.springframework.org/schema/aop"
         xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-2.5.xsd
          http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
           http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx-2.5.xsd" >
                       //  启动对@Aspect注解进行支持

Spring 提供两种切面使用方式(分别是基于XML配置方式和基于注解方式),这里我们采用注解的方式。

第二步,创建业务层业务Bean接口及实现类,代码如下:

接口:

package com.lyk.service;

public interface PersonService {
 public void save(String name);
 public void update(String name, Integer id);
 public String getPersonName(Integer id);
}

实现类:

package com.lyk.service.impl;

import com.lyk.service.PersonService;

public class PersonServiceBean implements PersonService {

 public String getPersonName(Integer id) {
  System.out.println("我是getPersonName()方法");
  return "xxx";
 }

 public void save(String name) {
  throw new RuntimeException("我爱例外");
  //System.out.println("我是save()方法");
 }

 public void update(String name, Integer id) {
  System.out.println("我是update()方法");
 }

}

至此准备工作做好,第三步正式进行AOP开发。编写一个被声明为切面的类(其中要定义切入点、定义环绕通知等)。代码如下:

package com.lyk.service;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
 * 切面
 *
 */
@Aspect
public class MyInterceptor {
 @Pointcut("execution (* com.lyk.service.impl.PersonServiceBean.*(..))")
 private void anyMethod() {}//声明一个切入点
 
 @Before("anyMethod() && args(name)")
 public void doAccessCheck(String name) {
  System.out.println("前置通知:"+ name);
 }
 @AfterReturning(pointcut="anyMethod()",returning="result")
 public void doAfterReturning(String result) {
  System.out.println("后置通知:"+ result);
 }
 @After("anyMethod()")
 public void doAfter() {
  System.out.println("最终通知");
 }
 @AfterThrowing(pointcut="anyMethod()",throwing="e")
 public void doAfterThrowing(Exception e) {
  System.out.println("例外通知:"+ e);
 }
 
 @Around("anyMethod()")
 public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
  //if(){//判断用户是否在权限
  System.out.println("进入方法");
  Object result = pjp.proceed();
  System.out.println("退出方法");
  //}
  return result;
 }
 
}
此外,还要将定义的业务Bean和切面类交给Spring管理,添加相应的配置文件。如下:

        
       

第四步,进行Juit测试。代码如下:

package junit.test;


import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.lyk.service.PersonService;

public class SpringAOPTest {

 @BeforeClass
 public static void setUpBeforeClass() throws Exception {
 }

 @Test public void interceptorTest(){
  ApplicationContext cxt = new ClassPathXmlApplicationContext("beans.xml");
  PersonService personService = (PersonService)cxt.getBean("personService");
  personService.save("xx");
 }
}

如能顺利通过测试,则可看到Junit测试出现绿条,且控制台有正确的结果显示。

over~

 

Spring学习之深入AOP面向切面编程

标签: aopspring编程classobjectbean
  9088人阅读  评论(0)  收藏  举报
  分类:
 

        AOP(Aspect Oriented Programming,面向切面编程)的主要目的是针对业务处理过程中的切面进行提取,所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。可以通过预编译方式和运行时动态代理,实现在不修改源代码的请你工况下,给程序动态添加功能的一种技术。在OOP中模块化的关键单元是类,而在AOP中模块化的单元是切面。切面能对关注点进行模块化,例如横切多个类型和对象的事务管理。在AIP属于中通常成为横切关注点。 

         1、AOP基本概念术语。切面、通知、切入点、引入、代理、织入。

        切面,是指需要实现的交叉功能。是应用系统模块化的一个俄切面或领域。切面最常见的例子是日志记录。一个系统到处都需要日志记录,利用切面就能不侵入的情况下实现该功能。其实切面就是包含定义切面行为的通知和定义切面在什么地方织入的切入点组成。

        通知,就是切面的具体实现,通知将应用系统新的行为加入到系统中。比如在日志例子中,日志通知包含了实现实际日志功能的代码,例如想日志文件写入日志,这个具体的行为就是通知。

        切入点,定义了通知应该应用在那些地方,通知可以应用到系统的任何一个地方,如果想要过滤一些不想通知的地方,就要用到切入点,用来定义切面在什么地方切入。

        引入,允许为已存在类添加新的方法和属性。例如,可以常见一个稽查通知来记录对象的最后修改时间。只要用一个方法setLastModified记忆一个保存状态的变量。可以在不改变已存在类的情况下将这个方法与变量引用,给他们新的行为和封装。即可以让已存在的类实现一个类,并实现其中的方法,从而用新的行为。

         代理,将通知应用到目标对象后创建的对象,对和客户而言,目标对象(应用AOP之前的对象)和代理对象(应用AOP之后的对象)是一样的。就是代理真实主题,系统其他部分不用为了代理对象而改变。 

        织入,就是i将切面应用到目标对象从而创建一个新的代理对象的过程。

        切面在指定连接点织入到目标对象中。

        2、通知Advice。spring可以在多个地方织入通知,所以有多种类型。BeforeAdvice前置通知,AfterReturningAdivce后置通知,AfterThrowingAdvice异常通知,AroundAdice环绕通知,IntroductionAdvice引入通知。前置通知接口的一个实现:MethodBeforeAdvice,其中有个方法如下:

[java]  view plain  copy
 print ?
  1. <span style="font-family: Arial, Verdana, sans-serif; background-color: rgb(255, 255, 255); ">  
  2. </span>  
[java]  view plain  copy
 print ?
  1. void before(Method method,Object [] args, Object target);  
代理工厂的配置代码如下:
[html]  view plain  copy
 print ?
  1. <bean id="reception" class="org.framework.aop.framework.ProxyFactoryBean" >  
  2. <property name="proxyInterfaces" value="before.Reception" />  
  3. <property name="interceptorNames" value="greeting" />  
  4. <property name="target" ref="target /">  
  5. </bean>  
        后置通知和前置通知差不多一样的配置和是吸纳方法。
        环绕通知比较特殊,有两个特殊的地方,1)该接口MethodInterceptor 能控制目标方法是否真被调用,可以通过MethodIncovation.proceed()方法来调用目标方法,这一点不同于MethodBeforeAdvice,目标方法总是被调用,除非抛出异常。2)MethodInterceptor可以控制返回的对象,也就是说可以返回一个与proceed()方法返回的对象完全不同的对象。而是用AfterReturningAdvice则不能返回一个不同的对象。
        异常通知ThrowableAdivice是用来处理在方法调用过程中产生的错误或异常。

        引入通知IntroductionInterceptor,可以进行混合业务逻辑,可以在原有的类的基础上进行扩展。例如在原有的People类中引入记录执行时间的功能。代码如下:

[java]  view plain  copy
 print ?
  1. public class ExecuteTimeImpl implements InterductionInterceptor, ExecuteTimeInterface{  
  2.     public boolean implementsInterface(Class in) {//用于实现制定的接口,实现则返回true  
  3.         return in.isAssignableFrom(ExecuTimeInterface.class);  
  4.     }  
  5.     public Object invoke(MethodInvocation m) throws Throwable {  
  6.         if(implementsInterface(m.getMethod().getDeclaringClass()))  
  7.             return m.getMethod().invoke(this, m.getArguments());//调用引用的方法  
  8.         else   
  9.             return m.proceed();//委托其他方法  
  10.     }  
  11.     public void printExecuteTime() {  
  12.         System.out.println("时间:"+new SimpleDateFormate("yyyy-MM-dd").format(new Date));  
  13.     }  
  14. }  


这样就在原来的基础上加入了记录时间的方法,对原有的类没进行修改,不造成影响。
      3、切入点Pointcut。切入点可以确定在什么地方将通知织入到目标类中。Spring通过org.springframework.aop.Pointcut接口描述切点,该接口由ClassFilter和MethodMatcher构成。即Pointcut有两个方法:getClassFilter(), getMethodMatcher()。分别进行类过滤和方法过滤。类过滤:ClassFiler接口仅有一个方法Boolean matcher(Class clazz);用于过滤类,匹配过滤条件则返回true。方法过滤:MethodMatcher接口有三个方法,Boolean isRuntime(),判断MethodMatcher的类型是静态的还是动态的。Boolean matches(Method method, class targetClass); 用来过滤方法。
      4、切面Advisor。切面是由通知和切点组成的。切面分为一般切面,切点切面和引入切面,较常用的是切点切面。静态切入点的实现类的一个例子如下所示:

[java]  view plain  copy
 print ?
  1. public class PeopleAdvisor extends StaticMethodMatcherPointcutAdvisor{  
  2.     public boolean matches(Method method, Class clazz) {  
  3.         return "speaking".equals(method.getName);  
  4.     }   
  5.     public ClassFilter getClassFilter() {  
  6.         return new ClassFilter(){  
  7.             return new ClassFilter() {   
  8.                 public boolean matche(Class clazz){  
  9.                     return People.class.isAssignableFrom(clazz);//用于类过滤,判断是不是People即他的子类  
  10.                 }  
  11.             };  
  12.     }  
  13. }  

配置如下:

[html]  view plain  copy
 print ?
  1. <bean id="people" class="org.framework.aop.framework.ProxyFactoryBean" >  
  2. <property name="interceptorNames"><idref local="peopleAdvisor" /> </peoperty><!--定义的是切面而不是通知-->  
  3. <property name="target" ref="target /">  
  4. </bean>  

Spring AOP源码分析(拦截器调用的实现)

标签: spring
  325人阅读  评论(0)  收藏  举报
  分类:
 

目录(?)[+]

spring AOP通过JDK或者Cglib的方式生成代理对象的时候,相关的拦截器已经配置到代理对象中去了,拦截器在代理对象中的作用是通过对这些方法的回调完成的。

JDKDynamicAopProxy的invoke拦截

<code class="hljs oxygene has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">@<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Override</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Object invoke(Object proxy, <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Method</span> <span class="hljs-title" style="box-sizing: border-box;">method</span>, <span class="hljs-title" style="box-sizing: border-box;">Object</span>[] <span class="hljs-title" style="box-sizing: border-box;">args</span>) <span class="hljs-title" style="box-sizing: border-box;">throws</span> <span class="hljs-title" style="box-sizing: border-box;">Throwable</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">{
    MethodInvocation invocation;
    Object oldProxy = null;
    boolean setProxyContext = false;

    TargetSource targetSource = this.advised.targetSource;
    Class<?> targetClass = null;
    Object target = null;

    try {
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            // If the target does not implement the equals(Object) method itself.
            return equals(args[0]);
        }</span>
        <span class="hljs-title" style="box-sizing: border-box;">if</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(!this.hashCodeDefined && AopUtils.isHashCodeMethod(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">method</span>)</span>) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">{
            // If the target does not implement the hashCode() method itself.
            return hashCode();
        }</span>
        <span class="hljs-title" style="box-sizing: border-box;">if</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(!this.advised.opaque && <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">method</span>.getDeclaringClass()</span>.<span class="hljs-title" style="box-sizing: border-box;">isInterface</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> &&
                <span class="hljs-title" style="box-sizing: border-box;">method</span>.<span class="hljs-title" style="box-sizing: border-box;">getDeclaringClass</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span>.<span class="hljs-title" style="box-sizing: border-box;">isAssignableFrom</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(Advised.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span>)</span>) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">{
            // Service invocations on ProxyConfig with the proxy config...
            // 根据代理对象的配置来调用服务
            return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
        }</span>

        <span class="hljs-title" style="box-sizing: border-box;">Object</span> <span class="hljs-title" style="box-sizing: border-box;">retVal</span>;</span>

        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (this.advised.exposeProxy) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">{
            // Make invocation available if necessary.
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }</span>

        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// May be null. Get as late as possible to minimize the time we "own" the target,</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// in case it comes from a pool.</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 得到目标对象的地方</span>
        target = targetSource.getTarget();
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (target != null) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">{
            targetClass = target.getClass();
        }</span>

        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Get the interception chain for this method.</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 这里是定义好的拦截器链</span>
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">method</span>, <span class="hljs-title" style="box-sizing: border-box;">targetClass</span>);</span>

        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Check whether we have any advice. If we don't, we can fallback on direct</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// reflective invocation of the target, and avoid creating a MethodInvocation.</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 如果没有定义拦截器链,那么直接调用target对应方法</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (chain.isEmpty()) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">{
            // We can skip creating a MethodInvocation: just invoke the target directly
            // Note that the final invoker must be an InvokerInterceptor so we know it does
            // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        }</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">{
            // We need to create a method invocation...
            // 如果有拦截器链的设定,那么需要调用拦截器之后才调用目标对象方法
            // 通过构造一个ReflectiveMethodInovation来实现
            invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // Proceed to the joinpoint through the interceptor chain.
            // 沿着拦截器链继续前进
            retVal = invocation.proceed();
        }</span>

        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Massage return value if necessary.</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Class</span><?> returnType = <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">method</span>.<span class="hljs-title" style="box-sizing: border-box;">getReturnType</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span>;</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (retVal != null && retVal == target && returnType.isInstance(proxy) &&
                !RawTargetAccess.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span>.isAssignableFrom(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">method</span>.<span class="hljs-title" style="box-sizing: border-box;">getDeclaringClass</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span>)) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">{
            // Special case: it returned "this" and the return type of the method
            // is type-compatible. Note that we can't help if the target sets
            // a reference to itself in another returned object.
            retVal = proxy;
        }</span>
        <span class="hljs-title" style="box-sizing: border-box;">else</span> <span class="hljs-title" style="box-sizing: border-box;">if</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(retVal == null && returnType != Void.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">TYPE</span> && returnType.isPrimitive()</span>) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">{
            throw new AopInvocationException(
                    "Null return value from advice does not match primitive return type for: " + method);
        }</span>
        <span class="hljs-title" style="box-sizing: border-box;">return</span> <span class="hljs-title" style="box-sizing: border-box;">retVal</span>;</span>
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">finally</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">{
        if (target != null && !targetSource.isStatic()) {
            // Must have come from TargetSource.
            targetSource.releaseTarget(target);
        }</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (setProxyContext) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">{
            // Restore old proxy.
            AopContext.setCurrentProxy(oldProxy);
        }</span>
    }
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li><li style="box-sizing: border-box; padding: 0px 5px;">75</li><li style="box-sizing: border-box; padding: 0px 5px;">76</li><li style="box-sizing: border-box; padding: 0px 5px;">77</li><li style="box-sizing: border-box; padding: 0px 5px;">78</li><li style="box-sizing: border-box; padding: 0px 5px;">79</li><li style="box-sizing: border-box; padding: 0px 5px;">80</li><li style="box-sizing: border-box; padding: 0px 5px;">81</li><li style="box-sizing: border-box; padding: 0px 5px;">82</li><li style="box-sizing: border-box; padding: 0px 5px;">83</li><li style="box-sizing: border-box; padding: 0px 5px;">84</li><li style="box-sizing: border-box; padding: 0px 5px;">85</li><li style="box-sizing: border-box; padding: 0px 5px;">86</li><li style="box-sizing: border-box; padding: 0px 5px;">87</li><li style="box-sizing: border-box; padding: 0px 5px;">88</li><li style="box-sizing: border-box; padding: 0px 5px;">89</li><li style="box-sizing: border-box; padding: 0px 5px;">90</li><li style="box-sizing: border-box; padding: 0px 5px;">91</li><li style="box-sizing: border-box; padding: 0px 5px;">92</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li><li style="box-sizing: border-box; padding: 0px 5px;">75</li><li style="box-sizing: border-box; padding: 0px 5px;">76</li><li style="box-sizing: border-box; padding: 0px 5px;">77</li><li style="box-sizing: border-box; padding: 0px 5px;">78</li><li style="box-sizing: border-box; padding: 0px 5px;">79</li><li style="box-sizing: border-box; padding: 0px 5px;">80</li><li style="box-sizing: border-box; padding: 0px 5px;">81</li><li style="box-sizing: border-box; padding: 0px 5px;">82</li><li style="box-sizing: border-box; padding: 0px 5px;">83</li><li style="box-sizing: border-box; padding: 0px 5px;">84</li><li style="box-sizing: border-box; padding: 0px 5px;">85</li><li style="box-sizing: border-box; padding: 0px 5px;">86</li><li style="box-sizing: border-box; padding: 0px 5px;">87</li><li style="box-sizing: border-box; padding: 0px 5px;">88</li><li style="box-sizing: border-box; padding: 0px 5px;">89</li><li style="box-sizing: border-box; padding: 0px 5px;">90</li><li style="box-sizing: border-box; padding: 0px 5px;">91</li><li style="box-sizing: border-box; padding: 0px 5px;">92</li></ul>

可以看到在执行拦截器链是递归前进的:

ReflectiveMethodInvocation的proceed

<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Object <span class="hljs-title" style="box-sizing: border-box;">proceed</span>() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Throwable {
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//  We start with an index of -1 and increment early.</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 从索引为-1的拦截器开始调用,并按序递增</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 如果拦截器链中的拦截器迭代调用完毕,这里开始调用target函数,通过反射</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.currentInterceptorIndex == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.interceptorsAndDynamicMethodMatchers.size() - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> invokeJoinpoint();
    }

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 这里沿着定义好的 interceptorOrInterceptionAdvice链进行处理</span>
    Object interceptorOrInterceptionAdvice =
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.interceptorsAndDynamicMethodMatchers.get(++<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.currentInterceptorIndex);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (interceptorOrInterceptionAdvice <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">instanceof</span> InterceptorAndDynamicMethodMatcher) {
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Evaluate dynamic method matcher here: static part will already have</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// been evaluated and found to match.</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 这里对拦截器链进行匹配,如果和定义的PointCut匹配,这个Advice会得到执行</span>
        InterceptorAndDynamicMethodMatcher dm =
                (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (dm.methodMatcher.matches(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.method, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.targetClass, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.arguments)) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> dm.interceptor.invoke(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>);
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {
            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Dynamic matching failed.</span>
            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Skip this interceptor and invoke the next in the chain.</span>
            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 如果不匹配,那么proceed递归调用,知道所有的拦截器都被运行过为止</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> proceed();
        }
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// It's an interceptor, so we just invoke it: The pointcut will have</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// been evaluated statically before this object was constructed.</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 如果是一个interceptor,直接调用这个interceptor对应的方法</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>);
    }
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li></ul>

Cglib2AopProxy的拦截

DynamicAdvisedInteceptor的intercept:

<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">DynamicAdvisedInterceptor</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">MethodInterceptor</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Serializable</span> {</span>

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> AdvisedSupport advised;

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">DynamicAdvisedInterceptor</span>(AdvisedSupport advised) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.advised = advised;
    }

    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Object <span class="hljs-title" style="box-sizing: border-box;">intercept</span>(Object proxy, Method method, Object[] args, MethodProxy methodProxy) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Throwable {
        Object oldProxy = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> setProxyContext = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>;
        Class<?> targetClass = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>;
        Object target = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.advised.exposeProxy) {
                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Make invocation available if necessary.</span>
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>;
            }
            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// May be null. Get as late as possible to minimize the time we</span>
            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// "own" the target, in case it comes from a pool...</span>
            target = getTarget();
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (target != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {
                targetClass = target.getClass();
            }
            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 从advised中取得配置好的通知</span>
            List<Object> chain = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
            Object retVal;
            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Check whether we only have one InvokerInterceptor: that is,</span>
            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// no real advice, but just reflective invocation of the target.</span>
            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 如果没有AOP通知配置,那么直接调用target对象的调用方法</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// We can skip creating a MethodInvocation: just invoke the target directly.</span>
                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Note that the final invoker must be an InvokerInterceptor, so we know</span>
                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// it does nothing but a reflective operation on the target, and no hot</span>
                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// swapping or fancy proxying.</span>
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                retVal = methodProxy.invoke(target, argsToUse);
            }
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {
                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// We need to create a method invocation...</span>
                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 通过CglibMethodInvocation来启动通知</span>
                retVal = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
            }
            retVal = processReturnType(proxy, target, method, retVal);
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> retVal;
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">finally</span> {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (target != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {
                releaseTarget(target);
            }
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (setProxyContext) {
                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Restore old proxy.</span>
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }

    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> <span class="hljs-title" style="box-sizing: border-box;">equals</span>(Object other) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span> == other ||
                (other <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">instanceof</span> DynamicAdvisedInterceptor &&
                        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.advised.equals(((DynamicAdvisedInterceptor) other).advised)));
    }

    <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
     * CGLIB uses this to drive proxy creation.
     */</span>
    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> <span class="hljs-title" style="box-sizing: border-box;">hashCode</span>() {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.advised.hashCode();
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> Object <span class="hljs-title" style="box-sizing: border-box;">getTarget</span>() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Exception {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.advised.getTargetSource().getTarget();
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">releaseTarget</span>(Object target) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Exception {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.advised.getTargetSource().releaseTarget(target);
    }
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li><li style="box-sizing: border-box; padding: 0px 5px;">75</li><li style="box-sizing: border-box; padding: 0px 5px;">76</li><li style="box-sizing: border-box; padding: 0px 5px;">77</li><li style="box-sizing: border-box; padding: 0px 5px;">78</li><li style="box-sizing: border-box; padding: 0px 5px;">79</li><li style="box-sizing: border-box; padding: 0px 5px;">80</li><li style="box-sizing: border-box; padding: 0px 5px;">81</li><li style="box-sizing: border-box; padding: 0px 5px;">82</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li><li style="box-sizing: border-box; padding: 0px 5px;">75</li><li style="box-sizing: border-box; padding: 0px 5px;">76</li><li style="box-sizing: border-box; padding: 0px 5px;">77</li><li style="box-sizing: border-box; padding: 0px 5px;">78</li><li style="box-sizing: border-box; padding: 0px 5px;">79</li><li style="box-sizing: border-box; padding: 0px 5px;">80</li><li style="box-sizing: border-box; padding: 0px 5px;">81</li><li style="box-sizing: border-box; padding: 0px 5px;">82</li></ul>

目标方法的调用

如果没有实现拦截器链(链为空),那么直接调用目标方法: 
JdkDynamicAopProxy是通过反射实现的: 
AopUtils的invokeJoinpointUsingReflection

<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> Object <span class="hljs-title" style="box-sizing: border-box;">invokeJoinpointUsingReflection</span>(Object target, Method method, Object[] args)
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Throwable {

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Use reflection to invoke the method.</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> {
        ReflectionUtils.makeAccessible(method);
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> method.invoke(target, args);
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (InvocationTargetException ex) {
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Invoked method threw a checked exception.</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// We must rethrow it. The client won't see the interceptor.</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> ex.getTargetException();
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (IllegalArgumentException ex) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> AopInvocationException(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"AOP configuration seems to be invalid: tried calling method ["</span> +
                method + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"] on target ["</span> + target + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"]"</span>, ex);
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (IllegalAccessException ex) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> AopInvocationException(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Could not access method ["</span> + method + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"]"</span>, ex);
    }
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li></ul>

Cglib2AopProxy:

<code class="hljs fix has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-attribute" style="box-sizing: border-box;">retVal </span>=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"> methodProxy.invoke(target, argsToUse);</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

Aop拦截器链的调用

两种代理拦截器链的调用都是ReflectionMethodInvocation的proceed方法。 
在proceed方法中,会逐个运行拦截器的拦截方法。 
在运行拦截器的拦截方法之前,需要对代理方法加一个匹配判断,通过这个匹配判断来决定拦截器是否满足切面增强的要求。 
这里是PointCut中进行matches的匹配过程(见上面的proceed分析)

配置通知器

获取拦截器链是在DynamicAdvisedInterceptor的intercept中,是通过AdvisedSupport的getInterceptsAndDynamicInterceptionAdvice获取的。 
在取得拦截器链的同时,为提高取得拦截器链的效率,还为这个拦截器链设置的缓存:

<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">AdvisedSupport</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ProxyConfig</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Advised</span> {</span>

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> List<Object> <span class="hljs-title" style="box-sizing: border-box;">getInterceptorsAndDynamicInterceptionAdvice</span>(Method method, Class<?> targetClass) {
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 这里使用cache,利用cache获取已有的inteceptor链,但是第一次还是需要自己动手生成。</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 这个inteceptor链的生成是由 advisorChainFactory完成的</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 这里使用的是DefaultAdvisorChainFactory</span>
        MethodCacheKey cacheKey = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> MethodCacheKey(method);
        List<Object> cached = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.methodCache.get(cacheKey);
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (cached == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {
            cached = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>, method, targetClass);
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.methodCache.put(cacheKey, cached);
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> cached;
    }
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>

DefaultAdvisorChainFactory实现了intecept链的获取过程:

<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 得到注册器GlobalAdvisorAdapterRegistry,这是单例模式</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> List<Object> <span class="hljs-title" style="box-sizing: border-box;">getInterceptorsAndDynamicInterceptionAdvice</span>(
        Advised config, Method method, Class<?> targetClass) {

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// This is somewhat tricky... We have to process introductions first,</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// but we need to preserve order in the ultimate list.</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 根据通知器的个数初始化一个List,xml中对ProxyFactoryBean做的inteceptNames属性的配置</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// advisor链已经在config中持有了,可以直接使用</span>
    List<Object> interceptorList = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ArrayList<Object>(config.getAdvisors().length);
    Class<?> actualClass = (targetClass != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> ? targetClass : method.getDeclaringClass());
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> hasIntroductions = hasMatchingIntroductions(config, actualClass);
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// registry 用于实现拦截器的注册,用它对从ProxyFactoryBean配置中得到的通知器进行适配,从而获取相应的拦截器,再把它加入到前面配置好的List中</span>
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (Advisor advisor : config.getAdvisors()) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (advisor <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">instanceof</span> PointcutAdvisor) {
            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Add it conditionally.</span>
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 拦截器链是通过AdvisorAdapterRegistory加入的,对advice的织入起到很大作用</span>
            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 从GlobalAdvisorAdapterRegistry取得MethodInterceptor实现</span>
                MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
                    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mm.isRuntime()) {
                        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Creating a new object instance in the getInterceptors() method</span>
                        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// isn't a problem as we normally cache created chains.</span>
                        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 在getInterceptors方法中创建新的对象实例</span>
                        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (MethodInterceptor interceptor : interceptors) {
                            interceptorList.add(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> InterceptorAndDynamicMethodMatcher(interceptor, mm));
                        }
                    }
                    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {
                        interceptorList.addAll(Arrays.asList(interceptors));
                    }
                }
            }
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (advisor <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">instanceof</span> IntroductionAdvisor) {
            IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
        }
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> interceptorList;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 判断Advisors是否符合实际要求</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> <span class="hljs-title" style="box-sizing: border-box;">hasMatchingIntroductions</span>(Advised config, Class<?> actualClass) {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i < config.getAdvisors().length; i++) {
        Advisor advisor = config.getAdvisors()[i];
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (advisor <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">instanceof</span> IntroductionAdvisor) {
            IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (ia.getClassFilter().matches(actualClass)) {
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>;
            }
        }
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li></ul>

在拦截器适配和注册过程完成后,List中的拦截器会被JDK生成的AopProxy代理对象的invoke方法或者CGLIB代理对象的intecept方法拦截,并启动拦截器的invoke调用,最终触发通知的切面增强。

在拦截器链的初始化中获取advisor通知器 
ProxyFactoryBean的initializeAdvisorChain:

<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">synchronized</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">initializeAdvisorChain</span>() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> AopConfigException, BeansException {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.advisorChainInitialized) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>;
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!ObjectUtils.isEmpty(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.interceptorNames)) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.beanFactory == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> IllegalStateException(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"No BeanFactory available anymore (probably due to serialization) "</span> +
                    <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"- cannot resolve interceptor names "</span> + Arrays.asList(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.interceptorNames));
        }

        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Globals can't be last unless we specified a targetSource using the property...</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.interceptorNames[<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.interceptorNames.length - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>].endsWith(GLOBAL_SUFFIX) &&
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.targetName == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> && <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.targetSource == EMPTY_TARGET_SOURCE) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> AopConfigException(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Target required after globals"</span>);
        }

        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Materialize interceptor chain from bean names.</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (String name : <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.interceptorNames) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (logger.isTraceEnabled()) {
                logger.trace(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Configuring advisor or advice '"</span> + name + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"'"</span>);
            }

            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (name.endsWith(GLOBAL_SUFFIX)) {
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.beanFactory <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">instanceof</span> ListableBeanFactory)) {
                    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> AopConfigException(
                            <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Can only use global advisors or interceptors with a ListableBeanFactory"</span>);
                }
                addGlobalAdvisor((ListableBeanFactory) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.beanFactory,
                        name.substring(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, name.length() - GLOBAL_SUFFIX.length()));
            }

            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {
                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// If we get here, we need to add a named interceptor.</span>
                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// We must check if it's a singleton or prototype.</span>
                Object advice;
                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 判断Bean类型是singleTon还是protoType</span>
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.singleton || <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.beanFactory.isSingleton(name)) {
                    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Add the real Advisor/Advice to the chain.</span>
                    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 这里取得advisor的地方,是通过BeanFactory获得的</span>
                    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 把interceptNames这个List中的interceptor名字交给BeanFactory,然后通过BeanFactory的getBean获取</span>
                    advice = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.beanFactory.getBean(name);
                }
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {
                    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// It's a prototype Advice or Advisor: replace with a prototype.</span>
                    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Avoid unnecessary creation of prototype bean just for advisor chain initialization.</span>
                    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 如果bean类型是Prototype</span>
                    advice = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> PrototypePlaceholderAdvisor(name);
                }
                addAdvisorOnChainCreation(advice, name);
            }
        }
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.advisorChainInitialized = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li></ul>

ProxyFactoryBean需要实现BeanFactoryAware接口,然后才能把BeanFactory设置进去,ProxyFactoryBean才能获取IOC容器(一般是DefaultListableBeanFactory)。 
注意ProxyFactoryBean是一个Bean,也需要配置的。

<code class="hljs php has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ProxyFactoryBean</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ProxyCreatorSupport</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">FactoryBean</span><<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Object</span>>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">BeanClassLoaderAware</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">BeanFactoryAware</span></span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>

这样,ProxyFactoryBean就能根据IOC容器的getBean获取在Bean定义文件中的通知器了。

IOC容器对ProxyFactoryBean依赖注入时,会将ProxyFactoryBean给出的通知器名字直接注入到FactoryBean的interceptorNames属性中。

Advice通知的实现

由GlobalAdvisorAdapterRegistory完成拦截器的适配和注册过程: 
DefaultAdvisorChainFactory见上文

registry 其实是一个 DefaultAdvisorAdapterRegistry单件,DefaultAdvisorAdapterRegistory中有许多适配器,为Spring AOP advice提供编织能力:

<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">DefaultAdvisorAdapterRegistry</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">AdvisorAdapterRegistry</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Serializable</span> {</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 这个List是对应advice功能的</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> List<AdvisorAdapter> adapters = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ArrayList<AdvisorAdapter>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>);


    <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
     * Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters.
     */</span>

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">DefaultAdvisorAdapterRegistry</span>() {
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 已有的advice实现功能加进来,before,afterReturn,throw</span>
        registerAdvisorAdapter(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> MethodBeforeAdviceAdapter());
        registerAdvisorAdapter(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> AfterReturningAdviceAdapter());
        registerAdvisorAdapter(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ThrowsAdviceAdapter());
    }


    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Advisor <span class="hljs-title" style="box-sizing: border-box;">wrap</span>(Object adviceObject) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> UnknownAdviceTypeException {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (adviceObject <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">instanceof</span> Advisor) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> (Advisor) adviceObject;
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!(adviceObject <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">instanceof</span> Advice)) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> UnknownAdviceTypeException(adviceObject);
        }
        Advice advice = (Advice) adviceObject;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (advice <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">instanceof</span> MethodInterceptor) {
            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// So well-known it doesn't even need an adapter.</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> DefaultPointcutAdvisor(advice);
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (AdvisorAdapter adapter : <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.adapters) {
            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Check that it is supported.</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (adapter.supportsAdvice(advice)) {
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> DefaultPointcutAdvisor(advice);
            }
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> UnknownAdviceTypeException(advice);
    }

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// DefaultAdvisorChainFactory中启动的getinterceptors方法</span>
    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> MethodInterceptor[] <span class="hljs-title" style="box-sizing: border-box;">getInterceptors</span>(Advisor advisor) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> UnknownAdviceTypeException {
        List<MethodInterceptor> interceptors = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ArrayList<MethodInterceptor>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>);
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//从advisor通知器配置中取得advice通知</span>
        Advice advice = advisor.getAdvice();
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// </span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (advice <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">instanceof</span> MethodInterceptor) {
            interceptors.add((MethodInterceptor) advice);
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (AdvisorAdapter adapter : <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.adapters) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (adapter.supportsAdvice(advice)) {
                interceptors.add(adapter.getInterceptor(advisor));
            }
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (interceptors.isEmpty()) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> UnknownAdviceTypeException(advisor.getAdvice());
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> interceptors.toArray(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> MethodInterceptor[interceptors.size()]);
    }

    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">registerAdvisorAdapter</span>(AdvisorAdapter adapter) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.adapters.add(adapter);
    }

}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li></ul>

这里用到适配器模式,比如MethodBeforeAdviceAdapter:

<code class="hljs php has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">MethodBeforeAdviceAdapter</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">AdvisorAdapter</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Serializable</span> {</span>

    @Override
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> boolean supportsAdvice(Advice advice) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> (advice <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">instanceof</span> MethodBeforeAdvice);
    }

    @Override
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> MethodInterceptor getInterceptor(Advisor advisor) {
        MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> MethodBeforeAdviceInterceptor(advice);
    }

}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li></ul>

MethodBeforeAdviceInterceptor实现:

<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">MethodBeforeAdviceInterceptor</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">MethodInterceptor</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Serializable</span> {</span>

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> MethodBeforeAdvice advice;

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 为指定的Advice创建对应的MethodBeforeAdvice</span>
    <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
     * Create a new MethodBeforeAdviceInterceptor for the given advice.
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> advice the MethodBeforeAdvice to wrap
     */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">MethodBeforeAdviceInterceptor</span>(MethodBeforeAdvice advice) {
        Assert.notNull(advice, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Advice must not be null"</span>);
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.advice = advice;
    }

    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//会在代理对象的方法被调用时回调</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Object <span class="hljs-title" style="box-sizing: border-box;">invoke</span>(MethodInvocation mi) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Throwable {
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//先执行advice的before方法,在方法调用之前完成通知增强</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> mi.proceed();
    }

}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul>

类似的,看AfterReturningAdviceInterceptor:

<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@SuppressWarnings</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"serial"</span>)
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">AfterReturningAdviceInterceptor</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">MethodInterceptor</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">AfterAdvice</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Serializable</span> {</span>

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> AfterReturningAdvice advice;


    <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
     * Create a new AfterReturningAdviceInterceptor for the given advice.
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> advice the AfterReturningAdvice to wrap
     */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">AfterReturningAdviceInterceptor</span>(AfterReturningAdvice advice) {
        Assert.notNull(advice, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Advice must not be null"</span>);
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.advice = advice;
    }

    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Object <span class="hljs-title" style="box-sizing: border-box;">invoke</span>(MethodInvocation mi) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Throwable {
        Object retVal = mi.proceed();
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> retVal;
    }

}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul>

ThrowsAdviceInterceptor:

<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ThrowsAdviceInterceptor</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">MethodInterceptor</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">AfterAdvice</span> {</span>

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> String AFTER_THROWING = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"afterThrowing"</span>;

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> Log logger = LogFactory.getLog(ThrowsAdviceInterceptor.class);


    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> Object throwsAdvice;

    <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** Methods on throws advice, keyed by exception class */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> Map<Class<?>, Method> exceptionHandlerMap = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> HashMap<Class<?>, Method>();


    <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
     * Create a new ThrowsAdviceInterceptor for the given ThrowsAdvice.
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> throwsAdvice the advice object that defines the exception
     * handler methods (usually a {@link org.springframework.aop.ThrowsAdvice}
     * implementation)
     */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">ThrowsAdviceInterceptor</span>(Object throwsAdvice) {
        Assert.notNull(throwsAdvice, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Advice must not be null"</span>);
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.throwsAdvice = throwsAdvice;

        Method[] methods = throwsAdvice.getClass().getMethods();
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (Method method : methods) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (method.getName().equals(AFTER_THROWING) &&
                    (method.getParameterTypes().length == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> || method.getParameterTypes().length == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>) &&
                    Throwable.class.isAssignableFrom(method.getParameterTypes()[method.getParameterTypes().length - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>])
                ) {
                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Have an exception handler</span>
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.exceptionHandlerMap.put(method.getParameterTypes()[method.getParameterTypes().length - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>], method);
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (logger.isDebugEnabled()) {
                    logger.debug(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Found exception handler method: "</span> + method);
                }
            }
        }

        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.exceptionHandlerMap.isEmpty()) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> IllegalArgumentException(
                    <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"At least one handler method must be found in class ["</span> + throwsAdvice.getClass() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"]"</span>);
        }
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> <span class="hljs-title" style="box-sizing: border-box;">getHandlerMethodCount</span>() {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.exceptionHandlerMap.size();
    }

    <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
     * Determine the exception handle method. Can return null if not found.
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> exception the exception thrown
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @return</span> a handler for the given exception type
     */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> Method <span class="hljs-title" style="box-sizing: border-box;">getExceptionHandler</span>(Throwable exception) {
        Class<?> exceptionClass = exception.getClass();
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (logger.isTraceEnabled()) {
            logger.trace(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Trying to find handler for exception of type ["</span> + exceptionClass.getName() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"]"</span>);
        }
        Method handler = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.exceptionHandlerMap.get(exceptionClass);
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> (handler == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> && exceptionClass != Throwable.class) {
            exceptionClass = exceptionClass.getSuperclass();
            handler = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.exceptionHandlerMap.get(exceptionClass);
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (handler != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> && logger.isDebugEnabled()) {
            logger.debug(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Found handler for exception of type ["</span> + exceptionClass.getName() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"]: "</span> + handler);
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> handler;
    }

    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Object <span class="hljs-title" style="box-sizing: border-box;">invoke</span>(MethodInvocation mi) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Throwable {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> mi.proceed();
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (Throwable ex) {
            Method handlerMethod = getExceptionHandler(ex);
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (handlerMethod != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {
                invokeHandlerMethod(mi, ex, handlerMethod);
            }
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> ex;
        }
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">invokeHandlerMethod</span>(MethodInvocation mi, Throwable ex, Method method) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Throwable {
        Object[] handlerArgs;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (method.getParameterTypes().length == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) {
            handlerArgs = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Object[] { ex };
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {
            handlerArgs = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Object[] {mi.getMethod(), mi.getArguments(), mi.getThis(), ex};
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> {
            method.invoke(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.throwsAdvice, handlerArgs);
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (InvocationTargetException targetEx) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> targetEx.getTargetException();
        }
    }

}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li><li style="box-sizing: border-box; padding: 0px 5px;">75</li><li style="box-sizing: border-box; padding: 0px 5px;">76</li><li style="box-sizing: border-box; padding: 0px 5px;">77</li><li style="box-sizing: border-box; padding: 0px 5px;">78</li><li style="box-sizing: border-box; padding: 0px 5px;">79</li><li style="box-sizing: border-box; padding: 0px 5px;">80</li><li style="box-sizing: border-box; padding: 0px 5px;">81</li><li style="box-sizing: border-box; padding: 0px 5px;">82</li><li style="box-sizing: border-box; padding: 0px 5px;">83</li><li style="box-sizing: border-box; padding: 0px 5px;">84</li><li style="box-sizing: border-box; padding: 0px 5px;">85</li><li style="box-sizing: border-box; padding: 0px 5px;">86</li><li style="box-sizing: border-box; padding: 0px 5px;">87</li><li style="box-sizing: border-box; padding: 0px 5px;">88</li><li style="box-sizing: border-box; padding: 0px 5px;">89</li><li style="box-sizing: border-box; padding: 0px 5px;">90</li><li style="box-sizing: border-box; padding: 0px 5px;">91</li><li style="box-sizing: border-box; padding: 0px 5px;">92</li><li style="box-sizing: border-box; padding: 0px 5px;">93</li><li style="box-sizing: border-box; padding: 0px 5px;">94</li><li style="box-sizing: border-box; padding: 0px 5px;">95</li><li style="box-sizing: border-box; padding: 0px 5px;">96</li><li style="box-sizing: border-box; padding: 0px 5px;">97</li><li style="box-sizing: border-box; padding: 0px 5px;">98</li><li style="box-sizing: border-box; padding: 0px 5px;">99</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li><li style="box-sizing: border-box; padding: 0px 5px;">75</li><li style="box-sizing: border-box; padding: 0px 5px;">76</li><li style="box-sizing: border-box; padding: 0px 5px;">77</li><li style="box-sizing: border-box; padding: 0px 5px;">78</li><li style="box-sizing: border-box; padding: 0px 5px;">79</li><li style="box-sizing: border-box; padding: 0px 5px;">80</li><li style="box-sizing: border-box; padding: 0px 5px;">81</li><li style="box-sizing: border-box; padding: 0px 5px;">82</li><li style="box-sizing: border-box; padding: 0px 5px;">83</li><li style="box-sizing: border-box; padding: 0px 5px;">84</li><li style="box-sizing: border-box; padding: 0px 5px;">85</li><li style="box-sizing: border-box; padding: 0px 5px;">86</li><li style="box-sizing: border-box; padding: 0px 5px;">87</li><li style="box-sizing: border-box; padding: 0px 5px;">88</li><li style="box-sizing: border-box; padding: 0px 5px;">89</li><li style="box-sizing: border-box; padding: 0px 5px;">90</li><li style="box-sizing: border-box; padding: 0px 5px;">91</li><li style="box-sizing: border-box; padding: 0px 5px;">92</li><li style="box-sizing: border-box; padding: 0px 5px;">93</li><li style="box-sizing: border-box; padding: 0px 5px;">94</li><li style="box-sizing: border-box; padding: 0px 5px;">95</li><li style="box-sizing: border-box; padding: 0px 5px;">96</li><li style="box-sizing: border-box; padding: 0px 5px;">97</li><li style="box-sizing: border-box; padding: 0px 5px;">98</li><li style="box-sizing: border-box; padding: 0px 5px;">99</li></ul>

ProxyFactory实现AOP

在ProxyFactory使用中,需要编程式完成AOP应用的配置。 
ProxyFactory没有使用FactoryBean的IOC封装,而是直接继承ProxyCreatorSupport功能来完成AOP属性配置。 
ProxyFactory也是以getProxy为入口的:

<code class="hljs java has-numbering" style="font-family: 'Source Code Pro', monospace; display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ProxyFactory</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ProxyCreatorSupport</span> {</span>

    <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
     * Create a new ProxyFactory.
     */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">ProxyFactory</span>() {
    }

    <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
     * Create a new ProxyFactory.
     * <p>Will proxy all interfaces that the given target implements.
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> target the target object to be proxied
     */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">ProxyFactory</span>(Object target) {
        setTarget(target);
        setInterfaces(ClassUtils.getAllInterfaces(target));
    }

    <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
     * Create a new ProxyFactory.
     * <p>No target, only interfaces. Must add interceptors.
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> proxyInterfaces the interfaces that the proxy should implement
     */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">ProxyFactory</span>(Class<?>... proxyInterfaces) {
        setInterfaces(proxyInterfaces);
    }

    <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
     * Create a new ProxyFactory for the given interface and interceptor.
     * <p>Convenience method for creating a proxy for a single interceptor,
     * assuming that the interceptor handles all calls itself rather than
     * delegating to a target, like in the case of remoting proxies.
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> proxyInterface the interface that the proxy should implement
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> interceptor the interceptor that the proxy should invoke
     */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">ProxyFactory</span>(Class<?> proxyInterface, Interceptor interceptor) {
        addInterface(proxyInterface);
        addAdvice(interceptor);
    }

    <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
     * Create a ProxyFactory for the specified {@code TargetSource},
     * making the proxy implement the specified interface.
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> proxyInterface the interface that the proxy should implement
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> targetSource the TargetSource that the proxy should invoke
     */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">ProxyFactory</span>(Class<?> proxyInterface, TargetSource targetSource) {
        addInterface(proxyInterface);
        setTargetSource(targetSource);
    }


    <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
     * Create a new proxy according to the settings in this factory.
     * <p>Can be called repeatedly. Effect will vary if we've added
     * or removed interfaces. Can add and remove interceptors.
     * <p>Uses a default class loader: Usually, the thread context class loader
     * (if necessary for proxy creation).
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @return</span> the proxy object
     */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Object <span class="hljs-title" style="box-sizing: border-box;">getProxy</span>() {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> createAopProxy().getProxy();
    }

    <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
     * Create a new proxy according to the settings in this factory.
     * <p>Can be called repeatedly. Effect will vary if we've added
     * or removed interfaces. Can add and remove interceptors.
     * <p>Uses the given class loader (if necessary for proxy creation).
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> classLoader the class loader to create the proxy with
     * (or {@code null} for the low-level proxy facility's default)
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @return</span> the proxy object
     */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Object <span class="hljs-title" style="box-sizing: border-box;">getProxy</span>(ClassLoader classLoader) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> createAopProxy().getProxy(classLoader);
    }


    <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
     * Create a new proxy for the given interface and interceptor.
     * <p>Convenience method for creating a proxy for a single interceptor,
     * assuming that the interceptor handles all calls itself rather than
     * delegating to a target, like in the case of remoting proxies.
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> proxyInterface the interface that the proxy should implement
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> interceptor the interceptor that the proxy should invoke
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @return</span> the proxy object
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @see</span> #ProxyFactory(Class, org.aopalliance.intercept.Interceptor)
     */</span>
    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@SuppressWarnings</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"unchecked"</span>)
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <T> T <span class="hljs-title" style="box-sizing: border-box;">getProxy</span>(Class<T> proxyInterface, Interceptor interceptor) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> (T) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ProxyFactory(proxyInterface, interceptor).getProxy();
    }

    <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
     * Create a proxy for the specified {@code TargetSource},
     * implementing the specified interface.
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> proxyInterface the interface that the proxy should implement
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> targetSource the TargetSource that the proxy should invoke
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @return</span> the proxy object
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @see</span> #ProxyFactory(Class, org.springframework.aop.TargetSource)
     */</span>
    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@SuppressWarnings</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"unchecked"</span>)
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <T> T <span class="hljs-title" style="box-sizing: border-box;">getProxy</span>(Class<T> proxyInterface, TargetSource targetSource) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> (T) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ProxyFactory(proxyInterface, targetSource).getProxy();
    }

    <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
     * Create a proxy for the specified {@code TargetSource} that extends
     * the target class of the {@code TargetSource}.
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> targetSource the TargetSource that the proxy should invoke
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @return</span> the proxy object
     */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> Object <span class="hljs-title" style="box-sizing: border-box;">getProxy</span>(TargetSource targetSource) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (targetSource.getTargetClass() == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> IllegalArgumentException(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Cannot create class proxy for TargetSource with null target class"</span>);
        }
        ProxyFactory proxyFactory = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ProxyFactory();
        proxyFactory.setTargetSource(targetSource);
        proxyFactory.setProxyTargetClass(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>);
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> proxyFactory.getProxy();
    }

}</code><ul class="pre-numbering" style="font-family: 'Source Code Pro', monospace; box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li><li style="box-sizing: border-box; padding: 0px 5px;">75</li><li style="box-sizing: border-box; padding: 0px 5px;">76</li><li style="box-sizing: border-box; padding: 0px 5px;">77</li><li style="box-sizing: border-box; padding: 0px 5px;">78</li><li style="box-sizing: border-box; padding: 0px 5px;">79</li><li style="box-sizing: border-box; padding: 0px 5px;">80</li><li style="box-sizing: border-box; padding: 0px 5px;">81</li><li style="box-sizing: border-box; padding: 0px 5px;">82</li><li style="box-sizing: border-box; padding: 0px 5px;">83</li><li style="box-sizing: border-box; padding: 0px 5px;">84</li><li style="box-sizing: border-box; padding: 0px 5px;">85</li><li style="box-sizing: border-box; padding: 0px 5px;">86</li><li style="box-sizing: border-box; padding: 0px 5px;">87</li><li style="box-sizing: border-box; padding: 0px 5px;">88</li><li style="box-sizing: border-box; padding: 0px 5px;">89</li><li style="box-sizing: border-box; padding: 0px 5px;">90</li><li style="box-sizing: border-box; padding: 0px 5px;">91</li><li style="box-sizing: border-box; padding: 0px 5px;">92</li><li style="box-sizing: border-box; padding: 0px 5px;">93</li><li style="box-sizing: border-box; padding: 0px 5px;">94</li><li style="box-sizing: border-box; padding: 0px 5px;">95</li><li style="box-sizing: border-box; padding: 0px 5px;">96</li><li style="box-sizing: border-box; padding: 0px 5px;">97</li><li style="box-sizing: border-box; padding: 0px 5px;">98</li><li style="box-sizing: border-box; padding: 0px 5px;">99</li><li style="box-sizing: border-box; padding: 0px 5px;">100</li><li style="box-sizing: border-box; padding: 0px 5px;">101</li><li style="box-sizing: border-box; padding: 0px 5px;">102</li><li style="box-sizing: border-box; padding: 0px 5px;">103</li><li style="box-sizing: border-box; padding: 0px 5px;">104</li><li style="box-sizing: border-box; padding: 0px 5px;">105</li><li style="box-sizing: border-box; padding: 0px 5px;">106</li><li style="box-sizing: border-box; padding: 0px 5px;">107</li><li style="box-sizing: border-box; padding: 0px 5px;">108</li><li style="box-sizing: border-box; padding: 0px 5px;">109</li><li style="box-sizing: border-box; padding: 0px 5px;">110</li><li style="box-sizing: border-box; padding: 0px 5px;">111</li><li style="box-sizing: border-box; padding: 0px 5px;">112</li><li style="box-sizing: border-box; padding: 0px 5px;">113</li><li style="box-sizing: border-box; padding: 0px 5px;">114</li><li style="box-sizing: border-box; padding: 0px 5px;">115</li><li style="box-sizing: border-box; padding: 0px 5px;">116</li><li style="box-sizing: border-box; padding: 0px 5px;">117</li><li style="box-sizing: border-box; padding: 0px 5px;">118</li><li style="box-sizing: border-box; padding: 0px 5px;">119</li><li style="box-sizing: border-box; padding: 0px 5px;">120</li><li style="box-sizing: border-box; padding: 0px 5px;">121</li><li style="box-sizing: border-box; padding: 0px 5px;">122</li><li style="box-sizing: border-box; padding: 0px 5px;">123</li></ul><ul class="pre-numbering" style="font-family: 'Source Code Pro', monospace; box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li><li style="box-sizing: border-box; padding: 0px 5px;">75</li><li style="box-sizing: border-box; padding: 0px 5px;">76</li><li style="box-sizing: border-box; padding: 0px 5px;">77</li><li style="box-sizing: border-box; padding: 0px 5px;">78</li><li style="box-sizing: border-box; padding: 0px 5px;">79</li><li style="box-sizing: border-box; padding: 0px 5px;">80</li><li style="box-sizing: border-box; padding: 0px 5px;">81</li><li style="box-sizing: border-box; padding: 0px 5px;">82</li><li style="box-sizing: border-box; padding: 0px 5px;">83</li><li style="box-sizing: border-box; padding: 0px 5px;">84</li><li style="box-sizing: border-box; padding: 0px 5px;">85</li><li style="box-sizing: border-box; padding: 0px 5px;">86</li><li style="box-sizing: border-box; padding: 0px 5px;">87</li><li style="box-sizing: border-box; padding: 0px 5px;">88</li><li style="box-sizing: border-box; padding: 0px 5px;">89</li><li style="box-sizing: border-box; padding: 0px 5px;">90</li><li style="box-sizing: border-box; padding: 0px 5px;">91</li><li style="box-sizing: border-box; padding: 0px 5px;">92</li><li style="box-sizing: border-box; padding: 0px 5px;">93</li><li style="box-sizing: border-box; padding: 0px 5px;">94</li><li style="box-sizing: border-box; padding: 0px 5px;">95</li><li style="box-sizing: border-box; padding: 0px 5px;">96</li><li style="box-sizing: border-box; padding: 0px 5px;">97</li><li style="box-sizing: border-box; padding: 0px 5px;">98</li><li style="box-sizing: border-box; padding: 0px 5px;">99</li><li style="box-sizing: border-box; padding: 0px 5px;">100</li><li style="box-sizing: border-box; padding: 0px 5px;">101</li><li style="box-sizing: border-box; padding: 0px 5px;">102</li><li style="box-sizing: border-box; padding: 0px 5px;">103</li><li style="box-sizing: border-box; padding: 0px 5px;">104</li><li style="box-sizing: border-box; padding: 0px 5px;">105</li><li style="box-sizing: border-box; padding: 0px 5px;">106</li><li style="box-sizing: border-box; padding: 0px 5px;">107</li><li style="box-sizing: border-box; padding: 0px 5px;">108</li><li style="box-sizing: border-box; padding: 0px 5px;">109</li><li style="box-sizing: border-box; padding: 0px 5px;">110</li><li style="box-sizing: border-box; padding: 0px 5px;">111</li><li style="box-sizing: border-box; padding: 0px 5px;">112</li><li style="box-sizing: border-box; padding: 0px 5px;">113</li><li style="box-sizing: border-box; padding: 0px 5px;">114</li><li style="box-sizing: border-box; padding: 0px 5px;">115</li><li style="box-sizing: border-box; padding: 0px 5px;">116</li><li style="box-sizing: border-box; padding: 0px 5px;">117</li><li style="box-sizing: border-box; padding: 0px 5px;">118</li><li style="box-sizing: border-box; padding: 0px 5px;">119</li><li style="box-sizing: border-box; padding: 0px 5px;">120</li><li style="box-sizing: border-box; padding: 0px 5px;">121</li><li style="box-sizing: border-box; padding: 0px 5px;">122</li><li style="box-sizing: border-box; padding: 0px 5px;">123</li></ul><div style="text-align: right;"><span style="font-family:Arial, Console, Verdana, Courier New;">
</span></div><div style="text-align: right;"><span style="font-family:Arial, Console, Verdana, Courier New;">
</span></div>





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值