Java and Spring development

Declaratively add enterprise functionality

with one comment

The goal with this tutorial is to explain how you can add enterprise functionality declaratively and how an application container does it.

Enterprise functionality like transaction handling and security are often handled by an application container. I will demonstrate how to add transactional handling with the Decorator pattern, an interceptor (AspectJ) and an interceptor configured with the Spring framework. All the alternatives works without adding boilerplate transaction logic to the business classes.

The decorator pattern can add behaviour to your business implementation without polluting the business implementation. The limitation with the decorator pattern compared to an interceptor is that the decorator must implement your business class’ interface. An interceptor implemented with the AspectJ technology modifies the class either at compile or load-time. A general practice is to add business functionality with decorators, while you add enterprise functionality like transaction handling and security logic with interceptors.

Example case for this tutorial

This tutorial consist of four examples all using the interfaces on the image below with transaction logic around the transferAmount(..) method. The sequence diagram illustrates a successful transaction that will be commited.

Transfer amount sequence diagram

The other case demonstrated is when the credit method fails. Then the amount transferred from the debit account must be cancelled with a roll back. The roll back is triggered with a RuntimeException. This is the default way with EJB as well as the lightweight containers like Spring and Google Juice.

All the examples except the last one uses stub implementations for the repository and the transaction logic. The last example with Spring uses an embedded database and a JDBC transaction manager.

Transaction handling with the decorator pattern

This decorator example consist of the interfaces on the sequence diagram above as well as implementations of them and a transaction decorator that also implements the AccountService.

The business interface:

public interface AccountService {

	public boolean transferAmount(final Amount amount, final Account debetAccount,
             final Account creditAccount);
}

The transferAmount() method in the business implementation:

@Transactional
public boolean transferAmount(final Amount amount,
		final Account debetAccount, final Account creditAccount) {
	final boolean transferred;

	final Amount debetAccountBalance = accountRepository
			.getBalance(debetAccount);

	logger.debug("Balance on debet account before transfer: {}", debetAccountBalance.getAmount());

	if (debetAccountBalance.isLargerThanOrEqualTo(amount)) {
		debetAmount(amount, debetAccount);
		creditAmount(amount, creditAccount);

		transferred = true;
		logger.debug("{} amount was transferred from {} to {}",
				new Object[] { amount, debetAccount, creditAccount });
	} else {
		transferred = false;
		logger.debug("The transfer amount: {} is higher than the balance available on the " +
                     "debet account", amount.getAmount());
	}

	return transferred;
}

The method doesn’t contain any transactional logic. Since this example doesn’t use any interceptors, the @Transactional annotation is ignored.

When I execute the method with sufficient balance on the debit account, the following line is printed to the log:

INFO  [com.redpill.linpro.service.impl.AccountServiceImpl] -

With the transaction decorator the output is:

DEBUG [com.redpill.linpro.service.impl.AccountTransactionDecorator] -
INFO  [com.redpill.linpro.service.impl.AccountServiceImpl] - <Amount [amount=50] was transferred from Account [accountNumber=1] to Account [accountNumber=2]>
DEBUG [com.redpill.linpro.service.impl.AccountTransactionDecorator] - <Commit transaction>

The transaction decorator stub implementation:

package com.redpill.linpro.service.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.redpill.linpro.integration.Account;
import com.redpill.linpro.integration.Amount;
import com.redpill.linpro.service.AccountService;

public class AccountTransactionDecorator implements AccountService {

	private final AccountService accountService;

	private final Logger logger = LoggerFactory.getLogger(AccountTransactionDecorator.class);

	private int commitCounter = 0;

	private int rollbackCounter = 0;

	public AccountTransactionDecorator(AccountService accountService) {
		this.accountService = accountService;
	}

	@Override
	public boolean transferAmount(Amount amount, Account debetAccount,
			Account creditAccount) {
		final boolean transferred;

		logger.debug("Begin transaction");

		try {
			transferred = accountService.transferAmount(amount, debetAccount, creditAccount);
			commitCounter++;
			logger.debug("Commit transaction");
		} catch (RuntimeException e) {
			rollbackCounter++;
			logger.debug("Rollback transaction");
			throw e;
		}
		return transferred;
	}

	public int getCommitCounter() {
		return commitCounter;
	}

	public int getRollbackCounter() {
		return rollbackCounter;
	}
}

The decorator must implement the business interface like the business implementation above. Then it must have a reference to the interface. This enables the decorator to call the next decorator/service recursively. The decorator doesn’t know if the reference to the interface is to the implementation or to another decorator. Only the factory method knows that. This enables loose coupling and the ability to add behaviour to your service with only a configuration change. The decorator adds behaviour before and after the service is executed. And if a RuntimeException is throwed back, it will be catched and a roll back will be simulated. With normal execution, the decorator will simulate a commit like you can see in the log message above.

An implementation that uses the decorator pattern, should also use the factory pattern. In this example the factory logic is in the constructor of the test class. The important part in this factory method is that the accountService instance points to the transaction decorator object. And that the transaction decorator is instantiated with a reference to the business implementation.

private final AccountService accountService;

public AccountServiceWithTransactionDecoratorTest() {
	accountRepositoryStub = new AccountRepositoryStub();

	// Basic service
	AccountService basicAccountService = new AccountServiceImpl(accountRepositoryStub);

	// Decorator
	accountTransactionDecorator = new AccountTransactionDecorator(basicAccountService);

	// The decorated service
	accountService = accountTransactionDecorator;
}

If the accountService instance had pointed to the business implementation instead of the decorator, then no transaction logic would have been executed.

The last part of this decorator example is the JUnit test. As you can see from the highlighted code, the test doesn’t know about the implementation or any decorators. It just executes the transferAmount() method on the accountService instance. And this instance is declared to be of the interface type.

@Test
public void testTransferAmount() {
	Amount amount = new Amount(50);
	Account debetAccount = new Account("1");
	Account creditAccount = new Account("2");

	boolean transferred = accountService.transferAmount(amount, debetAccount, creditAccount);

	assertTrue(transferred);
	assertEquals(1, accountTransactionDecorator.getCommitCounter());
}

Transaction handling with aspect

Spring Aspects supports Spring AOP (Dynamic Objects and CGLIB) and AspectJ. Both alternatives support the AspectJ syntax. AspectJ is more powerful while Spring AOP is easier to use together with the Spring container. In this interceptor example I will use AspectJ. This is because it also works without the Spring container. I’m using compile-time weaving for simplicity, since STS will do the weaving for me with the AJDT plugin and an AspectJ nature on the project.

An aspect doesn’t need to know anything about the class it will modify. All that’s necessary is to know the joinpoint where the extra functionality should be added. In this example the pointcut will be the @Transactional annotation which is showed here:

@Transactional
public boolean transferAmount(final Amount amount,
		final Account debetAccount, final Account creditAccount) { .. }

To enable AspectJ functionality with Java annotations, the @Aspect annotation must be above the class name with the AspectJ logic. Further, you have to declare the pointcut in a new annotation like this:

@Pointcut("execution(@org.springframework.transaction.annotation.Transactional * *(..))")
public void transactionalMethod() {}

A pointcut doesn’t add anything without advices. The three advises below supports the transaction handling example:

@Before("transactionalMethod()")
public void beforeTransactionalMethod(JoinPoint joinPoint) {
	transactionService.beginTransaction();
}

@AfterReturning("transactionalMethod()")
public void afterTransactionalMethod(JoinPoint joinPoint) {
	transactionService.commit();
}

@AfterThrowing(pointcut = "transactionalMethod()")
public void afterThrowingFromTransactionalMethod(JoinPoint joinPoint) {
	transactionService.rollback();
}

All the advises delegates to an instance of TransactionService. The last advice doesn’t swallow the exception, but throws it further after the rollback functionality is executed. The link below shows the TransactionAspect:

package com.redpill.linpro.transaction;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

import com.redpill.linpro.transaction.impl.TransactionServiceNull;

@Aspect
public class TransactionAspect {

	private TransactionService transactionService = new TransactionServiceNull();

	@Pointcut("execution(@org.springframework.transaction.annotation.Transactional * *(..))")
	public void transactionalMethod() {}

	@Before("transactionalMethod()")
	public void beforeTransactionalMethod(JoinPoint joinPoint) {
		transactionService.beginTransaction();
	}

	@AfterReturning("transactionalMethod()")
	public void afterTransactionalMethod(JoinPoint joinPoint) {
		transactionService.commit();
	}

	@AfterThrowing(pointcut = "transactionalMethod()", throwing = "e")
	public void afterThrowingFromTransactionalMethod(JoinPoint joinPoint, RuntimeException e) {
		transactionService.rollback();
	}

	public void setTransactionService(final TransactionService transactionService) {
		this.transactionService = transactionService;
	}
}

If you have enabled AspectJ nature on the Eclipse project, then you should see an orange arrow to the left of the transferAmount(..) method name.

transfer-amount-ajdt-support

In the factory method in the JUnit test, the difference between this method and the decorator test is that the accountService instance doesn’t know about the aspect and the aspect doesn’t know about the AccountService implementation. In this case, the transaction logic will be weaved in at compile-time with the AspectJ compiler.

public AccountServiceWithTransactionAspectTest() {
	accountRepositoryStub = new AccountRepositoryStub();

	accountService = new AccountServiceImpl(accountRepositoryStub);

	transactionServiceStub = new TransactionServiceStub();
	TransactionAspect transactionAspect = Aspects.aspectOf(TransactionAspect.class);
	transactionAspect.setTransactionService(transactionServiceStub);
}

The test class consist of two test methods. The first test method asserts that the normal flow works and the output from the log can be seen here:

DEBUG [com.redpill.linpro.transaction.impl.TransactionServiceStub] - <Begin transaction>
INFO  [com.redpill.linpro.service.impl.AccountServiceImpl] - <Amount [amount=50] was transferred from Account [accountNumber=1] to Account [accountNumber=2]>
DEBUG [com.redpill.linpro.transaction.impl.TransactionServiceStub] - <Commit transaction>

The other test try to transfer to an invalid account which should cause an exception. The after throwing advice should roll back the transaction which the log indicates:

DEBUG [com.redpill.linpro.transaction.impl.TransactionServiceStub] - <Begin transaction>
DEBUG [com.redpill.linpro.transaction.impl.TransactionServiceStub] - <Rollback transaction>

Transaction handling with Spring

With Spring it’s possible to add declarative transaction handling with Spring AOP and AspectJ. This example will use the default Spring AOP, since it’s the simplest and most used alternative.

The default way to add transaction support with Spring and Java 5 or better is to annotate the transactional methods with @Transactional. This alternative requires the element in the configuration. It’s higlighted below. This element requires a transaction manager that implements Spring’s PlatformTransactionManager interface. The example uses just a stub implementation. The component-scan elements below finds all the Spring beans annotated with a specialization of the @Component annotation.

<context:component-scan base-package="com.redpill.linpro.service" />
<context:component-scan base-package="com.redpill.linpro.integration.stub" />

<tx:annotation-driven />

<bean id="transactionManager" class="com.redpill.linpro.transaction.impl.PlatformTransactionManagerStub" />

The most used implementations of the PlatformTransactionManager is DataSourceTransactionManager for JDBC, JpaTransactionManager, HibernateTransactionManager and JtaTransactionManager. The stub implementation used in this example just counts and logs every time a method in the interface are executed. Below are the overriden interface methods in the stub implementation:

@Repository
public class PlatformTransactionManagerStub implements PlatformTransactionManager {

	@Override
	public void commit(TransactionStatus status) throws TransactionException {
		commitTransactionCounter++;
		logger.debug("Commit transaction");
	}

	@Override
	public TransactionStatus getTransaction(TransactionDefinition definition)
                        throws TransactionException {
		beginTransactionCounter++;
		logger.debug("Begin transaction");
		return new SimpleTransactionStatus();
	}

	@Override
	public void rollback(TransactionStatus status) throws TransactionException {
		rollbackTransactionCounter++;
		logger.debug("Rollback transaction");
	}
}

The test below demonstrates how to instantiate the Spring container with annotations and how to inject Spring beans into class variables. Further it executes the transferAmount(..) method on the accountService instance. This instance is of AccountServiceImpl type because the component-scan element in the configuration found the @Service annotation above that class and the class implements the AccountService interface. It doesn’t know about any aspects. And in this case with Spring AOP, the transaction logic will be added at runtime. No extra compiler or JVM agent is required.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("stub-config.xml")
public class AccountServiceWithTransactionManagerStubTest {

@Inject
private AccountService accountService;

@Inject
private PlatformTransactionManagerStub platformTransactionManagerStub;

@Test
public void testTransferAmount() {
Amount amount = new Amount(50);
Account debitAccount = new Account("1");
Account creditAccount = new Account("2");

boolean transferred = accountService.transferAmount(amount, debitAccount, creditAccount);

assertTrue(transferred);
assertEquals(1, platformTransactionManagerStub.getBeginTransactionCounter());
assertEquals(0, platformTransactionManagerStub.getRollbackTransactionCounter());
assertEquals(1, platformTransactionManagerStub.getCommitTransactionCounter());
}

@Test
public void testTransferAmountThatShouldRollback() {..}
}

The test prints the following to the log:

DEBUG [com.redpill.linpro.transaction.impl.PlatformTransactionManagerStub] - <Begin transaction>
INFO  [com.redpill.linpro.service.impl.AccountServiceImpl] - <Amount [amount=50] was transferred from Account [accountNumber=1] to Account [accountNumber=2]>
DEBUG [com.redpill.linpro.transaction.impl.PlatformTransactionManagerStub] - <Commit transaction>

Transaction handling with Spring and database

In all the examples so far in this tutorial, I have used stub implementations for the transaction handling and only simulated a repository with another stub. In this last example, I will use plain JDBC against HSQL database and a DataSourceTransactionManager.

First, the respository stub is replaced with this:

@Repository
public class AccountRepositoryImpl implements AccountRepository {

	@Inject
	private SimpleJdbcTemplate jdbcTemplate;

	private final String GET_BALANCE_SQL =
                "select BALANCE from ACCOUNT where ACCOUNT_NUMBER = ?";

	private final String UPDATE_AMOUNT_SQL =
                "update ACCOUNT set BALANCE = BALANCE + ? where ACCOUNT_NUMBER = ?";

	private final String VALIDATE_ACCOUNT_EXIST_SQL =
                "select count(*) from ACCOUNT where ACCOUNT_NUMBER = ?";

	@Override
	public Amount getBalance(Account account) {
		int balance = jdbcTemplate.queryForInt(GET_BALANCE_SQL, account.getAccountNumber());
		return new Amount(balance);
	}

	@Override
	public void updateBalance(Amount balance, Account account) {
		jdbcTemplate.update(UPDATE_AMOUNT_SQL, balance.getAmount(), account.getAccountNumber());
	}

	public boolean isAccountExisting(final Account account) {
		int accountsWithAccountNumber = jdbcTemplate.queryForInt(VALIDATE_ACCOUNT_EXIST_SQL,
                         account.getAccountNumber());
		return (accountsWithAccountNumber == 1 ? true : false);
	}
}

Second, the configuration must contain a DataSourceTransactionManager, a data source and the AccountRepository implementation above.

<context:component-scan base-package="com.redpill.linpro.service" />
<context:component-scan base-package="com.redpill.linpro.integration.db" />

<tx:annotation-driven />

<bean id="transactionManager"
	class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource" />
</bean>

jdbc.core.simple.SimpleJdbcTemplate">
	<constructor-arg ref="dataSource" />
</bean>

<jdbc:embedded-database id="dataSource" type="HSQL">
 	<jdbc:script location="classpath:com/redpill/linpro/integration/db/schema.sql"/>
 	<jdbc:script location="classpath:com/redpill/linpro/integration/db/data.sql"/>
 </jdbc:embedded-database>

The test below asserts that the balance on the debit account is the same after the roll back as it was before the transaction

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"config.xml", "../integration/db/database-config.xml"})
public class AccountServiceWithSpringTest {

	@Inject
	private AccountService accountService;

	@Inject
	private AccountRepository accountRepository;

	@Test
	public void testTransfer() {..}

	@Test
	public void testTransferWithInvalidCreditAccount() {
		Amount amount = new Amount(100);
		Account debetAccount = new Account("789");
		Account creditAccount = new Account("INVALID");

		try {
			accountService.transferAmount(amount, debetAccount, creditAccount);
			fail("transferAmount() should have throwed exception.");
		} catch (IllegalArgumentException e) {
			Amount debetBalanceAfterTransfer = accountRepository.getBalance(debetAccount);
			assertEquals(new Amount(100), debetBalanceAfterTransfer);
		}
	}
}

Summary

The Decorator pattern and aspect technologies enables enterprise functionality without an application container and boilerplate code in your business logic.The simplest solution if you’re already are familiar with an application container is to delegate the enterprise functionality to the container like the last two examples in this tutorial.

The coded used in this article was developed in my work time at Redpill Linpro. It can be downloaded from: http://samplecode-espenberntsen.googlecode.com/svn/enterprise.functionality/trunk/


Redpill Linpro is the leading provider of Professional Open Source services and products in the Nordic region.

Written by Espen

April 1, 2010 at 15:21

@AspectJ cheat sheet

with 22 comments

This cheat sheet uses AspectJ’s @AspectJ style. It’s also possible to use the original AspectJ syntax like this example demonstrates, but I prefer to use standard Java classes with the AspectJ logic inside annotations.

Pointcuts

The definition of a pointcut from the AspectJ homepage:

A pointcut is a program element that picks out join points and exposes data from the execution context of those join points. Pointcuts are used primarily by advice. They can be composed with boolean operators to build up other pointcuts.

A pointcut example:

Pointcut designators

A method pointcut:

@Pointcut("[method designator](* aspects.trace.demo.*.*(..))")
public void traceMethodsInDemoPackage() {}
  • call – The pointcut will find all methods that calls a method in the demo package.
  • execution – The pointcut will find all methods in the demo package.
  • withincode – All the statements inside the methods in the demo package.

A type pointcut:

@Pointcut("[type designator](*..*Test)")
public void inTestClass() {}
  • within – all statements inside the a class that ends with Test.

A field pointcut:

@Pointcut("[field designator](private org.springframework.jdbc.core.JdbcTemplate " +
       "integration.db.*.jdbcTemplate)")
public void jdbcTemplateGetField() {}
  • get – all reads to jdbcTemplate fields of type JdbcTemplate in the integration.db package. Includes all methods on this field if it’s an object.
  • set – when you set the jdbcTemplate field of type JdbcTemplate in the integration.db package to a new value.

Signature pointcuts

This chapter explains more advanced signature pointcuts than illustrated on the image above.

Support for sub packages is provided with “..”:

@Pointcut("within(*..*Test)")
public void inTestClass() {}

To find the joinpoints inside a type that ends with Test inside the ..demo package:

@Pointcut("within(com.redpill.linpro.demo..*Test)")
public void inDemoProjectTestClass() {}

All statements inside all classes except test classes in the ..demo package with the “!” before the designator:

@Pointcut("!within(com.redpill.linpro.demo..*Test)")
public void notInDemoProjectTestClass() {}

All methods in the Service class or a subtype of it:

@Pointcut("execution(void *..service.Service+.*(..))")
public void servicePointcut() {}

All getCoffeeType methods in a class that begins with CoffeeTypeRepository:

@Pointcut("execution(CoffeeType integration.db.CoffeeTypeRepository*.getCoffeeType(CoffeeTypeName))" +
    " && args(coffeeTypeName)")
public void getCoffeeTypePointcut(CoffeeTypeName coffeeTypeName) {}

Note that the pointcut also contains args(coffeeTypeName) and that the Java method has a method with a CoffeeTypeName as input parameter. An advice that advices this pointcut must also have this input parameter.

This field pointcut finds all the places in the integration package where a field named jdbcTemplate gets a new value of type JdbcOperations or a subtype of it like JdbTemplate.

@Pointcut("set(private org.springframework.jdbc.core.JdbcOperations+ " +
    "integration..*.jdbcTemplate)")
public void jdbcTemplateSetField() {}

Annotation pointcuts

A pointcut can declare an annotation before the signature pattern.

An example of an annotation used as a marker interface:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PerformanceLogable {}

All it does is to provide meta information to methods.

A pointcut that finds all methods marked with the @PerformanceLogable on the classpath:

@Pointcut("execution(@aspects.log.performance.PerformanceLogable * *(..))")
public void performanceLogableMethod() {}

The @Transactional annotation supports both method and type target. Which means it can be used with both method and type designators. The pointcut below is the same as the performanceLogableMethod pointcut, except it finds methods with Spring’s @Transactional annotation.

@Pointcut("execution(@org.springframework.transaction.annotation.Transactional * *(..))")
public void transactionalMethod() {}

A pointcut that finds all constructors marked with @Inject and have an integer as input parameter:

@Pointcut("execution(@javax.inject.Inject *.new(Integer)) && args(integer)")
public void constructorAnnotatedWithInjectAndIndemoPackage(Integer integer) {}

The @Service annotation has target set to type and can therefore only annotate types. The pointcut below will find all statements in all types marked with @Service.

@Pointcut("within(@org.springframework.stereotype.Service *)")
public void serviceBean() {}

The joinpoint will be all statements inside a type marked with the @Component annotation or a specialization of it:

@Pointcut("within(@(@org.springframework.stereotype.Component *) *)")
public void beanAnnotatedWithComponentOrASpecializationOfIt() {}

Finds all statements that’s not inside a method marked with @Test:

@Pointcut("!withincode(@org.junit.Test * *(..))")
public void notInTestMethod() {}

Finds all methods with one or more parameters marked with the @MyParamAnnotation:

@Pointcut("execution(public * *(.., @aspects.MyParamAnnotation (*), ..))")
public void methodWithAnnotationOnAtLeastOneParameter() {}

For a full example with explanations, see this post.

A pointcut with a runtime condition and a required public static method:

@Pointcut("execution(* *.actionPerformed(java.awt.event.ActionEvent)) " +
		"&& args(actionEvent) && if()")
public static boolean button1Pointcut(ActionEvent actionEvent) {
	return (actionEvent.getSource() == j1);
}

More information can be found in this post

Combining pointcuts

Instead of having a large pointcut, it’s a much better approach to combine several pointcuts into one.

@Pointcut("traceMethodsInDemoPackage() && notInTestClass() && notSetMethodsInTraceDemoPackage()")
public void filteredTraceMethodsInDemoPackage() {}

Advices

The definition from the AspectJ homepage:

A piece of advice brings together a pointcut and a body of code to define aspect implementation that runs at join points picked out by the pointcut.

An advice can be executed before, after, after returning, after throwing or around the joinpoint.

The before advice below is executed before the target method specified in filteredTraceMethodsInDemoPackage pointcut:

@Before("filteredTraceMethodsInDemoPackage()")
public void beforeTraceMethods(JoinPoint joinPoint) {
	// trace logic ..
}

This after advice is executed after the target method.

@After("filteredTraceMethodsInDemoPackage()")
public void afterTraceMethods(JoinPoint joinPoint) {
	// trace logic ..
}

The afterThrowing advice will be executed if the method that matches the pointcut throws an exception. You can also declare the Exception and handle it like this:

@AfterThrowing(value="serviceMethodAfterExpcetionFromIntegrationLayerPointcut()", throwing="e")
public void serviceMethodAfterExceptionFromIntegrationLayer(JoinPoint joinPoint,
                RuntimeException e) {
	StringBuilder arguments = generateArgumentsString(joinPoint.getArgs());

	logger.error("Error in service " + joinPoint.getSignature() + " with the arguments: " +
			arguments, e);
}

The AfterReturning advice will only be executed if the adviced method returns successfully.

@AfterReturning("transactionalMethod()")
public void afterTransactionalMethod(JoinPoint joinPoint) {
	transactionService.commit();
}

The around advice is quite powerful, but also consumes more resources and should only be used if you can’t make it work with other advices. The example below simulates some logic before and after the adviced method. The ProceedingJoinPoint extends the JoinPoint class and is required to call the adviced method with the proceed() method.

@Around("performanceLogablePointcut()")
public void aroundPerformanceLogableMethod(ProceedingJoinPoint point) {

    // Pre processing work..

    point.proceed();

    // Post processing work..
}

Note: You don’t need an around advice to monitor the execution time for a method. It’s just the simplest option and therefore used in this example.

The advice below combines two pointcuts and the last one has an integer object as input parameter. This requires the Java method to also have an integer parameter. It enables the advice logic to access the input parameter directly and in a type safe manner. A less elegant alternative is to access the parameter with the joinPoint’s getArgs() method.

@AfterReturning("beanAnnotatedWithComponentOrASpecializationOfIt() &&  " +
	"constructorAnnotatedWithInjectAndIndemoPackage(integer)")
public void afterReturningFromConstructorInSpringBeanWithIntegerParameter(
		JoinPoint joinPoint, Integer integer) {

	// Advice logic..
}

Summary

This cheat sheet consist of many simple pointcuts. Often you have to combine them to add value to your application. This example article combines pointcuts with a class marked with @Service and a constructor and method marked with @Inject. It also filters away the test method with the @Test annotation.

The code used in this article was developed in my work time at Redpill Linpro.


Redpill Linpro is the leading provider of Professional Open Source services and products in the Nordic region.

Written by Espen

March 20, 2010 at 18:28

Posted in Aspects

Tagged with , , ,