Before implementing AOP components, let us first implement logging by following these steps:
- The previous has already created some POJOs, so just copy the Employee model, the supporting DAO and service interfaces, and their corresponding implementation classes. Place all model classes in a new package, org.packt.aop.transaction.model.data, all DAO components in org.packt.aop.transaction.dao, and all services in org.packt.aop.transaction.service.
- Add the updated Log4J libraries to the pom.xml:
<dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
- Create the log4j.properties containing the needed configuration details such as the type of appenders to be used, message formats to be applied, and the location of the log file:
# LOG4J configuration log4j.rootLogger=INFO, Appender1, Appender2 log4j.appender.Appender1=org.apache.log4j.ConsoleAppender log4j.appender.Appender1.layout=org.apache.log4j.PatternLayout log4j.appender.Appender1.layout.ConversionPattern=%-7p %d [%t] %c %x - %m%n log4j.appender.Appender2=org.apache.log4j.FileAppender log4j.appender.Appender2.File=C:\logs\ch05.log log4j.appender.Appender2.layout=org.apache.log4j.PatternLayout log4j.appender.Appender2.layout.ConversionPattern=%-7p %d [%t] %c %x - %m%n
- Save this file in src/main/resources/ of your Maven project.
- To start with AOP, include in the repository the AspectJ plugin which is an AOP extension for implementing aspects:
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.10</version> <scope>runtime</scope> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjtools</artifactId> <version>1.8.10</version> </dependency>
- Create an @Aspect class inside the package org.packt.aop.transaction.core that will manage the logging concerns of EmployeeService. This class will cut across any EmployeeService method execution just to monitor the status of the service calls. This class must be injected as an @Component bean of the container:
import org.apache.log4j.Logger; @Component @Aspect public class EmployeeAspect { private Logger logger = Logger.getLogger(EmployeeAspect.class); @Before("execution(* org.packt.aop.transaction.service .impl.EmployeeServiceImpl.*(..))") public void logBeforeEmployeeTransactions( JoinPoint joinPoint){ logger.info("EmployeeAspect.logBeforeEmployeeTransactions() detected : " + joinPoint.getSignature().getName()); } @After("execution(* org.packt.aop.transaction.service .impl.EmployeeServiceImpl.*(..))") public void logAfterEmployeeTransactions( JoinPoint joinPoint) { logger.info("EmployeeAspect.logAfterEmployeeTransactions() detected : " + joinPoint.getSignature().getName()); } }
- The two methods inside the aspect class are called advices.
The logBeforeEmployeeTransactions() is a type of @Before advice which means its execution is triggered after any EmployeeServiceImpl method execution is encountered.
On the other hand, the logAfterEmployeeTransactions() is an @After advice which is called after any execution of the EmployeeServiceImpl advisced methods.
Both methods implement the needed logging concerns. The expressions inside @After and @Before advices are called Pointcuts, which tells the advices when to execute.
- Create more @Aspect classes that will cover specific service transactions such as EmployeeDeleteAspect, EmployeeInsertAspect, EmployeeReadAspect, and EmployeeUpdateAspect. The following is an implementation of EmployeeUpdateAspect, which highlights the args() expression used to capture the arguments of the adviced updateEmployee() method. The args() is also part of the Pointcut expression:
@Component @Aspect public class EmployeeUpdateAspect { private Logger logger = Logger.getLogger(EmployeeUpdateAspect.class); @Before("execution(* org.packt.aop.transaction.service .impl.EmployeeServiceImpl.updateEmployee(..)) && args(empForm, id)") public void logBeforeUpdateEmp(JoinPoint joinPoint, EmployeeForm empForm, int id) { // refer to sources } @After("execution(* org.packt.aop.transaction.service .impl.EmployeeServiceImpl.updateEmployee(..)) && args(empForm, id)") public void logAfterUpdateEmp(JoinPoint joinPoint, EmployeeForm empForm, int id) { // refer to sources } }
If the adviced method has no arguments, avoid using args() because it will lead to compiler errors or non-execution of the Aspect class. Keyword args() includes all the local parameters of the adviced method.
- For a Spring container to recognize aspects, apply the @EnableAspectJAutoProxy annotation to the application context definition SpringContextConfig, which will enable the support for handling aspect classes and other related annotations.
- Create a test class, TestEmployeeService, to evaluate if logging and AOP are successfully integrated into the MVC application:
@RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration(classes = { SpringDbConfig.class, SpringDispatcherConfig.class }) public class TestEmployeeService { @Autowired private EmployeeService employeeServiceImpl; @Test public void testPersistEmployee(){ EmployeeForm form = new EmployeeForm(); form.setFirstName("Sherwin"); form.setLastName("Tragura"); form.setAge(38); // refer to sources } @Test public void testReadEmployees(){ List<Employee> emps = employeeServiceImpl.readEmployees(); assertNotNull(emps); } @Test public void testReadOneEmp(){ Employee emp = employeeServiceImpl.readEmployee(10); } @Test public void testDelEmp(){ employeeServiceImpl.delEmployee(11111); } }