Book Image

Spring Essentials

Book Image

Spring Essentials

Overview of this book

Spring is an open source Java application development framework to build and deploy systems and applications that run on the JVM. It is the industry standard and the most popular framework among Java developers with over two-thirds of developers using it. Spring Essentials makes learning Spring so much quicker and easier with the help of illustrations and practical examples. Starting from the core concepts of features such as inversion of Control Container and BeanFactory, we move on to a detailed look at aspect-oriented programming. We cover the breadth and depth of Spring MVC, the WebSocket technology, Spring Data, and Spring Security with various authentication and authorization mechanisms. Packed with real-world examples, you’ll get an insight into utilizing the power of Spring Expression Language in your applications for higher maintainability. You’ll also develop full-duplex real-time communication channels using WebSocket and integrate Spring with web technologies such as JSF, Struts 2, and Tapestry. At the tail end, you will build a modern SPA using EmberJS at the front end and a Spring MVC-based API at the back end.By the end of the book, you will be able to develop your own dull-fledged applications with Spring.
Table of Contents (14 chapters)
Spring Essentials
Credits
About the Authors
About the Reviewer
www.PacktPub.com
Preface
Index

Aspect Oriented Programming


Most software applications usually have some secondary—but critical—features, such as security, transaction, and audit-logging, spanned across multiple logical modules. It would be a nice idea not to mix these cross-cutting concerns in your core business logic. Aspect Oriented Programming (AOP) helps you achieve this.

Object Oriented Programming (OOP) is about modularizing complex software programs, with objects as the fundamental units that hold your core business logic and data. AOP complements OOP to add more complex functionality transparently across modules of your application without polluting the original object structure. AOP stitches (weaves) cross-cutting concerns into your program, either at compile time or runtime, without modifying the base code itself. AOP lets the object-oriented program stay clean and just have the core business concerns.

Static and dynamic AOP

In AOP, the framework weaves the cross-cutting concerns into the main program transparently. This weaving process comes in two different flavors: static and dynamic. In the case of static AOP, as the name implies, Aspects are compiled directly into static files, that is, to the Java bytecode, on compilation. This method performs better, as there is no special interception at runtime. But the drawback is that you need to recompile the entire application every time you change anything in the code. AspectJ, one of the most comprehensive AOP implementations, provides compile-time weaving of Aspects.

In the case of dynamic AOP, the weaving process is performed dynamically at runtime. Different frameworks implement this differently, but the most general way of achieving this is using proxies or wrappers for the advised objects, allowing the Advice to be invoked as required. This is a more flexible method as you can apply AOP with varying behavior at runtime depending on data, which is not possible in the case of static AOP. There is no need for recompiling the main application code if you use XML files for defining your AOP constructs (schema-based approach). The disadvantage of dynamic AOP is a very negligible performance loss due to the extra runtime processing.

Spring AOP is proxy based, that is, it follows the dynamic flavor of AOP. Spring provides the facility to use static AOP by integrating with AspectJ too.

AOP concepts and terminology

Understanding AOP concepts and terms gives you an excellent starting point for AOP; it helps you visualize how and where AOP can be applied in your application:

  • Aspect: The concern that cuts across multiple classes or modules. Transaction and security are examples. Spring Transaction is implemented as Aspects.

  • Join point: A point during the execution of the program at which you want to insert additional logic using AOP. A method execution and a class instantiation are examples.

  • Advice: The action taken by (the code or method that executes) the Aspect at a particular join point. Different types of advices include before, after, and around advices. Typically, an Aspect has one or more Advices.

  • Pointcut: An expression that defines or matches a set of join points. The Advice associated with a pointcut executes at any join point it matches. Spring supports the AspectJ pointcut expression language by default. An example is execution(* com.xyz.service.*.*(..)).

  • Target object: The advised object. If you use dynamic AOP, this would be a proxied object.

  • Weaving: Inserting Aspects into a target object to make it advised at compile time, load time or runtime. AspectJ supports compile-time weaving and Spring weaves at runtime.

  • Introduction: The process by which you add a new method or field to an advised object, with or without making it implement an interface.

Spring AOP – definition and configuration styles

Spring provides a proxy-based dynamic implementation of AOP, developed purely in Java. It neither requires a special compilation process like AspectJ nor controls the class loader hierarchy, hence it can be deployed inside any Servlet container or application server.

Although not a full-blown AOP framework like AspectJ, Spring provides a simple and easy-to-use abstraction of most of the common features of AOP. It supports only method execution join points; field interception is not implemented. Spring provides tight integration with AspectJ, in case you want to advise very fine-grained Aspect orientation that Spring AOP doesn't cover by adding more AspectJ-specific features without breaking the core Spring AOP APIs.

Spring AOP uses standard JDK dynamic proxies for Aspect orientation by default. JDK dynamic proxies allow any interface (or set of interfaces) to be proxied. If you want to proxy classes rather than interfaces, you may switch to CGLIB proxies. Spring automatically switches to use CGLIB if a target object does not implement an interface.

Starting from Spring 2.0, you can follow either a schema-based approach or an @AspectJ annotation style to write custom Aspects. Both of these styles offer fully typed Advice and use of the AspectJ pointcut language while still using Spring AOP for weaving.

XML schema-based AOP

When using schema-based AOP, you need to import aop namespace tags into your application-context file, as follows:

<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">
<!-- bean definitions here -->
</beans>

@AspectJ annotation-based AOP

@AspectJ refers to a style of declaring Aspects as regular Java classes that are annotated. Spring interprets the same annotations as AspectJ 5, using a library supplied by AspectJ for pointcut parsing and matching. Spring AOP has no dependency on the AspectJ compiler or weaver, though.

When using the @AspectJ annotation style, you first need to enable @AspectJ support in your Spring configuration, whether or not it is in the XML or Java configuration. Additionally, you need to make sure you add aspectjweaver.jar in your classpath. Adding an @EnableAspectJAutoProxy annotation to your Java @Configuration annotation will enable @AspectJ support in your project:

@Configuration
@ComponentScan(basePackages = "com.springessentialsbook")
@EnableAspectJAutoProxy
public class AOPJavaConfigurator {
...
}

Alternatively, if you use XML-based configuration, @AspectJ support can be enabled by adding the <aop:aspectj-autoproxy/> element in your application-context file.

Declaring an @Aspect annotation

Your Aspect is a simple POJO, either annotated with @Aspect (org.aspectj.lang.annotation.Aspect) or declared as <aop:aspect/> under the <aop:config> section of your application-context XML file. Remember, the class marked as @Aspect should be declared as a Spring bean using either an annotation or <bean/> declaration in your application context XML file.

Here is an annotated Aspect, a Spring component annotated as @Aspect:

@Component("auditLoggerAspect")
@Aspect
public class AuditLoggerAspect {
...
}

Note that @Aspect is a Spring bean too. It can be any of the specializations of @Component.

Now, let's take a look at the XML alternative for Aspect declaration:

<aop:config>
   <aop:aspect id="audLogAspect" ref="auditLoggerAspect">
</aop:config>
<bean id="auditLoggerAspect" class="com...AuditLoggerAspect"/>

Aspects may have methods and fields, just like any other class. They may also contain pointcut, advice, and introduction (inter-type) declarations. Aspects themselves cannot be the target of Advice from other Aspects; they are excluded from auto-proxying.

Pointcuts

A pointcut comprises two parts, as shown in the following code snippet: a method signature (an empty method with a void return type inside the Aspect class) with any parameters and an expression that matches the exact method executions we are interested in. Remember, Spring AOP only supports method execution join points:

@Pointcut("execution(* com.springessentialsbook.service.TaskService.createTask(..))") //Pointcut expression
private void createTaskPointCut() {} //Signature

The pointcut expression follows the standard AspectJ format. You may refer to the AspectJ pointcut expression reference for the detailed syntax. The following section gives you a strong foundation for constructing pointcuts for Spring AOP.

Pointcut designators

Spring AOP supports just a subset of the original AspectJ pointcut designators (PCDs) for use in pointcut expressions, as given in the following table:

PCD

Description

execution

Method execution join point; the default PCD for Spring AOP

within

Matches methods in a range of types, packages, and so on

this

Matches proxy instances of a given type

target

Matches target object with a given type

args

Matches methods with the given argument types

@target

Matches methods of classes with the given annotation

@args

Matches methods having argument (s) with the given annotation (s)

@within

Matches methods within types that have a given annotation

@annotation

Matches methods with the given annotation

In addition to the preceding table, Spring supports an extra non-AspectJ PCD, bean, which is useful to directly refer to a Spring bean or a set of beans with a comma-separated list of beans using bean(idsOrNamesOfBean).

Note that the pointcuts intercept only public methods due to the proxy nature of Spring AOP. If you want to intercept protected and private methods or even constructors, consider using AspectJ weaving (integrated with Spring itself) instead.

Pointcut examples

Pointcut expressions can be combined using &&, ||, and !. You can refer to pointcut expressions by name, too. Let's see a few examples:

@Pointcut("execution(* com.taskify.service.*.*(..))")
private void allServiceMethods() {}

@Pointcut("execution(public * *(..))")
private void anyPublicOperation() {}

@Pointcut("anyPublicOperation() && allServiceMethods()")
private void allPublicServiceMethods() {}

@Pointcut("within(com.taskify.service..*)")
private void allServiceClasses() {}

@Pointcut("execution(* set*(..))")
private void allSetMethods() {}

@Pointcut("execution(* com.taskify.service.TaskService.*(..))")
private void allTaskServiceMethods() {}

@Pointcut("target(com.taskify.service.TaskService)")
private void allTaskServiceImplMethods() {}


@Pointcut("@within(org.springframework.transaction.annotation.Transactional)")
private void allTransactionalObjectMethods() {}

@Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)")
private void allTransactionalAnnotatedMethods() {}

@Pointcut("bean(simpleTaskService)")
private void allSimpleTaskServiceBeanMethods() {}

An XML version of a pointcut definition goes like this:

<aop:config>
  ...
   <aop:pointcut id="allTaskServicePointCut"
         expression="execution(*com.taskify.service..TaskService.*(..))"/>
</aop:config>

Advices

An Advice is the action that gets injected before, after, or around the method executions matched by the pointcut expression. The pointcut expression associated with an Advice could be a named or defined pointcut, as listed in the above examples, or a pointcut expression declared in place, that is, advices and pointcuts can be declared together.

Let's see an example for an Advice that refers to a pointcut expression named Pointcut:

@Pointcut("execution(* com.taskify.service.TaskService.*(..))")
private void allTaskServiceMethods() {}

@Before("allTaskServiceMethods()")
private void logBeforeAllTaskServiceMethods() {
  logger.info("*** logBeforeAllTaskServiceMethods invoked ! ***");
}

The following code listing combines both a join point and Advice in one go. This is the most common approach:

@After("execution(* com.taskigy.service.TaskService.*(..))")
private void logAfterAllTaskServiceMethods() {
  logger.info("***logAfterAllTaskServiceMethods invoked ! ***");
}

The following table lists the available Advice annotations:

Advice annotation

Description

@Before

Runs before method execution.

@After

Runs after method exit (finally).

@AfterReturning

Runs after the method returns without an exception. You can bind the return value with the Advice as the method argument.

@AfterThrowing

Runs after the method exits by throwing an exception. You can bind the exception with the Advice as the method argument.

@Around

The target method actually runs inside this Advice. It allows you to manipulate the method execution inside your Advice method.

The @Around Advice

The @Around Advice gives you more control over method execution, as the intercepted method essentially runs inside your Advice method. The first argument of the Advice must be ProceedingJoinPoint. You need to invoke the proceed() method of ProceedingJoinPoint inside the Advice body in order to execute the target method; else, the method will not get called. After the method execution returns to you with whatever it returns back to your advice, do not forget to return the result in your Advice method. Take a look at a sample @Around advice:

@Around("execution(* com.taskify.service.**.find*(..))")
private Object profileServiceFindAdvice(ProceedingJoinPoint jPoint) throws Throwable {
    Date startTime = new Date();
    Object result = jPoint.proceed(jPoint.getArgs());
    Date endTime = new Date();
    logger.info("Time taken to execute operation: " + jPoint.getSignature() + " is " + (endTime.getTime() - startTime.getTime()) + " ms");
    return result;
}
Accessing Advice parameters

There are two distinct ways of accessing the parameters of the method you are advising in the Advice method:

  • Declaring a join point as the first argument

  • Binding args in the pointcut definition

Let's see the first approach:

@Before("execution(* com.taskify.service.TaskService.createTask(..)")
private void logBeforeCreateTaskAdvice(JoinPoint joinpoint) {
   logger.info("***logBeforeCreateTaskAdvice invoked ! ***");
   logger.info("args = " + Arrays.asList(joinpoint.getArgs()));
}

You can see that joinpoint.getArgs() returns Object[] of all the arguments passed to the intercepted method. Now, let's see how to bind named arguments to the Advice method:

@Before("createTaskPointCut() and args(name, priority, createdByuserId, assigneeUserId)")
private void logBeforeCreateTaskAdvice(String name, int priority, int createdByuserId, int assigneeUserId) {

  logger.info("name = " + name + "; priority = " + priority + ";
  createdByuserId = " + createdByuserId);
}

Note that the joinpoint expression matches the arguments by name. You can have a joinpoint object as an optional first argument in the method signature without specifying it in the expression: you will have both joinpoint and arguments, enabling more manipulation.