A Different Aspect On Things

Aspect Orientated Programming has been around for a long time, it’s not a new invention. However, as with an ever changing world, new requirements and inventions come in, and sometimes we look to the old, to give us inspiration for the new.

I’m not about to tell you all about the different ways you can surround your code with aspects, there are many posts out there that do that.
I want to tell you about a few ways I think that they are useful, to developers and to our customers alike.

The first is logging. How many times do you write a
LOG.debug() statement at the beginning or end of a method?
Maybe, you’d like to log requests as they come in?

Dependencies

For my example, I’ve written a simple Spring Boot Web API, and these are the dependencies I’ve used.

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <version>${h2.version}</version>
    </dependency>
</dependencies>

The Logging Aspect

I want to log information about every request. How long they took, what the arguments were, and which method ran.
The execution Pointcut below picks up every public method, and the @Within Pointcut, picks up every RestController.
By combining them in the @Around I can execute the method around every method that matches. The ProceedingJoinPoint
contains all the information required about the method that will be called, and enough to actually invoke it when you are ready.
By making it a Spring @Component it is wired into the Spring ecosystem for you.

@Aspect
@Component
public class RequestLoggingAspect {

    private static final String MSG_FORMAT = "Method %s took %dms with args %s";

    private final RequestLogger requestLogger;

    public RequestLoggingAspect(final RequestLogger requestLogger) {
        this.requestLogger = requestLogger;
    }

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

    @Pointcut("@within(org.springframework.web.bind.annotation.RestController)")
    public void getRestControllers() {
    }

    @Around("getPublicMethods() && getRestControllers()")
    public Object restControllerPublicMethods(final ProceedingJoinPoint pjp) throws Throwable {
        var sw = new StopWatch();
        var methodName = pjp.getSignature().toLongString();
        var args = Arrays.stream(pjp.getArgs())
                .map(String::valueOf)
                .collect(Collectors.joining(","));
        sw.start();
        try {
            return pjp.proceed();
        } finally {
            sw.stop();
            var msg = String.format(MSG_FORMAT, methodName, sw.getTotalTimeMillis(), args);
            requestLogger.log(msg);
        }
    }
}

The Storing Aspect

The above example logs according to your logging frameworks configuration.
It may be that you need to do something more complicated. This works in exactly the same way, but lets have a look
at an aspect that stores requests to a database.

@Aspect
@Component
public class RequestStoringAspect {

    private final RequestLogService requestLogService;
    private final MethodParser methodParser;
    private final ArgumentMatcher argumentMatcher;

    public RequestStoringAspect(final RequestLogService requestLogService,
                                final MethodParser methodParser,
                                final ArgumentMatcher argumentMatcher) {
        this.requestLogService = requestLogService;
        this.methodParser = methodParser;
        this.argumentMatcher = argumentMatcher;
    }

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

    @Pointcut("@within(org.springframework.web.bind.annotation.RestController)")
    public void getRestControllers() {
    }

    @Around("getPublicMethods() && getRestControllers()")
    public Object restControllerPublicMethods(final ProceedingJoinPoint pjp) throws Throwable {
        var sw = new StopWatch();
        var methodSignature = pjp.getSignature().toLongString();
        var params = methodParser.parse(methodSignature);
        var args = Arrays.stream(pjp.getArgs())
                .map(String::valueOf)
                .filter(str -> !StringUtils.isNullOrEmpty(str))
                .collect(Collectors.toList());
        sw.start();
        try {
            return pjp.proceed();
        } finally {
            sw.stop();
            var arguments =  argumentMatcher.match(params, args);
            var requestLog = new RequestLogDao();
            requestLog.setArguments(arguments);
            requestLog.setExecutionMillis(sw.getTotalTimeMillis());
            requestLog.setMethodName(methodSignature);
            requestLogService.saveRequestLog(requestLog);
        }
    }
}

Here I’ve started to store some more information about the methods called, and the arguments that were captured.

This can be really useful to start to build up monitoring information. You could also start to capture audits of who has accessed different endpoints, what exceptions were thrown. This can start to build up an historic picture of your application, its performance, and what your users are really doing. It can highlight bottlenecks in the application, and can help you prioritise where you focus your efforts in your application.

Code is available here (You’ll need Java 10 or above).

Constructors & DI

I’m a big advocate of constructor injection, but a recent office debate caused me to take a step back and reevaluate my beliefs.

I thought I’d take a stab at some good and bad points of different ways of injecting dependencies into a class using Spring.

Field Injection

@Component
public class FieldInjectionExample {

    @Value("${url.value}")
    private String url;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    public String doSomething() throws IOException {
        final String object = restTemplate.getForObject(url, String.class);
        return String.valueOf(objectMapper.readValue(object, String.class));
    }
}

So here you can see that my class looks nice and clean, there are very few lines of code require to construct my object. Although the fields aren’t final, there are no setters so you could only modify them using Reflection. It’s fairly succinct, and you could see all the things needed to construct a class. So, I think I probably need write some tests for this class.

public class FieldInjectionExampleTest {
    
    private FieldInjectionExample fieldInjectionExample;
    
    @Before
    public void setup(){
        fieldInjectionExample = new FieldInjectionExample();
    }
    
    @Test
    public void testDoSomething() throws IOException {
        assertThat(fieldInjectionExample.doSomething()).isEqualTo("?");
    }
}

So I think the first thing you can spot, is that I am able to create my object under test without necessarily being aware of the dependencies required to make the class do it’s job, regardless of whether or not they are being mocked.

What constructor injection would give us here is an explicit contract, which documents exactly what is needed to do it’s job -it will fail at start up time, rather than at run time.

This will allow you to also determine if you need to create any beans as configuration (maybe a non-spring managed component), as you can check the constructor.

Take the assumption that I have now run my test, and it has failed. I’ve realised (or remembered) that my class needs a few things to make it work.

@RunWith(MockitoJUnitRunner.class)
public class FieldInjectionExampleTest {

    @Mock
    private RestTemplate restTemplate;

    @Mock
    private ObjectMapper objectMapper;

    @InjectMocks
    private FieldInjectionExample fieldInjectionExample;

    @Test
    public void testDoSomething() throws IOException {
        final String returnedObject = "String";
        when(restTemplate.getForObject(anyString(), any(Class.class))).thenReturn(returnedObject);
        when(objectMapper.readValue(anyString(), any(Class.class))).thenReturn(returnedObject);
        final String something = fieldInjectionExample.doSomething();
        assertThat(something).isEqualTo("String");
    }

}

Ok, so here I’m pretty sure that I’ve captured everything that I need, but I will never be sure until it fails.

Setter Injection

It’s entirely possible to place @Autowired annotations on setter methods of objects. This can be a neat way of instantiate a class without having all the dependencies created at run time, but I believe that this comes with down sides, such as how easy it becomes to create circular dependencies, and spot them until it’s too late.

@Component
public class SetterInjectionExample {
    
    private String url;
    private RestTemplate restTemplate;
    private ObjectMapper objectMapper;
    
    public String doSomething() throws IOException {
        final String object = restTemplate.getForObject(url, String.class);
        return String.valueOf(objectMapper.readValue(object, String.class));
    }

    @Autowired
    public void setUrl(@Value("${url.value}") final String url) {
        this.url = url;
    }

    @Autowired
    public void setRestTemplate(final RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @Autowired
    public void setObjectMapper(final ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }
}

This comes with much more code, and the ability to change the object at run time.

public class SetterInjectionExampleTest {

    private SetterInjectionExample setterInjectionExample;

    @Before
    public void setup(){
        setterInjectionExample = new SetterInjectionExample();
    }

    @Test
    public void testDoSomething() throws IOException {
        assertThat(setterInjectionExample.doSomething()).isEqualTo("?");
    }
}

This still has the same problem – you cannot easily find what is required to create and use the class. There is an expectation that this would work.
You can inject your mocks the same way you would as if you were injecting field variables.

@RunWith(MockitoJUnitRunner.class)
public class SetterInjectionExampleTest {

    @Mock
    private RestTemplate restTemplate;

    @Mock
    private ObjectMapper objectMapper;

    @InjectMocks
    private SetterInjectionExample setterInjectionExample;

    @Test
    public void testDoSomething() throws IOException {
        final String returnedObject = "String";
        when(restTemplate.getForObject(anyString(), any(Class.class))).thenReturn(returnedObject);
        when(objectMapper.readValue(anyString(), any(Class.class))).thenReturn(returnedObject);
        final String something = setterInjectionExample.doSomething();
        assertThat(something).isEqualTo("String");
    }
}

This still means that, although you have setters available, it still isn’t clear what is needed in order for the class to do its job. Maybe it could be useful for optional parameters.

Constructor Injection

Here is the same class, with dependencies injected into the constructor.

@Component
public class ConstructorInjectionExample {
    private final String url;
    private final RestTemplate restTemplate;
    private final ObjectMapper objectMapper;

    @Autowired
    public ConstructorInjectionExample(@Value("${url.value}") final String url,
                                       final RestTemplate restTemplate,
                                       final ObjectMapper objectMapper) {
        this.url = url;
        this.restTemplate = restTemplate;
        this.objectMapper = objectMapper;
    }
    
    public String doSomething() throws IOException {
        final String object = restTemplate.getForObject(url, String.class);
        return String.valueOf(objectMapper.readValue(object, String.class));
    }

}

It’s really clear to see what your class needs in order to do it’s job. I cannot instantiate this class without having a URL, a RestTemplate and an ObjectMapper.

This doesn’t mean that you cannot inject your mocks if you so wish, but it does allow to see what the class needs to do it’s job.

@RunWith(MockitoJUnitRunner.class)
public class ConstructorInjectionExampleTest {

    @Mock
    private RestTemplate restTemplate;

    @Mock
    private ObjectMapper objectMapper;

    @InjectMocks
    private ConstructorInjectionExample constructorInjectionExample;

    @Test
    public void testDoSomething() throws IOException {
        final String returnedObject = "String";
        when(restTemplate.getForObject(anyString(), any(Class.class))).thenReturn(returnedObject);
        when(objectMapper.readValue(anyString(), any(Class.class))).thenReturn(returnedObject);
        final String something = constructorInjectionExample.doSomething();
        assertThat(something).isEqualTo("String");
    }
}

In order to understand the different ways of injection properties, I’ve broken down the key points in a table. This will allow you to make an informed decision as to which one is appropriate for your work.

Field Setter Ctor
Cannot instantiate without necessary
properties
X
Cannot create circular dependencies X X
Clearly defined requirements in one place X
Potential for easy readability X X
Allow the use of the ‘final’ keyword X
Obvious when breaking SRP X
Useful for non-mandatory properties X

What Does Spring Say?

Finally, what does Spring say about the most appropriate form of property injection?

The Spring team generally advocates constructor injection as it enables one to implement application components as immutable objects and to ensure that required dependencies are not null. Furthermore constructor-injected components are always returned to client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments is a bad code smell, implying that the class likely has too many responsibilities and should be refactored to better address proper separation of concerns.

Automating AWS Backups

As developers, we all know that things go wrong; machines break (for sometimes totally unpredictable reasons) and data can become corrupt. What better way of helping to mitigate these problems than taking backups and snapshots of your infrastructure and data.

In the office we use AWS extensively for our infrastructure. We have various tools running in EC2 instances that we use for our day to day development. You’d think that a suite of tools as sophisticated as AWS would have a way of automatically backing up volumes and instances and retaining them for periods of time!

We found a bash script that pretty much did what we were after, but there were licence implications with using it. Bash scripting can be a bit of a black art, especially for sophisticated operations, so why not do it in a language we all  understand – Java!

Spring Boot allows us to create a command line Java application, simply by implementing the CommandLineRunner interface:

@SpringBootApplication
public class BackupApplication implements CommandLineRunner {

  private final BackupService backupService;

  @Autowired
  public BackupApplication(final BackupService backupService) {
    this.backupService = backupService;
  }

  public static void main(String[] args) {
   SpringApplication.run(BackupApplication.class, args);
  }
 
  @Override
  public void run(String... args) throws Exception {
    backupService.backup();
    backupService.purge();
  }
}

Connecting to AWS using an already created access key and secret is also relatively simple using the AWS SDK. You can pass the parameters below on the command line (-Daws.secret.key=KEY):

@Configuration
public class AwsConfiguration {

  @Bean
  public AWSCredentials credentials(@Value("${aws.secret.key}") final String secretKey, @Value("${aws.secret.pass}") final String secretPass) {
    return new BasicAWSCredentials(secretKey, secretPass);
  }

  @Bean
  public AmazonEC2Client ec2Client(final AWSCredentials credentials) {
    return new AmazonEC2Client(credentials);
  }
}

In order to find the instances I want to back up, they’ve been tagged with ‘mint-backup’ as the key, and the period of backup for the value (e.g. ‘nightly’, ‘weekly’). These are passed in on the command line as arguments and are used by the Backup Service:

@Autowired
public BackupServiceImpl(final AmazonEC2Client ec2Client,
  @Value("${tag.key}") final String tagKey,
  @Value("${tag.value}") final String tagValue,
  @Value("${retention.days}") final long days) {
  this.ec2Client = ec2Client;
  this.tagKey = tagKey;
  this.tagValue = tagValue;
  this.duration = Duration.ofDays(days);
}

The AWS SDK allows you to search on Tags:

private List getVolumes() {
  final Filter filter = new Filter("tag:"+ tagKey, Collections.singletonList(tagValue));
  final DescribeVolumesRequest request = new DescribeVolumesRequest();

  DescribeVolumesResult result = ec2Client.describeVolumes(request.withFilters(filter));
  String token;
  final List volumes = result.getVolumes();
  volumes.addAll(result.getVolumes());
  while ((token = result.getNextToken()) != null) {
    request.setNextToken(token);
    result = ec2Client.describeVolumes(request);
    volumes.addAll(result.getVolumes());
  }
  return volumes;
}

Now I have a list of Volumes, I can create a snapshot of each one:

private List createSnapshots(final List volumes) {
  final List snapshotIds = new ArrayList<>();
  volumes.forEach(volume -> {
  final CreateSnapshotRequest createSnapshotRequest = new CreateSnapshotRequest(volume.getVolumeId(),
  "SNAPSHOT-" + DateTime.now().getMillis());
  final CreateSnapshotResult createSnapshotResult = ec2Client.createSnapshot(createSnapshotRequest);
  final Snapshot snapshot = createSnapshotResult.getSnapshot();
  snapshotIds.add(snapshot.getSnapshotId());
  });
return snapshotIds;
}

Once they are all created they are then tagged with a purge date, so that another process can remove them once they have expired:

private void tagSnapshots(final List snapshotIds) {
  final long purgeDate = DateTime.now().plus(period).getMillis();
  final Tag purgeTag = new Tag("purge-date", String.valueOf(purgeDate));
  final CreateTagsRequest createTagsRequest = new CreateTagsRequest()
    .withTags(purgeTag)
    .withResources(snapshotIds);
  ec2Client.createTags(createTagsRequest);
}

Purging is a little easier. We can request for all snapshots that have a ‘purge-date’ tag, and then filter them based on the value of the tag so that we only get ones before now, grab the ids and create a collection of new requests and issue each one to the ec2 client:

@Override
public void purge() {
  final DescribeSnapshotsRequest request = new DescribeSnapshotsRequest();
  final Filter filter = new Filter("tag-key", Collections.singletonList("purge-date"));
  DescribeSnapshotsResult result = ec2Client.describeSnapshots(request.withFilters(filter));
  String token;
  final List snapshots = new ArrayList<>();
  snapshots.addAll(result.getSnapshots());
  while ((token = result.getNextToken()) != null){
    request.setNextToken(token);
    result = ec2Client.describeSnapshots(request);
  snapshots.addAll(result.getSnapshots());
  }
  final DateTime now = DateTime.now();
  snapshots.stream()
    .filter(snapshot -> filterSnapshot(snapshot, now))
    .map(Snapshot::getSnapshotId)
    .map(DeleteSnapshotRequest::new)
    .forEach(ec2Client::deleteSnapshot);
  }

private boolean filterSnapshot(final Snapshot snapshot, final DateTime now) {
  for (final Tag tag : snapshot.getTags()){
    if (tag.getKey().equals("tag-key") && readyForDeletion(tag.getValue(), now)) {
      return true;
    }
  }
  return false;
}

private boolean readyForDeletion(final String tagValue, final DateTime now) {
  final long purgeTag = Long.parseLong(tagValue);
  final DateTime dateTime = new DateTime(purgeTag);
  return dateTime.isBefore(now);
}

This is packaged as an executable Jar, so that it can be placed on our Jenkins instances, and executed as needed (either by specifying a cron expression or clicking Build Now). It can also be run from the command line on a developers PC if needed. It means that the process of taking snapshots of our EBS Volumes is consistent, no matter who or where the process is executed, which should help avoid any problems or differences between back up executions.