`
jarfield
  • 浏览: 202706 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

A “Killer App” for AOP

阅读更多
原文地址:http://www.linux-mag.com/id/1677

Tuesday, June 15th, 2004

Pioneered at Xerox's Palo Alto Research Center (PARC) in the late '80s and early '90s, aspect-oriented programming (AOP) has greatly influenced modern software development, from the latest research at IBM, to the tag-driven development nature of Microsoft's .NET and C# environments. Indeed, AOP has been gaining an even wider audience of late: its research community is extremely active, a number of open source projects offer a wealth of implementations, and, as a natural complement to object-oriented programming (OOP), developers are discovering that AOP provides for more intuitive, extensible, and flexible middleware. If you're an enterprise software developer, the combination of JDK 1.5, the newest release of Java, and JBoss AOP, available in JBoss 4, may just be the best thing since sliced bread.

An aspect is a common feature that's typically scattered across methods, classes, object hierarchies, or even entire object models. For example, metrics is one common aspect. To capture useful benchmarks from your application, you have to sprinkle timing (often liberally) throughout your code.

However, metrics are something that your class or object model really shouldn't be concerned about. After all, metrics -- and, as you'll see, logging, persistence, caching, security, and other system heavyweights -- is irrelevant to your actual application: it doesn't represent a customer or an account, and it doesn't realize a business rule. It's simply orthogonal.

In AOP, a feature like metrics is called a crosscutting concern, as it's a behavior that "cuts" across multiple points in your object model, yet is distinctly different. As a development methodology, AOP recommends that you abstract and encapsulate crosscutting concerns.

For example, let's say you want to add code to an application to measure the amount of time it takes to invoke a particular method. In plain Java, that code would look something like Listing One.

Listing One: A bank account object with metrics added

public class BankAccountDAO
{
public void withdraw(double amount)
{
long startTime = System.currentTimeMillis();
try
{
// Actual method body...
}
finally
{
long endTime = System.currentTimeMillis() - startTime;
System.out.println("withdraw took: " +
endTime);
}
}
}

While this code works, there are a few problems with its approach:

1. The profiling code really doesn't belong sprinkled throughout your application. It makes your code bloated and harder to read, as you have to enclose the timings within a try/finally block.

2. It's extremely difficult to turn metrics on and off, as you have to manually add the code in the try/finally block to each and every method or constructor you want to benchmark.

3. If you wanted to expand your metrics to include a method or failure count, or even to register these statistics to a more sophisticated reporting mechanism, you'd have to modify a lot of different files (again).

All in all, this approach to metrics is very difficult to maintain, expand, and extend, because it's dispersed throughout your entire code base. And this is just a tiny example!

As an alternative, aspect-oriented programming allows you to add behavior such as metrics "around" your code. For example, AOP provides you with programmatic control to specify that you want calls to BankAccountDAO to go through a metrics aspect before executing the actual body of that code.

Creating Aspects in JBoss AOP

In short, all AOP frameworks define two things: a way to implement crosscutting concerns and a programmatic construct -- a programming language or a set of tags -- to specify how you want to apply those snippets of code.

Let's take a look at how JBoss AOP, available in JBoss 4.0 (http://www.jboss.org) implements its cross-cutting concerns, and see how you can implement a metrics aspect in JBoss.

The first step in creating a metrics aspect in JBoss AOP is to encapsulate the metrics feature in its own Java class. Listing Two extracts the try/finally block in Listing One's Bank AccountDAO.withdraw() method into Metrics, an implementation of a JBoss AOP Interceptor class.

Listing Two: Implementing metrics in a JBoss AOP Interceptor

01. public class Metrics implements org.jboss.aop.Interceptor
02. {
03. public Object invoke(Invocation invocation) throws Throwable
04. {
05. long startTime = System.currentTimeMillis();
06. try
07. {
08. return invocation.invokeNext();
09. }
10. finally
11. {
12. long endTime = System.currentTimeMillis() - startTime;
13. java.lang.reflect.Method m = ((MethodInvocation)invocation).method;
14. System.out.println("method " + m.toString() + " time: " + endTime + "ms");
15. }
16. }
17. }

Under JBoss AOP, the Metrics class wraps withdraw(). When calling code invokes withdraw(), the AOP framework breaks the method call into its parts and encapsulates those parts into an Invocation object. The framework then calls any aspects that sit between the calling code and the actual method body. Then, when the AOP framework is done dissecting the method call, it calls Metric's invoke() method at line 3. Line 8 wraps and delegates to the actual method and uses an enclosing try/finally block to perform the timings. Line 13 obtains contextual information about the method call from the Invocation object, while line 14 displays the method name and the calculated metrics.

With metrics code within its own object, you can easily expand and capture additional measurements later on.

Now that metrics are encapsulated into an aspect, let's see how to apply it.

Applying Aspects in JBoss AOP

To apply an aspect, you specify when to execute the aspect code. The points in execution are called pointcuts. (Pointcuts are sometimes called interceptors as well. See the sidebar "Aspects or Interceptors?" to learn why.)

For example, a pointcut might be defined as "for all calls to the JDBC method executeQuery(), call the aspect that verifies SQL syntax."

Defining pointcuts is what AOP is mostly about. An entry point could be a field access, or a method or constructor call. An event could be an exception being thrown.

Some AOP implementations use languages akin to queries to specify pointcuts. Others use tags. JBoss AOP uses both. Listing Three shows how to define a pointcut for the metrics example.

Listing Three: Defining a pointcut for Listing Two

1. <bind pointcut="public void com.mc.BankAccount DAO->withdraw(double amount)">
2. <interceptor class="com.mc.Metrics"/>
3. </bind >

4. <bind pointcut="* com.mc.billing.*->*(..)">
5. <interceptor class="com.mc.Metrics"/>
6. </bind >

Lines 1-3 define a pointcut that applies the metrics aspect only to BankAccountDAO.withdraw(). Lines 4-6 define a general pointcut that applies the metrics aspect to all methods in all classes in the com.mc.billing package.

JBoss AOP has a rich set of pointcut expressions that you can use to apply your aspects. You can attach your aspects to a specific Java class in your application or you can use more complex compositional pointcuts to specify a wide range of classes within one expression.

Benefits of AOP

With AOP, as this example shows, you're able to pull together crosscutting behavior into one object and apply it easily and simply, without polluting and bloating your code with features that ultimately don't belong mingled with business logic. Instead, common crosscutting concerns can be maintained and extended in one place.

Notice too that the code within the BankAccountDAO class has no idea that it's being profiled. This is what aspect-oriented programmers deem orthogonal concerns.

Profiling is an orthogonal concern. In the OOP code snippet in Listing One, profiling was part of the application code. With AOP, you can remove that code.

A modern promise of middleware is transparency, and AOP (pardon the pun) clearly delivers.

Just as important, orthogonal behavior could be bolted on after development. In Listing One, monitoring and profiling must be added at development time. With AOP, a developer or an administrator can (easily) add monitoring and metrics as needed without touching the original code.

This is a very subtle but significant part of AOP, as this separation (obliviousness, some may say) allows aspects to be layered on top of or below the code that they cut across. A layered design allows features to be added or removed at will. For instance, perhaps you snap on metrics only when you're doing some benchmarks, but remove it for production. With AOP, this can be done without editing, recompiling, or repackaging the code.

A unique feature of the JBoss AOP framework, even among other AOP frameworks, is the capacity to dynamically reshape flow and add aspects to objects. With JBoss AOP, you can turn on metrics at any time, as JBoss supports hot-deployment of aspects at runtime.

Extending the Java language

The Java Developers Kit version 1.5 (JDK 1.5) is due out this summer and is currently in beta. (See page 18 for details.) You can download it for Linux already.

One interesting new feature being introduced to Java is metadata, the ability to define metadata about a class, method, field, or constructor through typesafe annotations. (See the feature "Metadata for Java" on page 26 for a detailed article on metadata.) Metadata can provide additional information about Java constructs, much like synchronized and transient provide in the current grammar.

Long story short, you can tag a Java class, method, field, or constructor and have an aspect be triggered by the application of that tag. This amounts to "pluggable" Java keywords.

For example, let's apply the metrics aspect via metadata. This code...

public class BankAccountDAO
{
@profiled public void withdraw(double
amount)
{
// Actual method body...
}
}

... uses the new metadata feature of JDK 1.5 to tag the withdraw() method for profiling. You can then define a pointcut to apply metrics to any method that is @profiled:

<bind pointcut="* *->@profiled(..)">
<interceptor class="com.mc.Metrics"/>
</bind >

Given this framework, you can define your own annotations to trigger the application of aspects. In effect, you can extend the Java language.

Someone once pointed out that if OOP defines the words used to code, then, in a very linguistic sense, AOP introduces the grammar for adjectives. JBoss ships with a prepackaged set of adjectives that you can use to describe your application. Any object can be "remote," "cached," "persistent," "transactional," or "secure."

In fact, this sort of coding is known as tag driven development, because the simple usage of tags allows you to apply aspects to a class. For those of you familiar with C# and .NET, there are similar constructs in that system. For instance, .NET's @remote allows you to code a class and tag it to become a web service.

Aspect-Oriented Middleware

Just as GUIs helped formulate the early patterns of OOP, middleware is shaping up to be the "killer app" of aspect-oriented programming. The features provided by middleware, by nature, are crosscutting: the features are common across object hierarchies and are orthogonal to business logic.

For example, think about EJB: EJB defines APIs and XML for developers to interact with system services. You define an EJB, use the interface, and provide the XML, and the system provides remoting, persistence, caching, transactional demarcation, and security.

AOP is perfect for middleware, as middleware features can be applied to plain old java objects (POJOS) after-the-fact, without changing the code or design of the existing business model. AOP lets system designers and users get one step closer to "transparent nirvana." Packaging up middleware into a set of aspects is great for application developers as it frees them to focus on writing the POJOS that make up their application's specific behavior rather than forcing them to work under an API dictated to them by their system architecture or even by a standards body. Plain Java objects can run anywhere: within an application server, within an applet, and within simple unit tests.

JBoss 4 slices and dices J2EE features and serves them a la carte to your object model rather than going through the sometimes cumbersome and unnecessary process of implementing an EJB. Take the example of transactions.

Returning to the BankAccountDAO Java class, suppose that the withdraw() method has to update an account database table and insert a record into a transaction log for auditing. withdraw() is distinctly transactional, and it would be nice if the developer could define it just so.

JBoss AOP allows you to enable transactions within any Java class in your object model by simply specifying a metadata tag.

public class BankAccountDAO
{
@transaction (trans-attribute=Required)
public void withdraw(double amount)
{
// Actual method body
}
}

Here, the @transaction tag triggers a pre-packaged pointcut provided with the JBoss 4 application server. When withdraw() is invoked, a transaction is started and is either automatically committed when withdraw() finishes or is rolled back if an exception is thrown.

The pointcut is defined simply as:

<bind pointcut="all(@transaction)">
<interceptor factory="org.jboss.aop.tx.
TxInterceptorFactory"/>
</bind>

@transaction can be applied to any method, static or member, as well as any constructor.

For BankAccountDAO, it may also be useful to apply security so that only an authenticated and authorized user can invoke withdraw(). JBoss AOP also allows you to apply role-based security to any field, method, or constructor, using the enterprise security modules already available in the JBoss application server. The application of the security aspect is a little bit different than the one for transactions, as you usually don't embed security information in classes. So, JBoss AOP has the ability to define metadata in an XML format. JBoss 4 calls this crosscutting metadata.

1. <annotation tag="security" class="com.mc.BankAccountDAO">
2. <security-domain>java:/jaas/ldap </security-domain>
3. <method-permission>
4. <role-name>teller</role-name>
5. <method>
6. <method-name>withdraw </method-name>
7. </method>
8. </method-permission>
9. </annotation>

This annotation applies a security aspect to the withdraw() method. The security-domain on line 2 specifies the JBoss security repository, where information about users, roles, and passwords are stored. Lines 3-8 define the role that can invoke withdraw(). (If you're an EJB developer, you'll likely notice that this is the same syntax as an EJB deployment descriptor. This syntax has been extended to support the declaration of security for fields and constructors as well.)

To optimize access to your database, you might want to store the BankAccountDAO within a cache, so that read-only operations like getAccountBalance(), getAccountStatus(), and getCustomerAddress() are readily processed. JBoss AOP provides a transparent transactional and cluster-aware cache that can be used with plain Java objects.

1. cache = new org.jboss.cache.aop. TreeCacheAop();
2. config = new PropertyConfigurator();
3. config.configure(tree, "META-INF/replSync-service.xml");
4.
5. BankAccountDAO account = ...;
6. cache.putObject(account.getAccountNumber(), account);
7. tx.begin()
8. account.setCustomerAddress("55 Street Road");
9. account.withdraw(500.00);
10. tx.commit()

Line 6 simply puts the account object within the cache. It automatically becomes replicated across a cluster and transactional. Lines 8-9 are updates to the account object that happen within the transaction. The account object's in-memory transactional state (the Java fields) is isolated from any other transaction. On transaction commit, the changed Java fields within the transaction become "official" and are automatically replicated to the rest of the cluster. There are both optimistic and pessimistic locking schemes that can be used to ensure the integrity of the in-memory data. This requires no changes to the BankAccountDAO code.

Generalized Containers

AOP is a new paradigm for expanding code re-use and easing the maintenance of complex code. AOP provides guidelines for encapsulating code that is typically scattered throughout your object model into one set of objects, and provides a simple mechanism to integrate new code at a later time. When combined with JDK 1.5's new metadata feature, AOP can even be used to extend the Java language.

The first killer application of AOP is middleware. AOP allows application code to be freer from middleware APIs, making application developers more productive. Standalone, tag-like constructs offer developers a trivial way to interact with the system and ask for services for their POJOs. EJB is already a fixed set of system services, but JBoss AOP is a more intuitive approach to applying these services and is much more flexible to user requirements.

The complexity of middleware is slowly dissolving, and as more and more aspects are defined and implemented, things will become even simpler. One day we will all walk through walls.

Aspects or Interceptors?

To implement aspects, you might imagine a rules engine matching conditions and generating indirection in execution. Execution proceeds as normal until the rules engine finds a match, which causes control to be interrupted and transferred to the AOP framework. This is why aspects are sometimes called interceptors: code execution is intercepted via indirection.

分享到:
评论

相关推荐

    app aop code withbug

    标题 "app aop code withbug" 暗示我们正在处理一个关于应用程序(app)的面向切面编程(AOP)代码,其中存在错误或漏洞。面向切面编程是一种编程范式,它允许我们将关注点(如日志、事务管理等)与主要业务逻辑分离...

    AOPA口试题库

    AOPA口试题库 AOPA无人机驾驶员考试是民航局认可的无人机驾驶资质考试,这份口试题库是比较早的题库,后期题库应该会有所增加,分享给有需要的人。以下是 一、遥控系统 * 遥控器通道辨识:通道就是指飞机控制的...

    spring aop spring aop

    在给出的XML配置中,`&lt;aop:config&gt;`元素开启AOP支持,而`&lt;aop:aspect&gt;`元素用于定义切面,其内部通过`&lt;aop:pointcut&gt;`定义切点,并通过`&lt;aop:before&gt;`和`&lt;aop:after&gt;`指定通知。 为了使用这些配置,我们需要在代码...

    AOPA无人机培训总题库讲解.doc

    AOPA无人机培训总题库讲解.doc

    spring-aop.jar各个版本

    spring-aop-1.1.1.jar spring-aop-1.2.6.jar spring-aop-1.2.9.jar spring-aop-2.0.2.jar spring-aop-2.0.6.jar spring-aop-2.0.7.jar spring-aop-2.0.8.jar spring-aop-2.0.jar spring-aop-2.5.1.jar spring-aop-...

    aop所依赖的所有包

    AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,旨在减少代码的重复性和增强可维护性,特别是在处理系统中的横切关注点时。这些关注点,如日志、事务管理、安全检查等,往往分散在系统的各个部分...

    开发工具 aopalliance-1.0

    开发工具 aopalliance-1.0开发工具 aopalliance-1.0开发工具 aopalliance-1.0开发工具 aopalliance-1.0开发工具 aopalliance-1.0开发工具 aopalliance-1.0开发工具 aopalliance-1.0开发工具 aopalliance-1.0开发工具...

    AOP@Work AOP 工具比较

    面向切面编程(AOP,Aspect Oriented Programming)是一种编程范式,旨在通过将关注点分离,提高软件的模块化程度。AOP的核心是切面,它封装了横切关注点,如日志、事务管理、性能监控等,使得这些功能可以独立于主...

    aopalliance-1.0.jar及aopalliance源码

    **AOP Alliance简介** AOP Alliance是一个开源项目,它的全称是Aspect Oriented Programming(面向切面编程)Alliance,是Java平台上的一个接口集合,为面向切面编程的实现提供了一个统一的API。这个库的主要目的是...

    spring-boot aop

    Spring Boot AOP(面向切面编程)是一种强大的设计模式,它允许我们在不修改现有代码的情况下,插入额外的功能或监控代码。在Spring框架中,AOP主要用于日志记录、事务管理、性能统计等场景。本示例是关于如何在...

    aopa无人机考试试题库1006道题.pdf

    aopa无人机考试试题库1006道题.pdf

    AOP联盟:aopalliance.jar API包

    AOP联盟:aopalliance.jar API包a set of AOP Java interface .

    spring aop jar 包

    Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的重要组成部分,它提供了一种在不修改源代码的情况下,对程序进行功能增强的技术。这个"spring aop jar 包"包含了实现这一功能所需的类和接口,...

    aop开发环境jar包

    在IT行业中,AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,它旨在提高软件的模块化程度,将关注点分离。在Java世界里,AOP常用于处理日志、事务管理、权限检查等横切关注点。当我们谈到“AOP...

    aopalliance最新完整jar包

    在Java应用中,aopalliance.jar包扮演着至关重要的角色,它包含了一些核心接口,如`org.aopalliance.intercept.MethodInterceptor`和`org.aopalliance.aop.Advice`,这些接口定义了拦截器和通知的概念,它们是AOP的...

    aopalliance

    它定义了一些基础的AOP接口,如`org.aopalliance.intercept.MethodInterceptor`和`org.aopalliance.aop.Advice`,这些接口被广泛应用于诸如AspectJ、Spring AOP等AOP框架中。 二、AOPAlliance在Spring 2.0中的作用 ...

    AOP使用CGLIB实现AOP功能

    Spring AOP实现方法之一:CGLIB 实现AOP功能

    aopalliance-1.0

    《AOP Alliance 1.0:面向切面编程的核心接口》 在软件开发领域,AOP(Aspect-Oriented Programming,面向切面编程)是一种重要的编程范式,它旨在提高代码的可重用性和模块化程度,使得关注点分离得以更好地实现。...

    反射实现 AOP 动态代理模式(Spring AOP 的实现原理)

    面向切面编程(AOP)是一种编程范式,旨在将横切关注点(如日志、安全等)与业务逻辑分离,从而提高模块化。AOP通过预定义的“切面”对横切关注点进行模块化,从而可以在不修改业务逻辑代码的情况下增加新功能。动态...

    基于注解实现SpringAop

    基于注解实现SpringAop基于注解实现SpringAop基于注解实现SpringAop

Global site tag (gtag.js) - Google Analytics