Modularizing and Code Reuse Using AOP

Sky-Tiger發表於2007-02-10

Aspect-Oriented Programming (AOP) is a new exciting paradigm. It is not a competitor to the famous Object-Oriented Programming (OOP), they actually complement each other. It can be considered an extension to OOP. AOP modularizes software applications based on loosely coupled aspects, whereas OOP does it by using Encapsulation, Inheritance, and Polymorphism.

AOP is a concept and not bound to any programming language. Software vendors can provide implementation for AOP in any programming language and make it available for the entire software community. Several vendors provide implementations in the Java language for AOP. This article uses the AspectJ implementation of AOP and will attempt to give some insight about code modularity and reuse using aspects.

[@more@]

Crosscutting Concerns

A concern is nothing but a function in a given system. Any system is typically composed of both core and non-core concerns. The non-core concerns such as logging and security are actually the supporting functionalities for the mainstay core functionalities. The core functionality is the one that the system is expected to do.

The main job of a non-core concern is to provide some extra functionality such as error handling to the core functionality, which will help in system management. But, in real life, what happens? For instance, take the example of a logging concern. Everyone will try to design in such as way that logging is implemented in a generic way and used for all modules/components of the system. Eventually, what happens? The logging code will cut across almost all modules in the system and become interleaved with the code responsible for core concerns. Thus, the logging concern becomes tightly coupled with the core concerns and becomes inseparable. In the case that any modification/enhancement/removal of logging is required, it will almost become impossible to do so because it involves huge efforts in terms of development and testing time.

Here is where AOP pitches in. AOP helps separate the non-core concerns from the core concerns by implementing concerns as aspects. Each aspect is independent and loosely coupled with other aspects in the system. This provides the flexibility for developers to enhance or remove any aspect at a later point in time without affecting the design and current state of the system.

Putting AOP to Practical Use

Think about another scenario, wherein AOP can really be useful. A developer has put in a lot of effort to implement an excellent business application, test it, and also move it into production systems. Later, he learns that execution of a particular logic in the application consumes more time than he has expected. To unveil the problem, he wants to benchmark the logic.

The one option that you could think of is wherever this logic is being called, just put the time stamps before and after invocations to measure the time taken to execute. Assume that it has been used in several places in the application; just think about the amount of effort involved in getting this task done. Huge, right???

AOP helps accomplishing this in a simple, maintainable, loosely coupled and reusable way. The benchmarking logics can be encapsulated separately as an aspect that can be reused for benchmarking other applications. You get the following advantages as you implement benchmarking as an aspect:

  • Encapsulating benchmark logic as a separate concern that can be re-used elsewhere.
  • This aspect could be used only for testing and removed later without affecting the original application.
  • Absolutely zero changes would be required in the original application under test.

That's a lot of theory. It's time to get your hands dirty.

Take a loan calculator example. Given the principle amount, tenure in months, and the interest rate per annum, the loan calculator should be able to give you the monthly installment that you might need to pay.

Conventional way of benchmarking

Please refer to the sample programs to benchmark the loan calculator application.

Loan Calculator

package sample;
public class LoanCalculator {
   public double calculateEMI ( int principle, int tenure,
                                double interest) {
      double emi ;
      // calculate the Equated Monthly Installment
      return emi;
   }
}

Loan Client

package sample;
public class LoanClient {
   public double calculate(){
      System.out.println("Calculate EMI...");
      double installment =
         new LoanCalculator().calculateEMI(100000, 60, 9.5);
      System.out.println("EMI is - "+ installment);
      return installment;
   }
   public static void main(String[] args){
      new LoanClient().calculate();
   }
}

Loan client with benchmarking

package sample;
public class LoanClient2 {
   public double calculate(){
      long start = System.currentTimeMillis();
      System.out.println("Calculate EMI...");
      double installment =
         new LoanCalculator().calculateEMI(100000, 60, 9.5);
      System.out.println("EMI is - "+ installment);
      long end = System.currentTimeMillis();
      return installment;
   }
   public static void main(String[] args){
      new LoanClient2().calculate();
   }
}

Please look at LoanClient2.java. The system time stamps have been put before and after invoking the business methods. Because of this ad-hoc method, there are several disadvantages:

  • Benchmark logic has been interleaved with core logic
  • Benchmark logic has been tightly coupled with core logic; they are almost inseparable
  • Benchmark logic cannot be reused. (Ignore copy & paste)
  • Management of code is very difficult.

What you need here is a re-usable, easily manageable and separable programming construct. AOP provides that.

The AOP Way of Benchmarking

In this section, you can see how AOP can be used to benchmark this loan calculator application. AOP can be configured to dynamically pick up the execution points within a program during execution and intercept the methods and fields to get to know what is happening around them.

An execution point within a program is called Join Point. For example, calling to a method is a join point. A set of join points is called point cut. You can configure many such point cuts. Advice is an encapsulation of piece of code (in your case, it is benchmarking logic) that you want to execute, when the execution points (in other words, point cuts) are detected during execution. For more information, please refer to .

You might need to get your hands little dirty before getting AspectJ working. Let me go step by step how to get it done. For your example, you use the AspectJ implementation of AOP.

  • Create aspect: AspectJ supports developing aspects based on annotations. You would need to have JDK 1.5 installed in your machine to try out the following programs. By using annotation-based developments, you can create regular Java programs but instruct JDK to generate aspects. The rest will be taken care by JDK and AspectJ.

    In the sample aspect, you have used "Around" advice and a point cut (whose configuration has been externalized by using aop.xml, which is explained in the next section).

  • Configure point cuts: The point cut configuration can be externalized by using aop.xml. The only one condition is that the META-INFaop.xml file has to be placed in CLASSPATH. From the point cut configuration, you can understand that AspectJ will intercept all calls to methods present in the sample.LoanCalculator class.
  • AspectJ Weaver: For AspectJ to know what should be intercepted, it uses something called "Weaver." The application classes may be woven during compile or runtime. Here, you use runtime-weaving functionality by passing "-javaagent:aspectjweaver.jar" as a JVM argument when you run the application.
  • Create Aspect:

    package aspect;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    
    @Aspect
    public abstract class AbstractBenchmarkAspect {
       @Pointcut
       public abstract void benchmark();
    
       @Around("benchmark()")
       public Object executeBenchmarkAdvise(ProceedingJoinPoint jp)
          throws Throwable{
          long startTime = System.currentTimeMillis();
          Object response = jp.proceed();
          long endTime = System.currentTimeMillis();
          System.out.println("TIME  TAKEN (in msecs): "+
             (endTime - startTime));
          return response;
       }
    }
    

    Point cut:

    
       
          
           
          
       
    
    

    The build file has been given; by using it, you can run both flavors of benchmarking. Set the environment variables for Ant and then run "ant" to build and run both flavors.

    Build.xml

    
    
       
          
       
       
          
             
          
       
    
       
          ========================================
          Running without aspect...
          ========================================
          
             
          
    
          
          ========================================
          Running with aspect...
          ========================================
    
          
             
             
          
       
    
       
          
          
          
             
          
       
    
    

    Advantages

    Aspect-Oriented Programming has numerous advantages. Some of them are mentioned below:

    • Aspects are loosely coupled
    • Reusable
    • Maintenance is easy
    • The following kind of aspects can be built
      • Error handling
      • Functional Testing
      • Performance Testing
      • Access Control
      • Logging
      • Event notification

    Disadvantages

    To give fair coverage of the topic I should list any negatives along with all the positives. On the downside, in my opinion, I found the learning curve steep. It takes a little longer to understand the concepts of joint point, advice and annotations style of programming. It also adds some latency to the target application, which might make you feel the performance hit.

    Summary

    Apart from AspectJ, there are other implementations also available. Some of them are Spring, Jboss, and AspectWerks. It's up to you to choose the implementation that is right for you. AOP is easier to understand and implement. It achieves code reuse and modularization at much greater levels. It removes the cross cutting concerns and makes application loosely coupled and maintenance easy.

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/71047/viewspace-898974/,如需轉載,請註明出處,否則將追究法律責任。

相關文章