`

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

    Spring AOP 简单入门示例 AOP(Aspect-Oriented Programming),即面向方面编程,是一种编程范式。AOP 是 OOP 的补充,它将系统中的横切性关注点模块化,并将其与业务逻辑分离。 在 Spring 中,AOP 是通过使用 ...

    最简单的SpringAOP入门案例

    本教程将通过一个简单的Spring AOP入门案例,帮助初学者理解这一概念。 ### 一、AOP基础 1. **切面(Aspect)**:切面是关注点的模块化,它封装了跨越多个对象的行为或数据。在Spring AOP中,切面可以由一个类定义...

    spring AOP入门实例

    在这个入门实例中,我们将深入理解Spring AOP如何实现简单日志记录。 首先,AOP的核心概念包括切面(Aspect)、通知(Advice)、连接点(Join Point)、切入点(Pointcut)和织入(Weaving)。切面是AOP中的核心...

    spring AOP入门教程

    **Spring AOP 入门教程** 在编程领域,Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架中的一个重要组成部分,它为开发者提供了一种强大的方式来管理横切关注点,如日志、事务管理、安全性等...

    spring的aop简单例子

    这个简单例子将帮助我们理解AOP的基本概念和如何在Spring框架中实现它。 首先,我们要知道AOP的核心概念:切面、通知、连接点、切点、目标对象和代理。切面是包含横切关注点(如日志记录、事务管理等)的模块化组件...

    Spring -Aop入门

    ### Spring AOP 入门详解 #### 一、Spring AOP 概述 Spring AOP (Aspect Oriented Programming) 是一种面向切面编程的技术,在Spring框架中得到了良好的支持。通过这种方式,开发者可以更加灵活地组织代码,使得...

    Spring AOP 入门实例1

    以下是一个简单的Spring AOP入门实例步骤: 1. 首先,定义一个切面类,包含通知方法。例如,一个简单的日志切面: ```java @Aspect @Component public class LoggingAspect { @Before("execution(* com.example*...

    Spring_02_入门篇_AOP_简单实例

    **Spring AOP 入门篇:面向切面编程的注解与XML模式** 在软件开发中,Spring框架因其强大的功能和灵活性而广受欢迎,尤其是在企业级应用开发中。本教程将深入探讨Spring中的核心概念之一——面向切面编程(Aspect-...

    spring2-aop入门实例教程

    - **HelloWorld示例**:通过编写一个简单的AspectJ切面来展示基本的AOP功能。 - **AspectJ语法**:介绍AspectJ中切面、切入点、通知等元素的基本语法。 #### 四、Spring AOP示例 - **定义业务组件**:创建具体的...

    Spring AOP入门及其实例讲解、下载

    **Spring AOP 入门及其实例讲解** 在软件开发中,面向切面编程(Aspect Oriented Programming,简称AOP)是一种编程范式,它旨在提高代码的可重用性,减少冗余,并将关注点分离。Spring框架是Java开发中的一个流行...

    Spring AOP 入门实例

    让我们通过一个简单的例子来理解Spring AOP。首先,我们需要一个业务接口和实现,例如: ```java public interface Service { void doSomething(); } @Service public class ServiceImpl implements Service { ...

    Spring_Aop入门例子

    在本入门例子中,你将学习如何在Spring环境中设置并使用AOP。 首先,我们需要理解AOP的基本概念。在面向对象编程中,业务逻辑代码往往会被一些通用的、非核心的代码(如日志、事务)所穿插,这降低了代码的可读性...

    Spring AOP简单demo

    以入门级的`advice`为例,我们可能有一个简单的日志切面: ```java @Aspect @Component public class LoggingAspect { @Pointcut("execution(* com.example.service.*.*(..))") public void serviceMethods() {} ...

    Spring 入门AOP材料

    以上就是一个简单的Spring AOP入门介绍。通过学习和实践,你可以更好地理解如何在实际项目中利用AOP来提高代码的可维护性和灵活性。在后续的学习中,你还可以探索更高级的特性,如自定义通知类型和使用AspectJ的编织...

    Spring AOP入门Demo分享

    在本文中,我们将通过一个简单的入门Demo来了解如何在Spring中使用AOP。首先,我们需要创建一个Maven项目,并添加相关的依赖。在`pom.xml`文件中,我们需要引入Spring的核心库、Spring的上下文库、Spring的AOP库以及...

    Spring_AOP入门与分析

    在这里,我们简单地打印出方法参数和方法名,并记录一条系统日志。这个例子展示了如何将日志记录这个横切关注点与主业务逻辑(User对象的持久化操作)分离,实现了代码的解耦。 在DAO层,我们定义了一个`IUserDAO`...

    Spring Framework中的AOP编程之入门篇

    本篇文章将深入探讨AOP编程的基础概念,并提供一个简单的入门指南。 一、AOP的基本概念 1. 切面(Aspect):切面是关注点的模块化,它封装了横切关注点。在Spring中,切面可以由一个或多个通知(advises)和一个...

    第五章示例代码__AOP入门

    在本章节中,我们将深入探讨AOP(面向切面编程)这一重要的编程概念,并通过具体的示例代码来帮助初学者入门。AOP是现代软件开发中的一个重要技术,它旨在提高代码的可重用性和模块化,减少代码冗余,使得程序更加...

    Spring @AspectJ 实现AOP 入门例子

    本文将深入探讨如何使用Spring的@AspectJ注解来实现AOP,这是一个入门级别的教程,旨在帮助开发者理解并掌握这一重要概念。 **什么是AOP?** 面向切面编程(Aspect-Oriented Programming,简称AOP)是一种编程范式...

Global site tag (gtag.js) - Google Analytics