用 Spring 实现 AOP 已翻译 100%

excepiton 投递于 2013/03/17 18:35 (共 11 段, 翻译完成于 03-19)
阅读 1512
收藏 8
0
加载中

一直以来,面向方面的编程(AOP)都是Spring框架中一个最基本的组成部分。由于这种编程模型将一些底层结构暴露给了Spring开发者,所以它曾经显得有点复杂。可能就是因为这个原因,Spring中的AOP编程只掌握在高级开发者手中。最近发生了很多变化 —— Spring已经改进了很多,AOP同样也得到了改进。我将在本文中籍由对AOP的一个权威性解释,展开讲解如何在Spring中实现AOP编程。所以,在我们真正上手之前,先来个小插曲。

fbm
fbm
翻译于 2013/03/19 18:16
2

函数式编程

在函数式编程(FP)的情况下,所有问题都要分解为由函数组成的模块,每个模块完成一组特定的任务。每个函数通过函数调用同其它函数打交道。总体的概念就是通过使用内聚性的函数模块对问题域(problem domain)进行分解。

现在让我们想象一下由函数调用组成的复杂的网状结构的情形。你得到的是象一碗意大利面条一样混乱的代码!

spaghetti code

意大利面条式的代码

fbm
fbm
翻译于 2013/03/19 18:24
1

面向对象的编程

在面向对象的编程(OOP)中,设计应用程序的思维过程得到了一种范型(paradigm)上的转变。不同的任务再也不是模型化为一组函数,而是转化为一个独特的对象,每个对象反映的是问题空间中一个不同的实体。

因此,设计复杂的代码变成为了一个更加清晰地分离关注点的过程。但是,仍旧还有。。。

Table


fbm
fbm
翻译于 2013/03/19 18:30
1
一些问题依然存在。
  • 有这样的情况出现:不是所有的任务都可以归类为一个对象,或者实现这样的对象并不依附于业务关注点本身。
  • 假设有些或所有的对象都使用了同一个过程(procedure),比如将一条消息记入日志的过程。现在要实现它,需要要么在每个对象中定义一个成员函数logMessage,要么定义一个单独的类并将 logMessage定义为其或静态或非静态的成员函数,只有这样才能让程序员通过或者继承或者创建一个新的Logger对象,或者只是调用其静态成员函数或者通过使用Spring的依赖注入(dependency injection)功能,使用该功能。

无论在那种情况下,以上文描述的方式进行设计都不是个特别好的主意。要注意的是,在上面提及的情况中最常用的对象实际上却是最不重要的对象。Logger对象并没有增加任何额外的业务功能。它只是对实现业务功能的过程提供了一种支持,而在对象交互中它获得的却是最大量的注意力。OOP还不错,但仍需要寻找另外一个层次的模块化思路,以解决对相互交叉的关注点进行更干净的分离问题。

fbm
fbm
翻译于 2013/03/19 18:50
1

面向方面的编程

AOP巧妙地将OOP范型中的模块化推向了一个全新的水平。通过引入了一个新的称之为“方面”的模块化单元,AOP提供了一种对相互交叉的关注点进行分离的新思路。“方面”着重于某个特定的交叉功能,为应用程序中的核心业务类免去了交叉性关注点方面的负担。这一切都是通过方面编织器(aspect weaver)完成的,方面编织器通过一个称为编织(weave)的过程,将核心类同交叉性的“方面”组合为最终的系统。AOP进一步革新了OOP,从而让程序的设计、实现以及维护变得更加简单。

fbm
fbm
翻译于 2013/03/19 19:06
2

Spring框架中的AOP

Spring的核心包括依赖注入(dependency injection)、企业级服务抽象(enterprise service abstraction)以及面向方面的编程。依赖注入可以把本无关联的许多部件以一种声明式的方式连接成为一个具有完整功能的应用程序,企业级服务抽象用来把稳定不变的应用逻辑同易变的基础设施代码隔离开来,而AOP可以让你将交叉性关注点的实现细节同业务关注点分开进行处理。Spring中的这三件套能够完美地整合到一起,为你提供一个极具竞争力的解决方案。

fbm
fbm
翻译于 2013/03/19 19:18
2

在Spring中实现AOP

所需软件:

Aspectj编程需要

  • Aspectj: Aspectj编译器可以为任意版本的Java平台生成代码,但该编译器本身需要Java2 (1.4或更新) 才能运行。
  • Cglib: 代码生成库,用于在运行态(at run time)下扩展Java类和实现接口。
  • Aopalliance : Guice和Spring等许多框架都会用到的一组接口。
  • asm: 全能型Java字节码操纵和分析框架,用于直接以二进制格式修改已有的类或动态产生类

Spring框架需要

  • Spring:  Java平台上的开源应用框架和控制反转(Inversion of Control)容器。
  • Common-logging: 用于记录日志信息的库

Java SEEclipse(注:任何其它的IDE都可以但本文使用的是Eclipse)

fbm
fbm
翻译于 2013/03/19 19:29
2

为AOP配置你的Project

首先安装Java SE和Eclipse。使用下列jar文件在Eclipse中创建用户库并包含如下所列的库。

创建aspectj用户库并导入下列jar文件

1.    aopalliance-x.x.x.jar

2.    cglib-nodep-x.x.x.jar

3.    aspectjrt.jar, aspectjweaver.jar (可能需要解压aspectj-x.x.x.jar才能得到这两个文件)

4.    asm-x.x.jar

创建Spring用户库并包含下列jar文件

1.    commons-logging-x.x.x.jar

2.    spring-framework-x.x.x/dist中所有的jar文件

在Eclipse中完成以上创建用户库的工作后,你就可以将该库重复使用于任何你希望具有aspectj特性的项目中。

注:在Eclipse中可以通过点击菜单Windows->Preference,然后展开preference窗口左侧的列表到Java->Build Path->User Libraries进行用户库的创建。

fbm
fbm
翻译于 2013/03/19 19:38
2

例子

该例子中包含四个类:EmployeeDepartment是数据模型类(model class),Main是应用程序的入口,LoggingAspect是“方面”类。

package org.simpleaop.model;
public class Employee {
       private String name;
       ...
       //Getters and Setters
}
 
package org.simpleaop.model;
public class Department {
       private String location;
       ...
       //Getters and Setters
}

Main类中展示了Spring中的依赖注入功能。

package org.simpleaop.app;
//...import statements
public class Main {
       public static void main(String[] args) {
             ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
             
             Employee emp = context.getBean("employee", Employee.class);
             emp.setName("Jerry Mouse");
             
             Department dept = context.getBean("department", Department.class);
             dept.setLocation("Disney Land");
             
             System.out.println("Name :"+emp.getName());
             System.out.println("Department :"+dept.getLocation());
       }
 
}

配置文件spring.xml展示的是依赖注入和AOP的配置细节。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://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
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
       
       <aop:aspectj-autoproxy />
       <bean name="employee" class="org.simpleaop.model.Employee"/>
       <bean name="department" class="org.simpleaop.model.Department"/>
       <bean name="loggingAspect" class="org.simpleaop.aspect.LoggingAspect" />
 
</beans>


LogginAspect类展示了Spring中的AOP实现方法。请注意,它只是一个annotation为@Aspect的简单POJO。 在该类中可以编写任意多的建议(英文为advice,建议是一个AOP术语,指的就是一个带有AOP annotation前缀的函数),可以使用的annotation包括有@Before、@After、@Within、@Around、@Pointcut等。

package org.simpleaop.aspect;
//..import statements
 
@Aspect
public class LoggingAspect {
       
       @Before("execution(public String getName())")
       public void beforeAdvice(){
             System.out.println("Before advice. Runs before the function called");
       }
       //...other advices
}


@Before意思就是,名为beforeAdvice的这个建议会在每次对public String getName()这个 函数的调用之前得到执行。@Before还有其它一些变化,比如:

@Before("execution(public
String org.simpleaop.Employee.getName())")

不同之处在于,所指定的建议仅会在对Employee类的getName函数调用之前得到执行。

其中还可以使用通配符:

@Before("execution(public * get*())") 

表示的是对具有任意返回类型并且没有参数但函数名字的前缀为“get”的public函进行的调用。

@Before("execution(public * get*(..))") 

表示的是对具有任意返回类型并且具有零个或多个参数但函数名字的前缀为“get”的public函进行的调用。

@Before("execution(public * get*(*))") 

表示的是对具有任意返回类型并且具有一个或多个参数但函数名字的前缀为“get”的public函进行的调用。

需要更多的例子和解释请参见Spring中关于某些方面编程的文档

fbm
fbm
翻译于 2013/03/19 19:58
2

AOP的用法

有些情况下AOP会非常好用,最常见的用例中可能会有记录日志和性能分析。

  • 在事务管理中AOP可以大有用武之地,可以将请求处理方法用@Around建议封装起来,从而能够在出现问题的时立即将事务回滚(roll back)。
  • 可以使用@Before建议建立起一种访问权限控制或者安全机制,在让用户进入时对其访问凭证( access credential)进行验证。
  • 当业务方法要抛出异常时可以对异常进行封装。@After抛出异常建议可以用于处理这种情况。例如,当你想要将所有的SQLException封装为数据访问层异常,并不想在每个DAO方法中对它们进行处理,只是将它们抛回服务层时,就可以这么做。

AOP象这样的用法多不胜数。这里列举的几项仅仅是蜻蜓点水而已。

fbm
fbm
翻译于 2013/03/19 20:14
2
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(1)

IT小何
IT小何
表示目前看不懂,好高深的样子!!!
返回顶部
顶部