Search code examples
spring-bootdesign-patternsaspectjspring-aop

aspectj check broken layer access in spring boot


I try to use aspectj for checking whether the layers of the architecture are broken, e.g. the access from controller to repository without using a service between

Now this is marking every method call to a autowired annotated within de.fhb.controller.

but how can i then limit that to Repositories for example?

The package structure looks like this:

  • de.fhb.controller
  • de.fhb.service
  • de.fhb.entity and and so on.

my aspect looks like this

@Aspect
public class Layer {

@DeclareError("within(de.fhb.controller..*) && @annotation(org.springframework.beans.factory.annotation.Autowired) " )
private static final String typeWarning = "You try to access through many layers";

}

the repository:

@Repository
public interface BoxRepository extends JpaRepository<Box, Long>{

    public List findByPrio(long prio);
}

and the controller that should be checked by aspects:

@RequestMapping("/box")
@Controller
public class BoxController {

@Autowired
private BoxRepository boxRepository; // negative example

@Autowired
private BoxService boxService;

@RequestMapping(value = "/")
public String list(Model model) {
    List boxes = boxRepository.findAll(); // negativ example
    model.addAttribute("boxes", boxes);
    return "box/list";
}

for further look: repository at github


Solution

  • Your pointcut

    within(de.fhb.controller..*) &&
    execution(de.fhb.repository.BoxRepository *(..))
    

    means in prose: Intercept any method in package de.fhb.controller or its sub-packages which has a return type of de.fhb.repository.BoxRepository, but in your code is no such method. So you will never see a compiler error.

    ;-)


    Updated answer after question update:

    You need to intercept calls to methods of types with a @Repository annotation:

    within(de.fhb.controller..*) &&
    call(* (@org.springframework.stereotype.Repository *).*(..))
    

    But in order to do that you need to switch from Spring AOP to full-blown AspectJ with compile-time weaving, i.e. you need to use the AspectJ compiler Ajc to compile and weave your aspect. The reason is that Spring AOP does not support the call() pointcut, but this is what you need. An execution() pointcut will not help you here, but that is the only one supported by a proxy-based "AOP lite" framework like Spring AOP. You just need to weave this one aspect with AspectJ, the other aspects can still use Spring AOP. But then need to take care about AspectJ not picking up your other aspects.