5,699,997 members and growing! (20,607 online)
Email Password   helpLost your password?
General Reading » Book Chapters » General     Advanced License: The Code Project Open License (CPOL)

Building Spring 2 Enterprise Applications: Chapter 4: Spring AOP 2.0

By aPress

The open-source Spring Framework has become a popular application framework for building enterprise Java apps. This chapter explores the newest features in Spring AOP (Aspect-Oriented Programming), including @AspectJ-style annotations, the AspectJ pointcut language, Spring AOP XML tags and more.
Dev, Design

Posted: 19 May 2008
Updated: 19 May 2008
Views: 3,349
Bookmarked: 1 time
Announcements
Loading...



Search    
Advanced Search
Sitemap
votes for this Article.
Popularity: 0.00 Rating: 0.00 out of 5
Note: This is an unedited contribution. If this article is inappropriate, needs attention or copies someone else's work without reference then please Report This Article

Title Building Spring 2 Enterprise Applications
Author(s) Interface21, Bram Smeets, Seth Ladd
Publisher Apress
Published August 2007
ISBN 978-1-59059-918-1
Pages 335

Welcome to the chapter on the future of Spring AOP. In Chapter 3, we described how Spring AOP has been used up to the Spring 1.2.x releases. This chapter covers features added to Spring AOP in the 2.0 release.

That's right, new features have been added, so everything you learned about AOP so far is still applicable and available. This really is proof that the Spring 2.0 release remains fully backward compatible with Spring 1.2.x. We strongly recommend upgrading your Spring version to the latest 2.0 release. Full backward-compatibility is assured.

If you haven't done so already, now is a good time to review the concepts covered in Chapter 3, as they continue to be the foundations of Spring AOP.

The following are the new features that will be covered in detail in this chapter:

  • The @AspectJ-style of writing aspects with Java 5 annotations, including the supported advice types
  • The AspectJ pointcut language
  • The Spring AOP XML tags to declare aspects in XML for those cases where Java 5 is not available or existing classes must be used as advice
  • The Spring AOP XML advisor tag to combine classic Spring AOP advice classes and the AspectJ pointcut language

Introducing AspectJ and Aspects

While classic Spring AOP (covered in Chapter 3) works with advice, pointcuts, and advisors, the new Spring AOP works with advice, pointcuts, advisors, and aspects. Not much of a difference you may think, but as you'll find out soon, things have changed significantly. Literally all the new Spring AOP features are built on top of the integration with the AspectJ AOP framework. (The proxy-based interception mechanism remains in place, so the skills you've gained from the previous chapter will remain useful.) So what is AspectJ? The AspectJ FAQ (http://www.eclipse.org/aspectj/doc/released/ faq.html) answers this question as follows:
AspectJ is a simple and practical extension to the Java programming language that adds to Java aspect-oriented programming (AOP) capabilities. AOP allows developers to reap the benefits of modularity for concerns that cut across the natural units of modularity. In objectoriented programs like Java, the natural unit of modularity is the class. In AspectJ, aspects modularize concerns that affect more than one class.
And what is an aspect? That is also answered by the same FAQ as follows:

Aspects are how developers encapsulate concerns that cut across classes, the natural unit of modularity in Java.
From the previous chapter, you know that cross-cutting concerns are modularized as advice. These are encapsulated by an advisor, which combines one advice and one pointcut. This encapsulation tells at which join points in the software the advice is executed.

Aspects and advisors seem to have much in common: they both encapsulate concerns that cut across classes. Advice is executed at join points that are matched by a pointcut; however, a given pointcut may not match any join points in an application.

Now let's look at what you can do with an aspect:

  • You can declare pointcuts.
  • You can declare errors and warnings for each join point that is selected by the associated pointcut.
  • You can declare new fields, constructors, and methods in classes. These are called inter-type declarations in AspectJ.
  • You can declare one or more advices, each one executed for all joint points matched by a pointcut.

When comparing the two, it quickly becomes clear an aspect is a much more sophisticated construct than an advisor. For now, it's sufficient to understand aspects and advisors both encapsulate cross-cutting concerns yet take a different approach.

Join Points and Pointcuts in AspectJ

AspectJ supports many more join point types than Spring AOP, which supports only method executions. The following is a selection of join points supported by AspectJ:
  • Calls to methods and execution of instance and static methods
  • Calls to get and set values on instance fields and static fields
  • Calls to constructors and execution of constructors
  • Classes and packages
None of these additional join points are featured in Spring AOP. However, it's useful to have an idea about which join points are supported by AspectJ when discussing pointcuts.

To select the rich set of supported join points, AspectJ has its own pointcut language. The following pointcut selects all static and instance methods named relax, regardless of their arguments, return type, or classes:

execution(* relax(..))
When you consider all the join point types supported by AspectJ, a proper language is the only flexible way to define pointcuts. Any other means, including XML configuration or an API, would be a nightmare to write, read, and maintain.

Spring AOP integrates with this AspectJ pointcut language, which is covered later in this chapter, in the "Working with Pointcuts" section. For now, all you need to know is that the asterisk (*) matches any method or class name or any argument type, and the double dot (..) matches zero or more arguments.

AspectJ Aspect Creation

AspectJ has its own language that extends the Java language specifications for creating aspects.

Originally, this was the only way to declare aspects with AspectJ. Because aspects and pointcuts are treated as first-class citizens, it's a very practical AOP language. Spring AOP does not integrate with this language, but to give you a better understanding of AspectJ aspects, here's a very simple example:

package com.apress.springbook.chapter04.aspects; 

public aspect MySimpleAspectJAspect { 
  before(): execution(* relax(..)) { 
    System.out.println("relax() method is about to be executed!"); 
  } 
} 
As you can see, the aspect is somewhat comparable to a Java class, but you wouldn't be able to compile it with a regular Java compiler.

AspectJ 1.5 has introduced Java 5 annotations to allow programmers to write AspectJ aspects as an alternative to the AspectJ language. (If you're not familiar with Java 5 annotations, you can find an introduction at http://www.developer.com/java/other/article.php/3556176.) Spring AOP integrates with this way of writing aspects, as detailed in this chapter. Listing 4-1 shows how the previous aspect looks when it's rewritten with annotations. This style is called the @AspectJ-style, although the @Aspect annotation is used. As you can see, aspects become regular Java classes.

Listing 4-1. A Simple AspectJ Aspect Written in the @AspectJ-Style

package com.apress.springbook.chapter04.aspects; 

import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.Before; 


@Aspect 
public class MySimpleAtAspectJAspect { 

  @Before("execution(* relax(..))") 
  public void beforeRelaxingMethod() { 
      System.out.println("relax() method is about to be executed!"); 
  } 
} 
The aspect in Listing 4-1 declares a regular Java class that is annotated with the @AspectJ-style Java 5 annotations. The class declares one pointcut/advice pair. The @Aspect annotation on the class declaration indicates that this class is an @AspectJ-style aspect. A class needs to have this annotation to qualify as an aspect.

The @Before annotation is used to turn the regular beforeRelaxingMethod() method into an advice declaration and holds the pointcut declaration for the advice. In AspectJ, an advice cannot exist without a pointcut.

The annotation type also defines the advice type; in this case, it's before advice. The @AspectJstyle supports the advice types defined in Chapter 3 plus one more. Only instance methods with an @AspectJ advice type annotation are advice declarations, so an aspect class can also have regular methods.

The @AspectJ annotations can be used on abstract classes and even interfaces, although this is not very useful, as the annotations are not inherited.

Listing 4-2 shows a class with one method that will be one of the join points matched by the pointcut in Listing 4-1.

Listing 4-2. The relax() method in the SunnyDay Class Is Selected As a Join Point

package com.apress.springbook.chapter04; 

public class SunnyDay { 
  public void relax() { 
      // go to the beach 
  } 
} 
Before the relax() method is executed, a message will be printed on the console. The print statement is the actual advice that is executed. The @AspectJ-style requires Java 5. Also, existing classes that don't declare the @AspectJ annotations cannot be used as advice.

In the typical Spring style, you can declare aspects in Spring AOP without using Java 5 and annotations. By making clever use of the Spring 2.0 XML Schema support (introduced in Chapter 2), the Spring developers have been able to define AOP tags for declaring aspects, advice, and pointcuts. There is also a new tag to declare advisors. This chapter covers these new XML tags after introducing the @AspectJ-style of declaring aspects and the pointcut language in more detail.

Now, without further ado, here comes Spring 2.0 AOP.


Note

You can find much more information about AspectJ at http://www.eclipse.org/aspectj/ . Another excellent resource is AspectJ in Action by Ramnivas Laddad (Manning, 2003).


Configuring @AspectJ-Style Aspects in Spring

By now, you know what an aspect looks like and how you can write one yourself. In this section, we'll start with an example of an @AspectJ-style aspect that's configured in the Spring container.

This will demonstrate how the Spring AOP framework uses aspects and creates proxy objects. After the example, we'll look at the details of advice types, pointcuts, and proxy objects.

A Simple @AspectJ-Style Aspect

@AspectJ-style aspects must be configured in the Spring container to be usable by Spring AOP. From the previous chapter, you'll remember proxy objects were created by using ProxyFactoryBean in the Spring container. In that case, we took our first AOP steps with a configuration per target object to create proxy objects. With @AspectJ-style aspects, Spring AOP takes a different approach to creating proxy objects based on the pointcuts in aspects, as this example will demonstrate. In this example, we'll use one simple pointcut so we can focus on the aspects. As the chapter progresses, we'll use more elaborate pointcut examples.

Aspect Definition

The aspect for this example is shown in Listing 4-3. It has one pointcut that selects all startMatch() methods it can find and an advice that prints a message to the console when this occurs. In the next sections, we'll look in more detail at how join points are searched for and what happens if they are found.

Listing 4-3. Aspect with Pointcut That Selects All startMatch() methods and Advice That Prints a Message Before the Join Point Is Executed

package com.apress.springbook.chapter04.aspects; 

import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.Before; 

@Aspect 
public class MessagePrintingAspect { 

  @Before("execution(* startMatch(..))") 
  public void printMessageToInformMatchStarts() { 
      System.out.println("Attempting to start tennis match!"); 
  } 
}

Note

You need to include the aspectjweaver.jar and aspectjrt.jar in your classpath. Both files can be found in the Spring Framework distribution under the lib/aspectj directory.


The MessagePrintingAspect in Listing 4-3 is a regular Java class with Java 5 annotations. It's also an aspect declaration because of the @AspectJ-style annotations.

The @Aspect annotation on the class declaration turns this class into an aspect declaration.

It can now hold pointcut declarations and advice/pointcut combinations. The aspect is called MessagePrintingAspect, indicating its responsibility is to print messages to the console. When we want to print messages for other join points, we can add more advice/pointcut combinations to this aspect. By organizing (or modularizing) advice that logically belongs together in aspects, it will be trivial to get an overview of which messages are printed to the console for which join points.

The @Before annotation on the printMessageToInformMatchStarts() method declaration has two roles: it defines the advice type (before advice), and it holds the pointcut declaration. Again, we've chosen a name, printMessageToInformMatchStarts, that explains the responsibilities of the advice.


Tip

Giving descriptive names to advice helps to organize your thoughts and organize advices. If you're having trouble coming up with names for your advices that exactly describe what they do, maybe they're overloaded with responsibilities and should be split into smaller parts.

The pointcut declaration selects all instance methods named startMatch(), regardless of the number of arguments, argument types, throws declarations, return type, visibility, or classes that declare them. Now that you understand the aspect declaration, it's time to look at the target class of this example.

Target Class

The target class in this example is our friend DefaultTournamentMatchManager, as shown in Listing 4-4.

Listing 4-4. DefaultTournamentMatchManager Class

package com.apress.springbook.chapter04; 

public class DefaultTournamentMatchManager implements TournamentMatchManager { 
  public Match startMatch(long matchId) throws 
    UnknownMatchException, MatchIsFinishedException, 
    MatchCannotBePlayedException, PreviousMatchesNotFinishedException { 
  // implementation omitted 
  } 

  /* other methods omitted */ 
} 
The startMatch() method matches the criteria of the pointcut in Listing 4-3. This doesn't mean, however, that Spring AOP will start creating proxy objects just like that. First, we must configure a target object and the @AspectJ-style aspect in the Spring container, as discussed in the next section.

Aspect Configuration

Listing 4-5 shows the required configuration in a Spring XML configuration file to have the printMessageToInformMatchStarts advice print a message to the console before the startMatch() method is executed (there is another way to do this, which we'll explore in the "Using AOP XML Tags" section later in this chapter).

Listing 4-5. aspect-config.xml: Required Configuration in a Spring XML File

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
    "http://www.springframework.org/dtd/spring-beans.dtd"> 
<beans> 
  <bean class="org.springframework.aop.aspectj.annotation.  --> 
AnnotationAwareAspectJAutoProxyCreator"/> 

  <bean class="com.apress.springbook.chapter04.aspects.MessagePrintingAspect"/> 

  <bean id="tournamentMatchManager" 
    class="com.apress.springbook.chapter04.DefaultTournamentMatchManager"> 
    <!-- properties omitted --> 
  </bean> 
</beans> 
Spring AOP provides a powerful integration with the Spring container called auto-proxy creation. Spring AOP will extend the bean life cycle of the Spring container to create proxy objects for those beans in the container that have join points that are matched by one or more pointcuts.

We'll look into the details of how the proxy is created in the next sections. For now, it's sufficient to understand that an object for the AnnotationAwareAspectJAutoProxyCreator bean definition in Listing 4-5 will be created first when the Spring container (ApplicationContext) loads. Once this is done, the Spring container detects any classes that have @Aspect annotation and uses them to configure Spring AOP.

The AnnotationAwareAspectJAutoProxyCreator bean has the potential to affect all other beans that are created by the container. During the bean life cycle of the tournamentMatchManager bean, AnnotationAwareAspectJAutoProxyCreator will create a proxy object for this bean and replace the original bean with the proxy object because one of its join points (the startMatch() method) is matched by the advice/pointcut combination in the MessagePrintingAspect.

The printMessageToInformMatchStarts advice will be called when the startMatch() method is executed on the tournamentMatchManager bean. Now, let's find out if the printMessageToInform MatchStarts advice actually gets called and prints a message before the startMatch() method is executed.

An Integration Test for the Configuration and Aspect

We can now use a simple integration test to verify if the message is printed to the console when the startMatch() method is called on the tournamentMatchManager bean. We'll also add a test that creates a new DefaultTournamentMatchManager object and calls its startMatch() method to verify that no message is printed when this method is called. Listing 4-6 shows the integration test case.

Listing 4-6. Integration Test Case for the Spring AOP Configuration and the Aspect

package com.apress.springbook.chapter04; 

import org.springframework.test.AbstractDependencyInjectionSpringContextTests; 

public class MessagePrintingAspectIntegrationTests extends 
    AbstractDependencyInjectionSpringContextTests { 
  
  protected String[] getConfigLocations() { 
    return new String[] { 
     "classpath:com/apress/springbook/chapter04/" + 
     "aspect-config.xml" 
    }; 
  }
  
  private TournamentMatchManager tournamentMatchManager; 
  
  public void setTournamentMatchManager( 
          TournamentMatchManager tournamentMatchManager) { 
    this.tournamentMatchManager = tournamentMatchManager; 
  } 

  public void testCallStartMatchMethodOnBeanFromContainer() 
      throws Exception { 
    System.out.println("=== GOING TO CALL METHOD " + 
          "ON BEAN FROM CONTAINER ==="); 
          
  this.tournamentMatchManager.startMatch(1); 
  
  System.out.println("=== FINISHED CALLING METHOD " + 
        "ON BEAN FROM CONTAINER ===");     
  } 
  
  public void testCallStartMatchMethodOnNewlyCreatedObject() 
      throws Exception { 
    TournamentMatchManager newTournamentMatchManager = 
        new DefaultTournamentMatchManager(); 
        
  System.out.println("=== GOING TO CALL METHOD " + 
          "ON NEWLY CREATED OBJECT ==="); 
          
  newTournamentMatchManager.startMatch(1); 
      System.out.println("=== FINISHED CALLING METHOD " + 
          "ON NEWLY CREATED OBJECT ==="); 
    } 
  } 
The test case in Listing 4-6 loads the Spring XML configuration file (Listing 4-5). It declares two tests:

testCallStartMatchMethodOnBeanFromContainer(): This test uses a tournamentMatchManager object that is injected from the container. This is the tournamentMatchManager bean defined in the Spring XML configuration file. The test calls the startMatch() method on this object. The tournamentMatchManager bean is a proxy object that has been created by the AnnotationAware AspectJAutoProxyCreator bean. A proxy object was created because the sole pointcut in the MessagePrintingAspect matches the startMatch() join point. When the startMatch() method is executed on the proxy object, the printMessageToInformMatchStarts advice, which prints its message to the console, will be executed, and then the actual method on the target object will be executed.

testCallStartMatchMethodOnNewlyCreatedObject(): This test creates a new DefaultTournament MatchManager object. This object is not a proxy and is in no way touched or affected by Spring AOP. When its startMatch() method is called, no advice will be executed. Because this object is not created by the Spring container, it is not affected by the MessagePrintingAspect.

When the test case in Listing 4-6 is executed, messages will be printed on the console as follows:

=== GOING TO CALL METHOD ON BEAN FROM CONTAINER === 
Attempting to start tennis match! 
=== FINISHED CALLING METHOD ON BEAN FROM CONTAINER === 
=== GOING TO CALL METHOD ON NEWLY CREATED OBJECT === 
=== FINISHED CALLING METHOD ON NEWLY CREATED OBJECT === 

The printMessageToInformMatchStarts() advice method declared in MessagePrintingAspect is executed when the startMatch() join point is executed on the tournamentMatchManager bean.

Our example touches many facets of how Spring AOP deals with aspects. You've been exposed to all the requirements that must be met in order to use @AspectJ-style aspects with Spring AOP:

  • Join points need to be public or protected instance methods on objects.
  • Objects must be created by the Spring container.
  • Callers need to call methods on the proxy objects, not on the original objects.
  • Aspect instances must also be created by the Spring container.
  • A special bean must be created by the Spring container to take care of auto-proxy creation.

Now, let's look at the advice types supported by aspects in Spring AOP.

@AspectJ-Style Advice Types

Aspects in Spring AOP are not declared by interfaces as is the case for classic Spring AOP. Instead, an advice is declared as a regular Java method, which can have arguments, return objects, and throw exceptions. As you saw in the previous example, the advice type is defined by the @Aspect annotation declaration on methods. The following advice types are supported:

Before advice (@Before): Executed before a join point is executed. It has the same semantics as before advice described in the previous chapter. It can prevent method execution on the target object from happening only by throwing an exception.

After returning advice (@AfterReturning): Executed after a join point has been executed without throwing an exception. It has the same semantics as after returning advice described in the previous chapter. It can have access to the return value of the method execution if it wants to, but can't replace the return value.

After throwing advice (@AfterThrowing): Executed after executing a join point that threw an exception. It has the same semantics as throws advice described in the previous chapter. It can have access to the exception that was thrown if it wants to, but can't prevent this exception from being thrown to the caller unless it throws another exception.

After (finally) advice (@After): Always called after a join point has been executed, regardless of whether the join point execution threw an exception or not. This is a new advice type that is not available in classic Spring AOP. It can't get access to the return value or an exception that was thrown.

Around advice (@Around): Executed as an interceptor around the execution of a join point. As with around advice described in the previous chapter, it's the most powerful advice type, but also the one that requires the most work.


Note

Actually, the Spring 2.0 AOP framework supports a sixth advice type: the introduction advice. We won't discuss this advice type in this book since it's not often used. You can just remember it is available and that it can be used to add methods and properties to the advised class.


You saw an example of before advice in the previous examples; MessagePrintingAspect contained before advice. Let's take a quick look at the other advice types and how to declare them in an @AspectJ-style aspect.

After Returning Advice

After returning advice is called when a join point has been executed and has exited with a return value or without a return value if the return type is void. Listing 4-7 shows MessagePrintingAspect with after returning advice.

Listing 4-7. Printing a Message After a Join Point Has Been Executed Normally

package com.apress.springbook.chapter04.aspects; 

import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.AfterReturning; 


@Aspect 
public class MessagePrintingAspect { 
  @AfterReturning("execution(* startMatch(..))") 
  public void printMessageWhenTennisMatchHasBeenStartedSuccessfully() { 
    System.out.println("Tennis match was started successfully!"); 
  } 
} 
After Throwing Advice

If you want to do some work when a join point throws an exception, you can use after throwing advice. Listing 4-8 shows MessagePrintingAspect with after throwing advice that prints out a warning when an exception is thrown.

Listing 4-8. Printing a Warning Message After a Join Point Has Thrown an Exception

package com.apress.springbook.chapter04.aspects; 

import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.AfterThrowing; 


@Aspect 
public class MessagePrintingAspect { 
  @AfterThrowing("execution(* startMatch(..))") 
  public void printMessageWhenSomethingGoesWrong() { 
    System.out.println("Oops, couldn't start the tennis match. " + 
        "Something went wrong!"); 
  } 
}

After (Finally) Advice

After (finally) advice is always executed after a join point has been executed, but it can't get hold of the return value or any exception that is thrown. In other words, this advice type can't determine the outcome of the execution of the join point. It's typically used to clean up resources, such as to clean up objects that may still be attached to the current thread.

Listing 4-9 shows MessagePrintingAspect with after (finally) advice that prints a message to bring closure to the tennis match-starting event.

Listing 4-9. Printing a Message When a Tennis Match Start Has Been Attempted

package com.apress.springbook.chapter04.aspects; 

import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.After; 


@Aspect 
public class MessagePrintingAspect { 
  @After("execution(* startMatch(..))")   
  public void printMessageToConcludeTheTennisMatchStartAttempt() { 
    System.out.println("A tennis match start attempt has taken place. " + 
      "We haven't been informed about the outcome but we sincerely " + 
      "hope everything worked out OK and wish you very nice day!"); 
  } 
}

Around Advice

Around advice is the most complicated type to use because it hasn't been specifically designed for any particular tasks. Instead, it's based on an interception model that allows you to take full control over the join point execution.

Its semantics are the same as those of MethodInterceptor, which was discussed in the previous chapter. As is the case with MethodInterceptor, this advice needs to able to proceed with the ongoing method execution. For this purpose, every around advice method must have a ProceedingJoinPoint declared as its first argument, as shown in Listing 4-10.

Listing 4-10. Passing on Our Regards and Then Getting on with Things

package com.apress.springbook.chapter04.aspects; 

import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.Around; 

import org.aspectj.lang.ProceedingJoinPoint; 


@Aspect 
public class MessagePrintingAspect { 
  @Around("execution(* startMatch(..))") 
  public Object printMessageToTellHowNiceTheLifeOfAnAdviceIs( 
      ProceedingJoinPoint pjp) throws Throwable { 

    System.out.println("Greetings, Master, how are you today? I'm " 
      "very glad you're passing by today and hope you'll enjoy " + 
      "your visit!"); 
    try { 
      return pjp.proceed(); 
    } finally { 
      System.out.println("Au revoir, Master, I'm sorry you can't stay " + 
      "longer, but I'm sure you'll pay me a visit again. Have a very " + 
      "nice day yourself, sir!"); 
    } 
  } 
} 
The example of around advice in Listing 4-10 looks different from the previous examples. The first thing to notice is the advice method signature. Three things are special about this signature:
  • The return type is java.lang.Object; the other advice types have return type void.
  • The first argument is of type org.aspectj.lang.ProceedingJoinPoint.
  • The method declares java.lang.Throwable in its throws clause.

Another interesting thing to notice in Listing 4-10 is the call to the proceed() method on the ProceedingJoinPoint object. The entire advice method is actually very comparable to the invoke() method on MethodInterceptor used by classic Spring AOP:

package org.aopalliance.intercept; public interface MethodInterceptor extends Interceptor { Object invoke(MethodInvocation invocation) throws Throwable; } If you're familiar with how the MethodInceptor and its MethodInvocation object work, you'll find around advice and ProceedingJoinPoint very easy to use.

Pointcut Declaration and Reuse

You can also declare named pointcuts in @AspectJ-style aspects. These pointcuts are a great way to reuse pointcut declarations throughout your aspects.

Listing 4-11 shows an example of an aspect with a named pointcut declaration.

Listing 4-11. An Aspect That Declares Systemwide Pointcuts

package com.apress.springbook.chapter04.aspects; 

import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.Pointcut; 


@Aspect 
public class SystemPointcutsAspect { 
  @Pointcut("within(com.apress.springbook.chapter04.service..*)")   
  public void inServiceLayer() {  } 
} 
The inServiceLayer pointcut selects all join points in the com.apress.springbook.chapter04.

service package, meaning all public and protected methods of all classes in this package and its subpackages. within() is a pointcut designator, which we'll discuss in the "Working with Pointcuts" section later in this chapter.

The inServiceLayer() method is a pointcut declaration, but also a regular Java method. However, Spring AOP will never execute this method; instead, it will read its @Pointcut annotation. So it's not useful to add any implementation to the method body, and it's not even useful to call this method yourself, because it's a pointcut declaration. We recommend that methods with the @Pointcut annotation always have an empty method body. It's the name of the method that's important here.

We can now reuse the inServiceLayer pointcut in other aspects, as shown in Listing 4-12 (if you do this, remember to configure both aspects).

Listing 4-12. Reusing the inServiceLayer Pointcut in Another Aspect

package com.apress.springbook.chapter04.aspects; 

import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.Before; 


@Aspect 
public class SecurityAspect { 
  @Before("com.apress.springbook.chapter04.aspects." + 
    "SystemPointcutsAspect.inServiceLayer()")   
  public void denyAccessToAll() { 
    throw new IllegalStateException("This system has been compromised. " + 
        "Access is denied to all!"); 
  } 
} 
Pointcut reuse provides you with a powerful tool to select join points in one place and reuse these declarations anywhere. In Listing 4-11, we've defined the pointcut that selects the service layer of our application. In Listing 4-12, we decide to deny access to the system for all, since there's an unresolved security issue.

We can add more behaviors to the service layer by reusing the same pointcut in other aspects.

Reusing pointcut declarations will make your applications easier to maintain.

Auto-Proxy Creation in the Spring Container

We've already covered how to use AnnotationAwareAspectJAutoProxyCreator in the Spring container to enable auto-proxy creation, which is a requirement to use @AspectJ-style aspects with Spring AOP. In this section, we'll discuss another way of enabling auto-proxy creation. We'll also explain how Spring AOP 2.0 decides which proxy types to use, and we'll shed some more light on how Spring AOP decides to create proxy objects for beans.

Auto-Proxy Creation with the AOP XML Schema

The other way of enabling auto-proxy creation is to use the Spring AOP XML Schema and its <aop:aspectj-autoproxy> tag. Listing 4-13 shows a Spring XML configuration file that uses the AOP XML Schema and the aop namespace.

Listing 4-13. Using Spring's AOP XML Schema to Enable @AspectJ-Style Aspects in the Spring Container

<?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.xsd 
              http://www.springframework.org/schema/aop 
              http://www.springframework.org/schema/aop/spring-aop.xsd"> 

  <aop:aspectj-autoproxy/> 

</beans> 
Using the <aop:aspectj-autoproxy> XML tag has an advantage: if you accidentally define this tag more than once in your Spring configuration, no harm is done. If you configure the AnnotationAwareAspectJAutoProxyCreator more than once in your configuration, auto-proxy creation will occur twice for each bean—something you want to avoid. Otherwise, both approaches have exactly the same effect: auto-proxy creation is enabled for the entire Spring container.

Proxy Type Selection

The proxy type selection strategy in Spring AOP 2.0 has changed slightly from the previous version of Spring AOP. Since version 2.0, JDK proxy objects will be created for target objects that implement at least one interface. For target objects that implement no interfaces, CGLIB proxy objects will be created.

You can force the creation of CGLIB proxies for all target classes by setting the proxy-targetclass option to true:

<aop:aspectj-autoproxy proxy-target-class="true"/> Forcing the use of CGLIB proxy objects is required when at least one object for which a proxy object is created in the Spring container implements one or more interfaces, but is used as the class type by its callers. In this case, a JDK proxy object that implements only the interfaces would not be type-compatible for certain callers. Proxy objects created by CGLIB remain type-compatible with the target object.

In all other cases, you can safely leave the proxy-target-class option disabled.

The Proxying Process

In the example in Listing 4-5, we configured three beans to be loaded by the Spring container.

A proxy object was created for only one of them. Let's review the role of each bean definition in Listing 4-5:

AnnotationAwareAspectJAutoProxyCreator: This class is responsible for auto-proxy creation.

There's no need to create a proxy object for this bean, since it's not called by the application itself. Instead, it will enhance the bean life cycle for all other beans in the container.

MessagePrintingAspect: This is a regular Java class and an @AspectJ-style aspect. No proxy object is created for this bean, since it's also not called by the application. Instead, it embeds advices and pointcuts that will determine for which other beans in the container proxy objects will be created.

DefaultTournamentMatchManager: This class is part of the application logic. What's more, it has a join point that is matched by the pointcut in the MessagePrintingAspect: its startMatch() method. Because at least one join point is matched, a proxy object will be created and will replace the original bean in the container during the bean life cycle. So once the bean life cycle has been completed successfully for the tournamentMatchManager bean, the container will return a proxy object with advice and its target object.

So let's wrap up the rules for auto-proxy creation in the Spring container based on the example:

  • Beans that implement the org.springframework.beans.factory.BeanPostProcessor or org.springframework.beans.factory.BeanFactoryPostProcessor interfaces will never be proxied. AnnotationAwareAspectJAutoProxyCreator implements the BeanPostProcessor interface, which allows it to enhance the bean life cycle for beans created by the Spring container.
  • @AspectJ-style aspects, beans that implement the org.springframework.aop.Advisor or org.springframework.aop.Pointcut interfaces, and beans that implement any of the classic Spring AOP advice-type interfaces discussed in the previous chapter are excluded from autoproxy creation because they have infrastructural roles.
  • All other beans that are created by the Spring container are eligible for auto-proxy creation.

During the life cycle of each bean created by the Spring container—both singleton and prototype beans—the container will ask all aspects and advisors found in the container if one or more of the bean join points are matched by one of their pointcuts. If there is at least one match, a proxy object will be created for the bean and will replace that bean. The proxy object will have all the advice embedded for all join points that were matched.

To fully understand the last rule, you need to know how join points will be matched by any given pointcut. If you look back at the example and its pointcut in Listing 4-3, it's obvious that only methods named startMatch() will be matched. Later in this chapter, in the "Working with Pointcuts" section, we'll discuss other pointcuts that select join points in specific ways.

Advice and Aspect Ordering

Advice declared in aspects is automatically selected and added to a proxy object during autoproxy creation. It is entirely possible that two advices apply to the same join point. Consider the MessagePrintingAspect @AspectJ-style aspect shown in Listing 4-14.

Listing 4-14. Two Advices Will Be Executed for the Same Join Points

package com.apress.springbook.chapter04.aspects; 

import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.Pointcut; 
import org.aspectj.lang.annotation.Before; 


@Aspect 
public class MessagePrintingAspect { 
  @Pointcut("execution(* startMatch(..))")   
  public void atMatchStart() {} 

  @Before("atMatchStart()")   
  public void printHowAnnoyedWeAre() { 
    System.out.println("Leave it out! Another tennis match!?"); 
  } 
  
  @Before("atMatchStart()")   
  public void printHowExcitedWeAre() { 
    System.out.println("Hurray for another tennis match!"); 
  } 
} 
The aspect in Listing 4-14 declares two advices that will be executed for the same join points.

This may leave you wondering in what order they will be executed, In this example, the actual order is not very important, but in other scenarios, it may be important to understand the exact order. And what would the order be if these two advices were defined in different aspects?

Ordering Advice

In those cases where advices are declared in the same aspect and they are both executed for the same join point, Spring AOP uses the same order as AspectJ: the order of declaration. So, advices in the same aspect that are executed for the same join point will maintain their order of declaration.

For the aspect in Listing 4-14, consider the Spring configuration in Listing 4-15.

Listing 4-15. Configuring DefaultTournamentMatchManager with Two Advices Declared in the Same Aspect

<beans> 
  <bean class="org.springframework.aop.aspectj.annotation. --> 
AnnotationAwareAspectJAutoProxyCreator"/> 

  <bean class="com.apress.springbook.chapter04.aspects.MessagePrintingAspect"/> 

  <bean id="tournamentMatchManager" 
    class="com.apress.springbook.chapter04.DefaultTournamentMatchManager"> 
    <!-- properties omitted --> 
  </bean> 
</beans> 
When the startMatch() method on the tournamentMatchManager bean is executed, the following messages are printed on the console:

Leave it out! Another tennis match!?

Hurray for another tennis match! So, the two aspects are executed in the order in which they are declared.

Ordering Aspects

When two advices that are declared in different aspects are executed for the same join point, the order is determined by the org.springframework.core.Ordered interface, as shown in Listing 4-16.

Listing 4-16. Spring's Ordered Interface

package org.springframework.core; 

public interface Ordered { 
  int getOrder(); 
} 
The Spring Framework uses the Ordered interface whenever a list of object needs to be processed in a particular order. By implementing the Ordered interface aspects, you can place your advices in a specific spot in the order of advice execution for join points. The ordering rules for aspects are as follows:
  • Aspects that don't implement the Ordered interface are in an undetermined order and come after the aspects that do implement the interface.
  • Aspects that implement the Ordered interface are ordered according to the return value of the getOrder() method. The lowest values get the first position.
  • Two or more aspects that have the same return value for the getOrder() method are in an undetermined order.

To demonstrate how the ordering of aspects works, we first create a common pointcut, as shown in Listing 4-17.

Listing 4-17. A Common Pointcut

package com.apress.springbook.chapter04.aspects; 

import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.Pointcut; 


@Aspect 
public class TennisMatchEventsAspect { 
  @Pointcut("execution(* startMatch(..))")   
  public void atMatchStart() {  } 
} 
Next, we'll declare two advices in separate aspects, as shown in Listings 4-18 and 4-19.

Listing 4-18. Aspect That Implements Spring's Ordered Interface

package com.apress.springbook.chapter04.aspects; 

import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.Before; 


import org.springframework.core.Ordered; 


@Aspect 
public class HappyMessagePrintingAspect implements Ordered { 
  private int order = Integer.MAX_VALUE; 
public int getOrder() { return this.order; }   
  public void setOrder(int order) { this.order = order; } 
    @Before("com.apress.springbook.chapter04.aspects." + 
        "TennisMatchEventsAspect.atMatchStart()")   
    public void printHowExcitedWeAre() { 
      System.out.println("Hurray for another tennis match!"); 
    } 
  } 
Listing 4-19. Aspect That Doesn't Implement the Ordered Interface
package com.apress.springbook.chapter04.aspects;  

import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.Before; 


@Aspect 
public class AnnoyedMessagePrintingAspect { 
  @Before("com.apress.springbook.chapter04.aspects." + 
    "TennisMatchEventsAspect.atMatchStart()")   
  public void printHowAnnoyedWeAre() { 
    System.out.println("Leave it out! Another tennis match!?"); 
  } 
} 
Next, we load these two aspects in the Spring container, as shown in Listing 4-20.

Listing 4-20. Configuring the Two Aspects for Loading by the Spring Container

<beans> 
  <bean class="org.springframework.aop.aspectj.annotation. --> 
AnnotationAwareAspectJAutoProxyCreator"/> 

  <bean class="com.apress.springbook.chapter04.aspects.HappyMessagePrintingAspect"/> 

  <bean class="com.apress.springbook.chapter04.aspects. --> 
AnnoyedMessagePrintingAspect"/> 

  <bean id="tournamentMatchManager" 
    class="com.apress.springbook.chapter04.DefaultTournamentMatchManager"> 
    <!-- properties omitted --> 
  </bean> 
</beans> 
When we call the startMatch() method on the tournamentMatchManager bean, the following messages will be printed to the console:

Hurray for another tennis match! Leave it out! Another tennis match!?

We get this order of messages because the HappyMessagePrintingAspect implements the Ordered interface and the AnnoyedMessagePrintingAspect doesn't.

Because we have implemented the setOrder() method in HappyMessagePrintingAspect, we can change the order value via the bean definition, as follows:

<bean class="com.apress.springbook.chapter04.aspects.HappyMessagePrintingAspect"/> <property name="order" value="20"/> </bean> Although we can control the order of aspects and thus their advices, the order of declaration for advices within individual aspects remains.

So far, we've discussed only @AspectJ-style aspects in this chapter, but there is an alternative, which we'll cover next.

Using AOP XML Tags

The Spring developers have come up with a way to define aspects in XML by creating an AOP XML Schema for the Spring 2.0 custom XML Schema support. It allows you to turn any public instance methods on beans created by the Spring container into advice methods. These methods are comparable to the methods annotated with @Aspect in @AspectJ-style aspects.

@AspectJ-style aspects use Java 5 annotations, so they are not an option when Java 5 is not used in the production environment (many organizations still use Java 1.4). Also, you may want to use methods on existing classes as advice methods.

This section explains how to create aspects in XML, which solves these problems. We will also show how you can replace the pointcut classes covered in the previous chapter with the AspectJ pointcuts discussed in this chapter.

As you will notice, XML aspects and advice declarations are straightforward to understand and work with when you're familiar with @AspectJ-style aspects. You may also notice that with XML declarations, the advice type and pointcut are separated from the advice method (which some see as a disadvantage because it splits a unit of functionality). For this reason, we recommend that you to write aspects with the @AspectJ-style when possible.

AOP Configuration Tags

The first step to using the AOP XML tags for declaring aspects, pointcuts, and advisors is to create a Spring XML file, as shown in Listing 4-21.

Listing 4-21. A Spring XML Configuration File Based on Spring 2.0 XML Schemas

<?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.xsd 
              http://www.springframework.org/schema/aop 
              http://www.springframework.org/schema/aop/spring-aop.xsd"> 
</beans> 
You can load this file, together with other, classic, Spring XML configuration files, into the Spring container. To declare aspects and advisors in XML, add the <aop:config> tag to the XML file, as shown in Listing 4-22.

Listing 4-22. Creating an AOP Configuration Unit in XML with the aop:config Tag

<?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.xsd 
              http://www.springframework.org/schema/aop 
              http://www.springframework.org/schema/aop/spring-aop.xsd"> 

    <aop:config> 

    </aop:config> 

</beans> 
You can declare multiple <aop:config> tags in one or multiple XML files. The <aop:config> tag can contain zero or more of the following tags:
  • <aop:aspect>: Allows you to create aspects in XML that are comparable to @AspectJ-style aspects.
  • <aop:advisor>: Allows you to create an advisor object with an AspectJ pointcut and a classic Spring AOP advice object.
  • <aop:pointcut>: Allows you to declare and reuse pointcuts in XML aspects.
We'll cover these tags in more detail as we work through our next example. Now we'll re-create the @AspectJ-style aspect from Listing 4-3 in XML.

XML Aspect Configuration

The @AspectJ-style concepts we've discussed in the chapter also apply to aspects declared in XML.

The only difference is the use of XML instead of annotations.

The first step for creating an aspect with XML is to add the <aop:aspect> tag to <aop:config>, as shown in Listing 4-23.

Listing 4-23. xml-aspect-context.xml: Creating an Empty XML Aspect

<?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.xsd 
              http://www.springframework.org/schema/aop 
              http://www.springframework.org /schema/aop/spring-aop.xsd"> 

  <aop:config> 

    <aop:aspect ref="messagePrinter"> 

    </aop:aspect> 
  </aop:config> 

  <bean id="messagePrinter" 
    class="com.apress.springbook.chapter04.MessagePrinter"/> 

  <bean id="tournamentMatchManager" 
      class="com.apress.springbook.chapter04.DefaultTournamentMatchManager"> 
      <!-- properties omitted --> 
  </bean> 
</beans> 
The <aop:aspect> tag takes a ref attribute that holds the name of a bean definition (messagePrinter). Listing 4-24 shows the MessagePrinter class.

Listing 4-24. The MessagePrinter Class

package com.apress.springbook.chapter04; 

public class MessagePrinter { 
  public (.*?) { 
      System.out.println("Attempting to start tennis match!"); 
  } 
} 
The MessagePrinter class is comparable to the MessagePrintingAspect in Listing 4-3, but without the @AspectJ-style annotations. So MessagePrinter is a regular Java class and not an aspect declaration.

But we've configured MessagePrinter in a bean definition in Listing 4-23, and we've let the <aop:aspect> tag refer to the messagePrinter bean definition. This configuration declares the messagePrinter bean as an aspect, not the MessagePrinter class. We've also added the tournamentMatchManager bean to the configuration in Listing 4-23.

So far, this aspect configuration won't do anything out of the ordinary. However, we can add more configuration to the <aop:aspect> tag to turn the printMessageToInformMatchStarts() method on the messagePrinter bean into an advice method, as shown in Listing 4-25.

Listing 4-25. xml-aspect-context.xml: Turning the printMessageToInformMatchStarts() method on the messagePrinter Bean into an Advice Method

<?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.xsd 
              http://www.springframework.org/schema/aop 
              http://www.springframework.org/schema/aop/spring-aop.xsd"> 

  <aop:config> 
    <aop:aspect ref="messagePrinter"> 

      <aop:before method="printMessageToInformMatchStarts" 
            pointcut="execution(* startMatch(..))"/> 
      </aop:aspect> 
    </aop:config> 

  <bean id="messagePrinter" 
      class="com.apress.springbook.chapter04.MessagePrinter"/> 

  <bean id="tournamentMatchManager" 
        class="com.apress.springbook.chapter04.DefaultTournamentMatchManager"> 
    <!-- properties omitted --> 
  </bean> 
</beans> 

That's it—we've created the XML aspect. The <aop:before> tag declares that the printMessageToInformMatchStarts() method on the messagePrinter bean becomes before advice and also declares the pointcut.

Let's run through the configuration in Listing 4-25 to look at all elements and their roles.

  • The <aop:config> tag activates auto-proxy creation in the Spring container. It also holds the configuration for one or more XML aspect, pointcut, or advisor declarations.
  • The <aop:aspect> tag refers to the messagePrinter bean and declares that bean as an aspect.

    This bean itself is not touched or affected in any way. In fact, the messagePrinter bean is not aware that it's being declared as an aspect. This tag by itself won't trigger the creation of proxy objects during auto-proxy creation. The tag only declares an aspect that can hold zero or more pointcut and advice/pointcut declarations in XML.

  • The <aop:before> tag is an advice/pointcut declaration that will execute the printMessageToInformMatchStarts() method on the messagePrinter bean for the execution of all join points that are matched by the pointcut.
  • The messagePrinter bean is an ordinary bean created and configured based on an ordinary bean definition by the Spring container. It is not aware of Spring AOP, advice, auto-proxy creation, or pointcuts. In fact, you can get this bean and execute its methods, and you'll find they will respond as expected.
  • The tournamentMatchManager bean is affected by auto-proxy creation during its bean life cycle since it has one join point—the startMatch() method—that is matched by the pointcut in the XML aspect declaration. When its startMatch() method is executed, the printMessageToInformMatchStarts() method on the messagePrinter bean will be executed first.

    Next, we'll load xml-aspect-context.xml into a test case to verify the tournamentMatchManager bean is proxied correctly. The test case in Listing 4-26 shows MessagePrintingXmlAspectIntegration Tests, which extends MessagePrintingAspectIntegrationTests from Listing 4-6.

    Listing 4-26. Test Case to Verify the XML Aspect Works As Expected

    package com.apress.springbook.chapter04; 
    
    public class MessagePrintingXmlAspectIntegrationTests extends 
    MessagePrintingAspectIntegrationTests { 
    protected String[] getConfigLocations() { 
      return new String[] { 
         "classpath:com/apress/springbook/chapter04/" + 
         "xml-aspect-context.xml" 
       }; 
      } 
    } 
    
    The test case in Listing 4-26 runs the test methods declared in Listing 4-6 and overwrites the getConfigLocations() method to load the Spring XML file in Listing 4-25. The following messages shown are printed to the console when the test runs:
    === GOING TO CALL METHOD ON BEAN FROM CONTAINER === 
    Attempting to start tennis match! 
    === FINISHED CALLING METHOD ON BEAN FROM CONTAINER === 
    === GOING TO CALL METHOD ON NEWLY CREATED OBJECT === 
    === FINISHED CALLING METHOD ON NEWLY CREATED OBJECT === 
    

    Pointcut Declaration and Reuse with XML

    You can declare and reuse pointcuts in the AOP XML configuration, and you can reuse pointcuts declared in @AspectJ-style aspects. Listing 4-27 reuses the pointcut declared in the SystemPointcutsAspect (Listing 4-11). The SecurityEnforcer class is the same as the SecurityAspect class, but has been stripped of its aspect status.

    Listing 4-27. Reusing a Pointcut Declared in an @AspectJ-Style Aspect

    <?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.xsd 
                  http://www.springframework.org/schema/aop 
                  http://www.springframework.org/schema/aop/spring-aop.xsd"> 
    
      <aop:config> 
        <aop:aspect ref="securityEnforcer"> 
          <aop:before method="denyAccessToAll" 
                     pointcut="com.apress.springbook.chapter04.aspects. --> 
          SystemPointcutsAspect.inServiceLayer()"/> 
    </aop:aspect> 
    </aop:config> 
    
      <bean id="securityEnforcer" 
        class="com.apress.springbook.chapter04.SecurityEnforcer"/> 
    </beans> 
    
    You can also declare pointcuts in XML, and you can declare them in two places. The first option is shown in Listing 4-28, which declares a pointcut inside the <aop:aspect> tag. This pointcut can be reused only inside this aspect.

    Listing 4-28. Declaring and Reusing a Pointcut in an XML Aspect

    <?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.xsd 
                  http://www.springframework.org/schema/aop 
                  http://www.springframework.org/schema/aop/spring-aop.xsd"> 
    
      <aop:config> 
        <aop:aspect ref="securityEnforcer"> 
          <aop:pointcut id="inServiceLayer" 
                    expression="within(com.apress.springbook.chapter04..*)"/> 
          <aop:before method="denyAccessToAll" 
                    pointcut-ref="inServiceLayer"/> 
        </aop:aspect> 
      </aop:config> 
    
      <bean id="securityEnforcer" 
        class="com.apress.springbook.chapter04.SecurityEnforcer"/> 
    </beans> 
    

    The <aop:pointcut> tag declares a pointcut and takes a name (id) and pointcut expression (expression). This pointcut is then reused by the <aop:before> tag (pointcut-ref).

    Listing 4-29 shows a pointcut that is declared inside the <aop:config> tag. This pointcut can be reused inside <aop:aspect> tags in this and other Spring XML files.

    Listing 4-29. Declaring a Pointcut Outside an Aspect and Reusing It Inside an XML Aspect

    <?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.xsd 
                  http://www.springframework.org/schema/aop 
                  http://www.springframework.org /schema/aop/spring-aop.xsd"> 
    
      <aop:config> 
        <aop:pointcut id="inServiceLayer" 
    expression="within(com.apress.springbook.chapter04..*)"/> 
    <aop:aspect ref="securityEnforcer"> 
    <aop:before method="denyAccessToAll" 
    pointcut-ref="inServiceLayer"/> 
    </aop:aspect> 
    </aop:config> 
    
      <bean id="securityEnforcer" 
        class="com.apress.springbook.chapter04.SecurityEnforcer"/> 
    </beans> 
    
    Pointcuts declared in XML have certain limitations, in that they cannot be reused in @AspectJ-style aspects. Also, they cannot take dynamic pointcut designators such as args() and @annotation() (pointcut designators are discussed in the "Working with Pointcuts" section later in this chapter). The reason has to do with the fact that pointcut declarations are not coupled to a method, as they are in @AspectJ-style aspects.

    Advice Declaration in XML

    The aspects that are declared in XML support the same advice types as @AspectJ-style aspects with exactly the same semantics. As explained in the previous section, advice declarations in XML use regular Java methods on an object as advice methods.

    Now we'll look at how to declare each of the different advice types in XML. Later, in the "Binding Advice Arguments" section, we'll rewrite the aspects we've used to explain how to bind advice arguments on @AspectJ-style advice methods and show the equivalent XML, so that you can easily compare the two.

    Listing 4-30 shows an example for a before advice XML declaration. Listing 4-30. Before Advice Declaration in XML

    <?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.xsd 
                  http://www.springframework.org/schema/aop 
                  http://www.springframework.org /schema/aop/spring-aop.xsd"> 
    
    
    
      <aop:config> 
        <aop:aspect ref="messagePrinter"> 
    <aop:before method="printMessageToInformMatchStarts" 
    pointcut="execution(* startMatch(..))"/> 
    </aop:aspect> 
    </aop:config> 
    
      <bean id="messagePrinter" 
        class="com.apress.springbook.chapter04.MessagePrinter"/> 
    
      <bean id="tournamentMatchManager" 
        class="com.apress.springbook.chapter04.DefaultTournamentMatchManager"> 
        <!-- properties omitted --> 
      </bean> 
    </beans> 
    
    Listing 4-31 shows an example of using after returning advice.

    Listing 4-31. After Returning Advice Declared in XML

    <?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.xsd 
                  http://www.springframework.org/schema/aop 
                  http://www.springframework.org/schema/aop/spring-aop.xsd"> 
    
      <aop:config> 
        <aop:aspect ref="messagePrinter"> 
    <aop:after-returning method="printMessageToInformMatchHasStarted" 
    pointcut="execution(* startMatch(..))"/> 
    </aop:aspect> 
    </aop:config> 
    
      <bean id="messagePrinter" 
        class="com.apress.springbook.chapter04.MessagePrinter"/> 
    
      <bean id="tournamentMatchManager" 
        class="com.apress.springbook.chapter04.DefaultTournamentMatchManager"> 
    <!-- properties omsitted --> 
    </bean> 
    </beans> 
    
    Declaring after throwing advice in XML is equally straightforward, as shown in Listing 4-32.

    Listing 4-32. After Throwing Advice Declared in XML

    <?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.xsd 
                  http://www.springframework.org/schema/aop 
                  http://www.springframework.org /schema/aop/spring-aop.xsd"> 
    
    
    
    
    
      <aop:config> 
        <aop:aspect ref="messagePrinter"> 
    <aop:after-throwing method="printMessageWhenMatchIdentifierIsNotFound" 
    pointcut="execution(* startMatch(..) throws --> 
    com.apress.springbook.chapter04.UnknownMatchException)"/> 
    </aop:aspect> 
    </aop:config> 
    
      <bean id="messagePrinter" 
        class="com.apress.springbook.chapter04.MessagePrinter"/> 
    
      <bean id="tournamentMatchManager" 
        class="com.apress.springbook.chapter04.DefaultTournamentMatchManager"> 
        <!-- properties omitted --> 
      </bean> 
    </beans> 
    
    
    In the after (finally) advice example shown in Listing 4-33, we again use a pointcut to match the startMatch() method. Listing 4-33. After (Finally) Advice Declared in XML
    <?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.xsd 
                  http://www.springframework.org/schema/aop 
                  http://www.springframework.org /schema/aop/spring-aop.xsd"> 
    
      <aop:config> 
        <aop:aspect ref="messagePrinter"> 
    <aop:after method="printMessageWhenStartMatchAttemptIsOver" 
    pointcut="execution(* startMatch(..))"/> 
    </aop:aspect> 
    </aop:config> 
    
      <bean id="messagePrinter" 
        class="com.apress.springbook.chapter04.MessagePrinter"/> 
    
      <bean id="tournamentMatchManager" 
        class="com.apress.springbook.chapter04.DefaultTournamentMatchManager"> 
        <!-- properties omitted --> 
      </bean> 
    </beans> 
    
    The code in Listing 4-34 shows the printMessageWhenStartMatchAttemptIsOver() method on MessagePrinter.

    Listing 4-34. The printMessageWhenStartMatchAttemptIsOver() method on MessagePrinter

    package com.apress.springbook.chapter04; 
    
    public class MessagePrinter { 
      public (.*?) { 
          System.out.println("Tried to start a match and this attempt is now over!");    } 
    } 
    

    Again, there are no surprises since the after (finally) advice XML declaration is very similar to the @AspectJ-style declaration we've discussed previously.

    And last, but not least, is the around advice as an XML declaration. As you may suspect, this advice type requires the declaration of a ProceedingJoinPoint argument in the advice method. This binds the MessagePrinter class to the AspectJ API. Listing 4-35 shows an around advice declaration in XML.

    Listing 4-35. Around Advice Declared in XML

    <?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=&q