`

AOP 的简单入门

阅读更多

 

AOP 的简单入门

 

自己也算是从业多年,对于AOP的概念应该算是听的烂的不能再烂了,这方面的书也看的不少,但是自己一直没有机会去实践下。

乘在这个稍微有点空闲的下午,就随手玩玩SPRING的AOP,也谈谈自己对于AOP的理解及其衍生的一些东西。

 

1.一切术语都是纸老虎

基本概念,也可以说是基本术语。任何一个软件概念提出时候,都少不了这个东西。CRM,AOP,SOA等等,伴随这些东西的都会有相应体系内的术语。

我个人的看法是一切术语的出现不是并不是向大众解释清楚这件事到底是怎么一回事,其主要是基于两个方面考虑:

 

1.让自己提出观点显得系统化,更具有说服力。

2.迷惑大众,或是迷糊那些刚进入这个领域的初学者。

 

两个看似矛盾的因素,其实归结到本质就是将一个简单的东西复杂化并迷糊那些辨别能力的一般的人,大家对于抽象到一定程度的东西但是心怀敬畏之心的,然后带着膜拜的心理去接受,生怕一不小心亵渎了内心的女神。扯开来讲现在社会,官员的道德沦丧,其中的一个诱因就是对于敬畏之心的缺失,当一个人无所畏时,才是最可怕的,因为这个时候已经没有任何约束能约束他的行为。

 

回归正题,既然提到术语,那么我们就将AOP中的那些术语列出来看看。

切面(Aspect)、连接点(Joinpoint)、通知(Advice)、切入点(Pointcut) 、目标对象(Target Object)、AOP代理(AOP Proxy)。

通知又分为几种:前置通知(Before advice)、后通知(After advice)、返回后通知(After return advice)、环绕通知(Around advice)、抛出异常后通知(After throwing advice) 等。

 

好了,现在我们来看看这些术语,谁能一眼就明白这些东西能告诉我们什么?谁能通畅的理清楚它们之间的关系。开始解释之前,我们看看维基百科上对AOP的定义是什么:

 

面向侧面的程序设计(aspect-oriented programming,AOP,又译作面向方面的程序设计、觀點導向編程)是计算机科学中的一个术语,指一种程序设计范型。该范型以一种称为侧面(aspect,又译作方面)的语言构造为基础,侧面是一种新的模块化机制,用来描述分散在对象、类或函数中的横切关注点(crosscutting concern)。
 

 

多么简单的解释,就是对于那些在主程序业务之外的事情,我们该怎么设计,看清楚,是程序设计,而不是程序编码,很多地方都将AOP理解成面向切面的编码,那是错误,AOP约定的是一种设计范型,具体到java上的实现例如aspectJ,例如spring的AOP。再具体到实现技术就是JDK自带的动态代理,cglib的字节码修改等等。AOP != spring AOP ,AOP != cglib 。一个是设计范型,一个是实现。

 

(这里扯开点说,一些所谓的架构师喜欢谈概念,还有人提出架构师更关注抽象的东西,普通的码农更关注具象的东西。这些东西本身没错,在大量的实践之后,我们确实应该去在这大量的实践中归纳,总结出规律,这就是进行抽象。但是,但是,那些只跟你扯抽象而不落地的架构师,还是远离些,因为他们不是基于大量的具象后,进行抽象,他们不过是邯郸学步的抄袭那些真正的架构师的想法,并转变为自己的观点,TMD就是个大忽悠)

 

2.那些主程序之外的杂事

我们知道,一个程序是会被编译成计算机能识别的机器码,交给机器去执行,那么我们想知道机器在执行我们的代码时候,发生的一些事,例如:

 

  1. 一个输入是否得到我们想要的输出呢?
  2. 一个函数执行的时间开销是多少呢?
  3. 若是一个良好的程序遇到无法处理的异常我们该怎么办呢?
  4. 存在多个数据源,我们需要在多个数据源的更新都完成后,再提交该怎么处理呢?
  5. 我们想将一些我们不认可的请求拒绝,那又该怎么处理呢?

 

当以上的这些杂事出现时,我们该怎么做呢,一种很简单粗暴的方式就是硬编码的将这些杂事写入到我们的主要业务程序中,我想这种方式大家在日常的开发经常能看到,包括你去看一些所谓平台级别的产品也是采用这种方式,笔者现在所在单位的部分产品也是如此。不管你爽不爽,老子爽了就可以了。

 

 

3.上吧,骚年

用个不恰当的比喻来说:你是个开饭店的,来了很多顾客,当你女服务员在招待顾客时,你突然发现XX院长来了,想来OOXX下。你就定了一个流程,来XX院长,可OOXX,硬编码的方式就是:

1.你女服务员在招待

2.XX院长跟她OOXX

3.你女服务员在招待

4.屌丝来了,无视之

......

这个过程中你不管你女服务员是否来例假,你不关心你女服务员是否今天心情不好。嗯,院长爽了,若是你得到了某种回报,也还好,爽了;若是什么都得不到,那可就欲哭无泪。

如果你足够幸福的话,有另一个口味美女服务员,她会隐藏技能---洗脚。恰巧经管学院院长也来了,这个家伙还喜欢洗脚,那怎么办,那就上吧:

1.你女服务员在招待

2.XX院长跟她OOXX+洗脚

3.你女服务员在招待

4.屌丝来了,无视之

......

如果你生意足够好,恰好XX院长又很多,好吧,你的美女们一直处在XXOO状态中..... 很high,很happy。但是,我们回到最开始,你为什么要招女服务员?找她们来,是因为你需要她们去招待顾客,一个屌丝在等吃饭没关系,若是一群的屌丝在等吃饭,你就悲剧,没人招待屌丝们了,因为你的那些服务员都在跟院长们OOXX中,因为命令已经固化到流程中,你改不了,至少在你修改流程之前。通过我们软件术语来说,就是不能及时、灵活的应对自身内部(你的美女们身体、心情)和外部(屌丝数量)的变化。当然, 你若是铁道部这样的共和国长子,那是没关系的,让那群屌丝们等去吧,因为方圆960万平方公里就此一家,别无分号。

 

若你不是,哪天觉得自己有点生意有点扛不住或是那点生殖器破事被某个黑心,吃不到葡萄的院长小弟揭发了,扛不住随之而来的社会舆论压力,不能跟院长们OOXX了,只准对他们笑个,这个时候你得通知那些女服务员,说不准OOXX了,只能看了。若是你只有一家店,还好,自己喊一声,重新打印流程规章表,若是全国连锁的话...... 一桌的杯具摆在你茶几上。

  

4.正义化身的出现

好了,扯了这么多,终于要该AOP兄弟出场了,再不出估计戏都散场了。

针对以上的种种问题,我们该怎么处理这些我们店主要生意之外的杂事呢(OOXX),有什么更好的方式来随时应对种种变化。这个就是我们AOP兄弟想干的事情,从主业中剥离出这些杂事,进行单独处理的设计。主业务只关注于自己的领域,对于特殊领域的处理(OOXX),通过侧面来封装维护,这样使得散落在不同口味美女的特殊操作可以很好的管理起来。来段专业点的说明吧:

 

从主关注点中分离出横切关注点是面向侧面的程序设计的核心概念。分离关注点使得解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑的代码中不再含有针对特定领域问题代码的调用,业务逻辑同特定领域问题的关系通过侧面来封装、维护,这样原本分散在在整个应用程序中的变动就可以很好的管理起来。
 

 

好了,AOP的就是个这么简单的东西,别去想那些繁杂的spring配置和概念术语。它只是一种设计范型。

 

 

绕了这么久,让我们来打倒那些纸老虎吧。

我开饭店,屌丝、院长来吃饭,美女们招待顾客 ,这个是我们的主业。  ========  目标对象(Target Object) 就是店主我,我开了两个店,戏院和饭店

哦,北大院长来饭店吃饭了                                                            ========  切入点(Pointcut) 他们来我戏院看戏的话,不管,直管饭店的事

院长开始吃饭,喝酒了。                                                               ========  连接点(Joinpoint) ,就是我们的一些行为,院长如果来围观的话,无视之,哥是开饭店的。

院长想跟美女们OOXX了                                                               ========  通知(Advice)院长来了,也吃了饭了,那接下来干什么呢?通知就是决定干什么:OOXX或是洗脚

院长除了想OOXX之外,还想洗脚,那么怎么办呢?                           ========  切面(Aspect) ,规定院长来了可以干什么,就是决定可以有多少个通知:OOXX||洗脚 或是 OOXX && 洗脚

----------------------------------------------------------------------------------------------------

院长想吃饭后洗脚                                                                ======== 后通知(After advice) 

院长想吃饭前洗脚                                                                ======== 前置通知(Before advice)

院长想根据吃饭后的心情决定是OOXX还是洗脚                         ======== 返回后通知(After return advice)

院长吃饭吃出脑中风了                                                          ======== 抛出异常后通知(After throwing advice)这个时候有个通知跳出来:打120,送医院!

院长想饭前洗脚,饭后OOXX                                                 ======== 环绕通知(Around advice)

 

作为老板的我,应该怎么更好的切入这些洗脚啊,OOXX服务呢    ======== AOP代理(AOP Proxy)怎么在干好招待顾客这件事上切入 洗脚||OOXX

 

若是上面的这些你还是看不明白的话,那么我们就具象到spring上,看看到底是件上面事吧。spring中Aspect叫Advisor。Joinpoint叫Weaving。很操蛋,也很让人无语的术语啊

 

 

切面:
package com.zhaming.aop.advice;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;

/**
 * 后置通知
 * @author inter12
 *
 */
public class AfterAdvice implements AfterReturningAdvice {

    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("拦截了:" + method.getName() + "方法");
        System.out.println("洗脚");
    }

}


package com.zhaming.aop.advice;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

/**
 * 前置通知
 * 
 * @author inter12
 */
public class BeforeAdvice implements MethodBeforeAdvice {

    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {

        System.out.println("拦截了:" + method.getName() + "方法");
        System.out.println("OOXX");
    }

}


package com.zhaming.aop.advice;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

/**
 * 环绕通知
 * 
 * @author inter12
 */
public class CompareAdvice implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Object result = null;
        String userName = invocation.getArguments()[0].toString();
        if (null != userName && userName.equals("yuanzhang")) {
            System.out.println("院长通过---------------");
            result = invocation.proceed();
        } else {
            System.out.println("屌丝拒绝---------------");
        }
        return result;
    }

}

目标对象:
package com.zhaming.aop.restaurant;

public interface RestaurantService {

    public void zhaodaiguke(String userName);

    public void weiguan(String userName);
}

package com.zhaming.aop.restaurant;

/**
 * 目标对象
 * 
 * @author inter12
 */
public class RestaurantServiceImpl implements RestaurantService {

    @Override
    public void zhaodaiguke(String userName) {
        System.out.println("--------- 姑娘们在招待顾客:" + userName);
    }

    @Override
    public void weiguan(String userName) {
        System.out.println(userName + ":在围观");

    }

}

客户端:
package com.zhaming.aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

import com.zhaming.aop.restaurant.RestaurantService;

public class Main {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new FileSystemXmlApplicationContext(
                                                                                    "//home/inter12/workspace/Light/src/main/java/appcontext-aop.xml");

        RestaurantService bean = (RestaurantService) applicationContext.getBean("restaurantService");
        bean.zhaodaiguke("yuanzhang");
        bean.zhaodaiguke("diaosi");
    }
}

配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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">

	<!-- 通知 -->
	<bean id="beforeAdvice" class="com.zhaming.aop.advice.BeforeAdvice"></bean>
	<bean id="afterAdvice" class="com.zhaming.aop.advice.AfterAdvice"></bean>
	<bean id="compareAdvice" class="com.zhaming.aop.advice.CompareAdvice"></bean>

	<!-- 目标对象 -->
	<bean id="restaurantServiceTarget" class="com.zhaming.aop.restaurant.RestaurantServiceImpl"></bean>

	<bean id="restaurantService" class="org.springframework.aop.framework.ProxyFactoryBean">

		<!-- 拦截那些接口 : 切入点 只关心饭店的事-->
		<property name="proxyInterfaces">
			<value>com.zhaming.aop.restaurant.RestaurantService</value>
		</property>

		<!-- 对这些方式做那些拦截:切面 -->
		<property name="interceptorNames">
			<list>
				<!-- 
				<value>beforeAdvice</value>
				 
				<value>afterAdvice</value>
				-->
				<value>compareAdvice</value>
			</list>
		</property>

		<property name="target">
			<ref bean="restaurantServiceTarget" />
		</property>
	</bean>

</beans>
 

 

 

5.AOP能干什么?

现在回头看看最初问的五个问题,那些杂事,是不是可以对应到软件中的几个概念:日志记录,性能统计,安全控制,事务处理,异常处理,更衍生的提还有缓存,持久化,同步等

25
2
分享到:
评论
20 楼 freezingsky 2013-07-02  
翻出来,再看一次!
19 楼 Lovic 2012-09-11  
dfgvgvgvgvgvgvgv
18 楼 ciao灰灰 2012-09-11  
讲的太好了、、 精彩部分果断Ctrl C、、Ctrl  V
17 楼 lsjinpeng 2012-09-11  
久经沙场,宝刀未老
lz一看就是工作XX年的经验人
16 楼 宋建勇 2012-09-10  
15 楼 wingsrao 2012-09-10  
要被和谐掉哦
14 楼 yayg 2012-09-10  
膜拜中
13 楼 fanyushuai 2012-09-10  
lz牛x!!!
12 楼 zhongmin2012 2012-09-10  
膜拜楼主,哈哈,有才哥
11 楼 一日一博 2012-09-10  
我只能用YD来形容LZ了
10 楼 lishen_1987 2012-09-10  
你真是太牛了 找了这么生动的示例
9 楼 wendal 2012-09-10  
最后还是用spring来演示了, 遗憾
8 楼 highill 2012-09-10  
好新鲜的帖子啊 比喻都如此恰当……
7 楼 jianqicui 2012-09-10  
AOP是不是重点,重点是想了这么个贴切的case,还真把AOP的词全整进去了,厉害啊。
6 楼 ansjsun 2012-09-10  
lz 你已经逆天了。
5 楼 sawadari_k 2012-09-10  
不愧是前辈,能够用这么生动的语言描述AOP!膜拜~~~~~~~~~~!
4 楼 dongbeiboy 2012-09-10  
真是才子啊。。
3 楼 viluo 2012-09-10  
lz 你已经逆天了。
2 楼 warrior701 2012-09-10  
lz能把AOP讲的如此生动并且YD,佩服啊,小弟算见识了。。
1 楼 aij 2012-09-10  
lz 你已经逆天了。

相关推荐

    SpringAOP简单入门示例..pdf

    SpringAOP简单入门示例..pdf

    AOP编程入门 Word版

    AOP编程入门,简单易懂。 希望能够帮助那些想学习它的人。

    最简单的SpringAOP入门案例

    最简单的SpringAOP入门案例,对于配置文件有详细的解释,适合初学者去理解AOP编程

    spring的aop简单例子

    spring的aop简单例子spring的aop简单例子spring的aop简单例子spring的aop简单例子

    spring AOP入门实例

    用spring AOP做的最简单的日志记录小例子,特别简单,可直接运行。

    spring aop简单例子

    spring aop简单例子,入门学习的好资料

    Spring AOP简单demo

    Spring AOP简单demo 入门级的 advice

    Spring_02_入门篇_AOP_简单实例

    采用注解模式,和XML模式对AOP面向切面编程进行测试。

    SpringAOP入门

    本文主要是介绍SpringAOP的相关知识,在本文里面我能介绍了SpringAOP的实现机理,在实现过程中所用到的相关技术,最后,通过一个简单的实例来对SpringAOP进行实现,进而加读者对SpringAOP的理解,以达到熟练运用的...

    springAOP-dome

    使用spring实现AOP的一个简单实例,很好的一个入门例子

    spring AOP 实例(@AspectJ)

    一个基于@AspectJ的spring2.0 AOP应用实例,很小很简单,没有任何额外信息,最适合AOP入门学习。使用log4j打印信息。把项目直接import进myeclipse就可以使用啦......

    基于AspectJ的AOP开发案例源码.rar

    aspectj的Aop开发的入门学习案例 demo1是aspectj的Aop开发,用于用户是否登录的验证,使用注解来实现,在切面类中配置好切入点。优点:方便快捷 demo2是aspectj的Aop开发,用于用户是否登录的验证,在xml中配置好切...

    Spring的AOP IOC

    一个机遇Spring3的入门小案例,里面主要简单演示了Spirng配置文件如何配置自动扫描包,控制类、服务类、Dao类如何加注解,被IOC扫描装入容器中。还有AOP例子的演示,有before after afterreturn afterthrow,还有...

    SpringMVC利用AOP实现自定义注解记录日志

    本文抛砖引玉,并没有详细的介绍更全面的内容,通过一个例子让初次使用的人能够快速入门,简单的介绍一下。 第一,注解: @Before – 目标

    spring入门上手小例子

    spring入门上手小例子,包括最基本最简单的的依赖注入和aop编程例子。

    Spring从入门到精通 pdf

    Spring从入门到精通(第七,十四章) pdf (非影印版) 清华大学出版社 作者:郭锋 ISBN:7302138117 IoC DI AOP的讲解,条理非常清晰,结合实例,简单明了。非常适合初次接触这些概念的人。

    Spring从入门到精通 源码

    本书最大的特色在于每章都是由浅入深,从一个简单的示例入手,让读者快速了解本章内容,然后再详细讲解本章涉及的基本原理和知识点,最后再通过一个详细的示例宋巩固所学内容。 本书每一章的例子都是经过精挑细选,...

    Quartz入门案例

    Quartz入门案例,QuartzManager管理器,简单任务调度案例和说明。

    springmvc拦截器入门实例.zip

    SpringMVC组件之拦截器组件,使用简单,入门级案例代码,类似SpringAOP,可以用来判断是否用户登录

Global site tag (gtag.js) - Google Analytics