AOP正在成为软件开发的下一个圣杯。使用AOP,你可以将处理aspect的代码注入主程序,通常主程序的主要目的并不在于处理这些aspect。AOP可以防止代码混乱。
为了理解AOP如何做到这点,考虑一下记日志的工作。日志本身不太可能是你开发的主程序的主要任务。如果能将“不可见的”、通用的日志代码注入主程序中,那该多好啊。AOP可以帮助你做到。
Spring framework是很有前途的AOP技术。作为一种非侵略性的,轻型的AOP framework,你无需使用预编译器或其他的元标签,便可以在Java程序中使用它。这意味着开发团队里只需一人要对付AOP framework,其他人还是象往常一样编程。
AOP是很多直觉难以理解的术语的根源。幸运的是,你只要理解三个概念,就可以编写AOP模块。这三个概念是:advice,pointcut和advisor。advice是你想向别的程序内部不同的地方注入的代码。pointcut定义了需要注入advice的位置,通常是某个特定的类的一个public方法。advisor是pointcut和advice的装配器,是将advice注入主程序中预定义位置的代码。

既然我们知道了需要使用advisor向主要代码中注入“不可见的”advice,让我们实现一个Spring AOP的例子。在这个例子中,我们将实现一个before advice,这意味着advice的代码在被调用的public方法开始前被执行。以下是这个before advice的实现代码:

代码:
package com.company.springaop.test;

import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;

public class TestBeforeAdvice implements MethodBeforeAdvice {

public void before(Method m, Object[] args, Object target)
  throws Throwable {
    System.out.println("Hello world! (by "
        + this.getClass().getName()
        + ")");
  }
}
 

接口MethodBeforeAdvice只有一个方法before需要实现,它定义了advice的实现。before方法共用三个参数,它们提供了相当丰富的信息。参数Method m是advice开始后执行的方法。方法名称可以用作判断是否执行代码的条件。Object[] args是传给被调用的public方法的参数数组。当需要记日志时,参数args和被执行方法的名称,都是非常有用的信息。你也可以改变传给m的参数,但要小心使用这个功能;编写最初主程序的程序员并不知道主程序可能会和传入参数的发生冲突。Object target是执行方法m对象的引用。

在下面的BeanImpl类中,每个public方法调用前,都会执行advice:

代码:
package com.company.springaop.test;

public class BeanImpl implements Bean {

public void theMethod() {
    System.out.println(this.getClass().getName()
        + "." + new Exception().getStackTrace()[0].getMethodName()
        + "()"
        + " says HELLO!");
  }
}

类BeanImpl实现了下面的接口Bean:

代码:
package com.company.springaop.test;

public interface Bean {
  public void theMethod();
}

虽然不是必须使用接口,但面向接口而不是面向实现编程是良好的编程实践,Spring也鼓励这样做。

pointcut和advice通过配置文件来实现,因此,接下来你只需编写主方法的Java代码:

代码:

package com.company.springaop.test;

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

public class Main {

public static void main(String[] args) {
    //Read the configuration file
    ApplicationContext ctx
        = new FileSystemXmlApplicationContext("springconfig.xml");

//Instantiate an object
    Bean x = (Bean) ctx.getBean("bean");

//Execute the public method of the bean (the test)
    x.theMethod();
  }
}

我们从读入和处理配置文件开始,接下来马上要创建它。这个配置文件将作为粘合程序不同部分的“胶水”。读入和处理配置文件后,我们会得到一个创建工厂ctx。任何一个Spring管理的对象都必须通过这个工厂来创建。对象通过工厂创建后便可正常使用。

仅仅用配置文件便可把程序的每一部分组装起来。

代码:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC  "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
  <!--CONFIG-->
  <bean id="bean" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="proxyInterfaces">
      <value>com.company.springaop.test.Bean</value>
    </property>
    <property name="target">
      <ref local="beanTarget"/>
    </property>
    <property name="interceptorNames">
      <list>
        <value>theAdvisor</value>
      </list>
    </property>
  </bean>

<!--CLASS-->
  <bean id="beanTarget" class="com.company.springaop.test.BeanImpl"/>

<!--ADVISOR-->
  <!--Note: An advisor assembles pointcut and advice-->
  <bean id="theAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <property name="advice">
      <ref local="theBeforeAdvice"/>
    </property>
    <property name="pattern">
      <value>com/.company/.springaop/.test/.Bean/.theMethod</value>
    </property>
  </bean>

<!--ADVICE-->
  <bean id="theBeforeAdvice" class="com.company.springaop.test.TestBeforeAdvice"/>
</beans>
 

四个bean定义的次序并不重要。我们现在有了一个advice,一个包含了正则表达式pointcut的advisor,一个主程序类和一个配置好的接口,通过工厂ctx,这个接口返回自己本身实现的一个引用。

BeanImpl和TestBeforeAdvice都是直接配置。我们用一个唯一的ID创建一个bean元素,并指定了一个实现类。这就是全部的工作。

advisor通过Spring framework提供的一个RegexMethodPointcutAdvisor类来实现。我们用advisor的一个属性来指定它所需的advice-bean。第二个属性则用正则表达式定义了pointcut,确保良好的性能和易读性。

最后配置的是bean,它可以通过一个工厂来创建。bean的定义看起来比实际上要复杂。bean是ProxyFactoryBean的一个实现,它是Spring framework的一部分。这个bean的行为通过一下的三个属性来定义:

  • 属性proxyInterface定义了接口类。
  • 属性target指向本地配置的一个bean,这个bean返回一个接口的实现。
  • 属性interceptorNames是唯一允许定义一个值列表的属性。这个列表包含所有需要在beanTarget上执行的advisor。注意,advisor列表的次序是非常重要的。

Spring工具

虽然你可以手工修改Ant构建脚本,但使用SpringUI(译注:SpringUI现在是Spring framework的一部分,并改名为spring-ide),使用Spring AOP变得很简单,只要点点鼠标即可。你可以把SpringUI安装成Eclipse的一个plug-in。然后,你只需在你的project上右击鼠标,并选择“add Spring Project Nature”。在project属性中,你可以在“Spring Project”下添加Spring配置文件。在编译前把下面的类库加入project:aopalliance.jar,commons-logging.jar,jakarta-oro-2.0.7.jar和spring.jar。运行程序时你会看到下面的信息:

... (logging information)
Hello world! (by com.company.springaop.test.TestBeforeAdvice)
com.company.springaop.test.BeanImpl.theMethod() says HELLO!

优点和缺点

Spring比起其他的framework更有优势,因为除了AOP以外,它提供了更多别的功能。作为一个轻型framework,它在J2EE不同的部分都可以发挥作用。因此,即使不想使用Spring AOP,你可能还是想使用Spring。另一个优点是,Spring并不要求开发团队所有的人员都会用它。学习Spring应该从Spring reference的第一页开始。读了本文后,你应该可以更好地理解Spring reference了。Spring唯一的缺点是缺乏更多的文档,但它的mailing list是个很好的补充,而且会不断地出现更多的文档。

spring AOP详解〇的更多相关文章

  1. 【转载】Spring AOP详解 、 JDK动态代理、CGLib动态代理

    Spring AOP详解 . JDK动态代理.CGLib动态代理  原文地址:https://www.cnblogs.com/kukudelaomao/p/5897893.html AOP是Aspec ...

  2. Spring AOP详解(转载)所需要的包

    上一篇文章中,<Spring Aop详解(转载)>里的代码都可以运行,只是包比较多,中间缺少了几个相应的包,根据报错,几经百度搜索,终于补全了所有包. 截图如下: 在主测试类里面,有人怀疑 ...

  3. Spring AOP详解及简单应用

    Spring AOP详解   一.前言 在以前的项目中,很少去关注spring aop的具体实现与理论,只是简单了解了一下什么是aop具体怎么用,看到了一篇博文写得还不错,就转载来学习一下,博文地址: ...

  4. 转:Spring AOP详解

    转:Spring AOP详解 一.前言 在以前的项目中,很少去关注spring aop的具体实现与理论,只是简单了解了一下什么是aop具体怎么用,看到了一篇博文写得还不错,就转载来学习一下,博文地址: ...

  5. Spring Aop 详解二

    这是Spring Aop的第二篇,案例代码很详解,可以查看https://gitee.com/haimama/java-study/tree/master/spring-aop-demo. 阅读前,建 ...

  6. [Spring学习笔记 5 ] Spring AOP 详解1

    知识点回顾:一.IOC容器---DI依赖注入:setter注入(属性注入)/构造子注入/字段注入(注解 )/接口注入 out Spring IOC容器的使用: A.完全使用XML文件来配置容器所要管理 ...

  7. Spring系列(四):Spring AOP详解

    一.AOP是什么 AOP(面向切面编程),可以说是一种编程思想,其中的Spring AOP和AspectJ都是现实了这种编程思想.相对OOP(面向过程编程)来说,提供了另外一种编程方式,对于OOP过程 ...

  8. Spring Aop 详解一

    Aop 是一个编程思想,最初是一个理论,最后落地成了很多的技术实现. 我们写一个系统,都希望尽量少写点儿重复的东西.而很多时候呢,又不得不写一些重复的东西.比如访问某些方法的权限,执行某些方法性能的日 ...

  9. Spring AOP详解

    一.前言 在以前的项目中,很少去关注spring aop的具体实现与理论,只是简单了解了一下什么是aop具体怎么用,看到了一篇博文写得还不错,就转载来学习一下,博文地址:http://www.cnbl ...

随机推荐

  1. python基础教程总结15——1.即时标记

    1. 测试文档: # test_input.txt Welcome to World Wide Spam. Inc. These are the corporate web pages of *Wor ...

  2. Python XML 解析

    什么是 XML? XML 指可扩展标记语言(eXtensible Markup Language). XML 被设计用来传输和存储数据. XML 是一套定义语义标记的规则,这些标记将文档分成许多部件并 ...

  3. 一、git提交代码步骤

    git add .   //添加到本地缓存区 git commit -m '备注 ' //提交代码到本地仓库 git push  //将本地代码推送到develop分支上 git checkout m ...

  4. 使用ServiceController组件控制计算机服务

    实现效果: 知识运用: ServiceController组件的MachineName属性 //获取或设置服务所驻留的计算机名称 public string MachineName{get;set;} ...

  5. 2018.3.16 Ubuntu 解决中文乱码问题

    一.乱码的样子类似: °²Àï¿ü ÒÁ¸ñÀ³Ï£ÑÇ˹,°²Àï¿ü ÒÁ¸ñÀ³Ï£ÑÇ˹ 这种乱码称为Gedit中文乱码 打开部分Windows下的txt文本文件的时候,中文显示为乱码.但 ...

  6. MySQL 外键 表的查询

    自增补充 这是查看怎么创建的表, \G示旋转90度显示表的内容 表的自增的关键是** AUTO_INCREMENT=3**,在表中添加数据后,这个会自动改变,通过alert可以改变这个默认值 mysq ...

  7. SQL Server 游标的应用

    ----------------SQL游标应用----------------- 今天由于业务需求,需要在存储过程中实现有一个表的主键去匹配在另一个表中作为外键所对应的数值 ,若在C#中则非常简单只需 ...

  8. GCD和NSThread延时执行对比

    1.NSThread: [self performSelector:@selector(performSome:) withObject:self afterDelay:.f]; [[self cla ...

  9. Spring源码剖析依赖注入实现

    Spring源码剖析——依赖注入实现原理 2016年08月06日 09:35:00 阅读数:31760 标签: spring源码bean依赖注入 更多 个人分类: Java   版权声明:本文为博主原 ...

  10. python入门:BREAK 的用法 跳当前循环后,不再执行下面代码块

    #!/urs/bin/env python # -*- coding:utf-8 -*- # BREAK 的作用 跳当前循环后,不再执行下面代码块 while True: ') break ') #w ...