AOP不是一种语言,而是一种软件工程方法。 像任何方法一样,它具有不同的实现,并且AspectJ当前是最丰富,最完整的。 由于AspectJ和AspectWerkz合并,现在可以使用注释创建方面。
开发人员编写代码的原因是为了提供某种功能。 对于这种讨论,功能性的种类并不重要:有些人可能想提供业务功能,另一些人可能出于研究目的编写代码,而另一些人则纯粹出于乐趣。 关键是任何信息系统都有其核心动机,即它想要提供的关键功能。 例如,我最近编写了PODAM ,这是一个测试工具,其最终目标是自动填充POJO / JavaBean属性。
每个信息系统也需要正交服务(AOP称之为横切关注点); 例如日志记录,安全性,审核,异常管理等。 尽管信息系统可以分为不同的功能(AOP定义了连接点),但全面需要正交服务。 例如,如果要记录每个公共方法执行所花的时间,则每个公共方法应具有以下伪代码:
public void someBusinessMethod() {long start = System.currentTimeInMilliseconds();doTheBusinessFunctionality();long end = System.currentTimeInMilliseconds();log.debug("The execution of someBusinessMethod took " + (end - start) + " milliseconds");}
在上述方法中,核心功能仅由someBusinessMethod()标识,而其他所有功能仅是记录活动。 最好有以下内容:
//Some external magic happens before the invocation of this method to take the start time
public void someBusinessMethod() {doTheBusinessFunctionality(); }
//Some external magic happens after the invocation of this method to take the end time and logs how long the execution took.
开发人员通常需要整个应用程序中的日志记录,安全性等,而不是单一方法。 AOP允许开发人员通过在外部某个地方(称为“方面”)定义行为以应用于匹配某种模式的所有代码(AOP实际上允许更广泛的功能集,例如添加接口,实例变量,方法,等等,只举一个例子)。 然后,通过AOP所谓的Weaver,将这种授权的行为添加到最终执行代码中。
可以通过多种方式实现:编织可以在源级别,二进制级别和加载时间进行。 您可以将编织器视为C和C ++中的链接器。 源和库链接在一起以创建可执行文件; 编织者将Java代码和方面结合在一起,以创建授权的行为。
Spring通过围绕必须丰富其行为的代码创建一个AOP代理来实现这种授权行为。 以下代码显示了一个基于AspectJ的非常简单的示例; 该示例围绕使用某些身份验证服务执行简单方法。
身份验证服务看起来非常简单(关键不是功能的实现方式,而是可用的身份验证服务):
/*** */
package uk.co.jemos.aop;/*** A simple authenticator service.* * @author mtedone* */
public class Authenticator {public void authenticate() {System.out.println("Authenticated");}}Now let's have a look at the business logic:/*** */
package uk.co.jemos.aop;/*** A simple service which delivers messages* @author mtedone* */
public class MessageCommunicator {public void deliver(String message) {System.out.println(message);}public void deliver(String person, String message) {System.out.println(person + ", " + message);}}
我们希望在调用MessageCommunicator的任何业务方法之前先调用Authenticator。 使用AspectJ注释语法,我们用纯Java编写Aspect:
package uk.co.jemos.aop;import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;@Aspect
public class SecurityAspect { private Authenticator authenticator = new Authenticator();@Pointcut("execution(* uk.co.jemos.aop.MessageCommunicator.deliver(..))")public void secureAccess() {};@Before("secureAccess()")public void secure() {System.out.println("Checking and authenticating user...");authenticator.authenticate();}}
上面的代码更加有趣。 一个方面用@Aspect注释标记。 切入点是我们代码中的一个关注点,我们希望我们的Aspect可以加入其中。语法
@Pointcut(“ execution(* uk.co.jemos.aop.MessageCommunicator.deliver(..))”)public void secureAccess(){};
意思是:“定义一个名为secureAccess的切入点,该切入点适用于MessageCommunicator类中的所有传递方法,而不管该方法的返回类型如何”。 接下来的内容被称为建议,这是AOP增强班级行为的地方:
@Before("secureAccess()")
public void secure() {System.out.println("Checking and authenticating user...");authenticator.authenticate();}
上面的代码说:“在对secureAccess()切入点进行任何匹配之前,将代码应用到块中”。 以上所有内容都是纯Java,尽管注释属于AspectJ运行时。 为了在Spring中使用上述方面,我定义了一个Spring上下文文件:
<?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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"><aop:aspectj-autoproxy /><bean id="messageCommunicator" /><bean id="securityAspect" /></beans>
XML元素:<aop:aspectj-autoproxy />指示Spring围绕各个方面创建代理。 现在,当我从客户端使用MessageCommunicator时:
/**
* @param args
*/
public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:aop-appContext.xml");MessageCommunicator communicator = ctx.getBean("messageCommunicator",MessageCommunicator.class);communicator.deliver("Hello World");communicator.deliver("Marco", "Hello World");
}
我得到以下输出:
信息:从类路径资源[aop-appContext.xml]加载XML bean定义2011年5月15日11:51:41
org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO:在org.springframework.beans.factory.support.DefaultListableBeanFactory@21b64e6a中预先实例化单例:定义bean [org.springframework.aop.config.internalAutoProxyCreator,messageCommunicator,securityAspect]; 工厂层次结构的根检查和认证用户…认证的Hello World 正在检查和认证用户…已认证Marco,Hello World
通过允许我们将外部组件中的横切关注点外部化,然后在需要时将其编织到我们的代码中,AOP大大改变了我们思考软件工程的方式,这允许编写更简洁,更可维护的代码,并且实现不受限制。 另外,如果我们通过使它们可重用而谨慎地编写我们的方面,我们可以快速地建立一个通用,可重用方面的库,以注入的方式为我们的代码添加功能。
采用AOP显然存在弊端,主要是开发人员熟悉该技术所需的学习曲线。 如上面的示例所示,AspectJ定义了自己的语言和语法); @Before注释只是一种可能性:建议可以在对象之前,之后,周围使用; 此外,定义切入点的语法不是Java,而是类似脚本的语法。 AspectJ方面还具有关键字和本机对象,以捕获他们建议的连接点的上下文,并且需要学习此语法。 但是,通过学习这项新颖而令人兴奋的技术所需的额外努力,潜在的收益将大大增加。
参考: Marco Tedone博客中的 JCG合作伙伴 Marco Tedone 使用AspectJ和Spring简化了AOP 。
翻译自: https://www.javacodegeeks.com/2012/04/aop-made-easy-with-aspectj-and-spring.html