AOP介绍

一、AOP是什么

AOP,即面向切面编程。AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任,例如事务处理、日志管理、权限控制、异常处理等,封装起来,便于减少系统重复的代码,降低模块之间的耦合度。
  AOP注重的是许多解决问题的方法中的共同点。

AOP

二、AOP的实现

AOP的实现可以分为两种:1.静态织入 2.动态代理

(1)静态AOP
  静态织入就是在编译期,切面直接以字节码的形式编译到目标字节码文件中。这种方式对系统的性能没有影响,但是灵活性不够。

(2)动态AOP

为了实现源码组成无关性,AOP往往通过预编译方式(如AspectJ)和运行期动态代理模式(如Spring AOP)实现。

spring动态AOP有两种方式:

  • JDK动态代理:通过反射和动态编译实现
  • cglib动态代理:通过修改字节码来实现代理

这里我们主要讨论JDK动态代理的方式。
  JDK动态代理的两个核心就是InvokationHandler和Proxy,下面我用一个简单的例子来说明JDK动态代理的实现。
  由于JDK动态代理只能创建指定接口的动态代理,所以下面先提供一个Dog接口:

interface Dog {  
    // info()方法声明  
    public void info();  
  
    // run()方法声明  
    public void run();  
}  

然后为接口Dog创建一个实现方法:

class GunDog implements Dog {  
    // info方法实现,仅仅打印一个字符串  
    @Override  
    public void info() {  
        System.out.println("我是一只猎狗");  
    }  
  
    // run方法实现,仅仅打印一个字符串  
    @Override  
    public void run() {  
        System.out.println("我奔跑迅速");  
    }  
}  

在DogUtil中创建两个通用的方法(公共代码):

class DogUtil {  
    // 第一个拦截器方法  
    public void method1() {  
        System.out.println("-----------模拟第一个通用方法-----------");  
    }  
  
    // 第二个拦截器方法  
    public void method2() {  
        System.out.println("-----------模拟第二个通用方法-----------");  
    }  
}  

假设info()和run()代表两个要调用公共代码的方法,但是不能以硬编码的方式来进行调用,应该怎么办呢?可以借助Proxy和InvocationHandler来实现:当程序调用info()和run()方法时,系统将会"自动"将method1()和method2()两个通用方法插入到info()和run()方法。

class MyInvokationHandlerPro implements InvocationHandler {  
    // 需要被代理的对象  
    private Object target;  
  
    public void setTarget(Object target) {  
        this.target = target;  
    }  
  
    // 执行动态代理对象的所有方法时,都会被替换成执行如下的invoke方法  
    public Object invoke(Object proxy, Method method, Object[] args)  
            throws Exception {  
        DogUtil du = new DogUtil();  
        // 执行DogUtil对象中method1方法  
        du.method1();  
        // 以target作为主调来执行method方法  
        Object result = method.invoke(target, args);  
        // 执行DogUtil对象中method2方法  
        du.method2();  
        return result;  
    }  
}  

上面程序中的类是InvokationHandler的一个实现类,该实现类的invoke方法将会作为代理的方法实现,其中invoke方法包含了一行关键的代码,这行代码以target作为主调通过反射来执行method方法,这就实现了target对象的原有方法。

有了代理处理类以及需要被代理的对象target,我们还需要一段代码为指定的target生成动态代理:

class MyProxyFactory {  
    // 为指定target生成动态代理对象  
    public static Object getProxy(Object target) throws Exception {  
        // 创建一个MyInvokationHandler对象  
        MyInvokationHandlerPro handler = new MyInvokationHandlerPro();  
        // 为MyInvokationHandler设置target对象  
        handler.setTarget(target);  
        // 创建,并返回一个动态代理  
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),  
                target.getClass().getInterfaces(), handler);  
    }  
}  

上面的类是一个动态代理工厂类,它提供了一个getProxy方法,为target对象生成了一个动态代理对象。这个动态代理实现了与target相同的接口,所以动态代理对象可以当成target对象来使用。通俗一点说,就像为明星忙碌的经纪人,他们就是活生生的代理,帮助明星打理事务。
  当程序调用动态代理对象的指定方法的时候,实际上就是执行MyInvokationHandlerPro 的invoke方法。
  下面提供主程序来测试这种动态代理的效果:

public class TestProxy {  
    public static void main(String[] args) throws Exception {  
        // 创建一个原始的GunDog对象,作为target  
        Dog target = new GunDog();  
        // 以指定的target来创建动态代理  
        Dog dog = (Dog) MyProxyFactory.getProxy(target);  
        dog.info();  
        dog.run();  
    }  
}  

程序的执行结果为:

-----------模拟第一个通用方法-----------
我是一只猎狗
-----------模拟第二个通用方法-----------
-----------模拟第一个通用方法-----------
我奔跑迅速
-----------模拟第二个通用方法-----------

上面程序中的dog对象实际上就是动态代理的对象,只是该动态代理对象也实现Dog接口,所以也可以当成Dog对象使用。
  这种动态代理在AOP被称为AOP代理。AOP代理可以替代目标对象,AOP代理包含了目标对象的全部方法。但是AOP代理中的方法与目标对象的方法存在差异:AOP代理里面的方法可以在执行目标方法之前,插入一些通用处理。

三、AOP中的"成员"介绍

连接点(JoinPoint)
  在AOP表示为"在哪里做",它用来定义在程序的什么地方能够通过AOP加入额外的逻辑。

切入点(Pointcut)
  在AOP表示为"在哪里做的集合"。通过创建切入点,我们可以精确地控制程序中什么组件接到什么通知,而一个典型的切入点就是对某一个类的所有方法调用的集合。

通知、增加(Advice)
  在AOP表示为"做什么"。增强即为在连接点上执行的行为,包括前置增强、后置增强、环绕增强。

方面/切面(Aspect)
  在AOP表示为"在哪里做和做什么的集合"。切面是通知和切点的集合,通知和切点共同定义了切面的全部功能——它是什么,在何时何处完成其功能。

顾问(Advisor)
  在Spring中,一个advisor就是一个aspect的完整的模块化标识。一般地,一个advisor包括通知和切入点,是通知和切入点的配置器。

目标对象(Target Object)
  在AOP表示为"对谁做"。目标对象是需要被织入横切关注点的对象,也就是切入点选择的对象、需要被增强的对象。由于Spring AOP通过代理模式实现,从而这个对象永远是被代理对象。

AOP代理(AOP Proxy)
  AOP框架使用代理模式创建的对象,从而实现在连接点处插入增加。Spring中,可以通过JDK动态代理或者CGLIB代理实现AOP代理,通过拦截器模型应用切面

织入(Weaving)
  织入是一个过程,是将切面运用到目标对象从而创建出AOP代理对象的过程。织入是在编译时完成的,它通常是作为编译过程中的一个额外的步骤。

引入(introduction)
  在AOP表示为"做什么(新增什么)"。引入也称为内部类型声明,为已有的类添加额外新的字段或方法。

四、AOP开发步骤

AOP基本运行流程

1.功能横切:找出横切关注点
2.分离关注点:各自独立地实现这些横切关注点所需要完成的功能。
3.根据切入点匹配Target中的方法
4.根据AOP的配置寻找对应的Advice,然后进行重组/织入/结合。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容