Spring
Why Interfaces are recommend by Spring?

Why Interfaces are recommend by Spring?

Spring framework has become the central part of every Java based micro-service application. Spring beans work with concrete classes and with interfaces as well, then why interfaces are recommended by Spring framework?

Introduction

Spring framework allows you to inject the beans by Interface as well as the Concrete classes. Consider following code,

public interface FileService {
    byte[] readFile(String filename);
}

public class RemoteFileService implements FileService {
    @Override
    public byte[] readFile(String filename) {
        // logic to read file and get contents from remote location
    }
}

Now, in your client code you can use FileService or RemoteFileService with @Autowired or @Inject annotation and Spring will inject them.

So then the question is, why interfaces are recommended by Spring framework? Well, there are some obvious reasons which are,

Most Obvious

  1. Using Interfaces allows your classes to extend from some other classes if required.
  2. Your Interfaces can have multiple implementations and you can switch between any of them without changing the client code.

Even though these are pretty obvious, these are important and following them does help you in some legacy code bases as well.

Aspect Oriented Programming(AOP) is another major reason for which Spring recommends using Interfaces.

Aspect Oriented Programming

For Aspect Oriented Programming to work, Spring has to intercept the method calls. For this there are two ways,

  1. Using Java Proxy creation
  2. Using Bytecode generation or modification

Let’s understand how both work.

Using Java Proxy Creation

In this case, Spring will use the Proxy functionality provided by the Java platform itself. Spring does not have to do any ByteCode modification. So using above given example of FileService interface, following is an example of how can we create a Proxy that can intercept the methods,

public FileService createProxy(FileService fileServiceImpl, MethodBeforeInterceptor interceptor) {
    return (FileService) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{FileService.class}, new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            interceptor.executeBeforeTarget();
            return method.invoke(fileServiceImpl, args);
        }
    });
}

Following is the definition of the MethodBeforeInterceptor interface,

public interface MethodBeforeInterceptor {

    void executeBeforeTarget();

}

As you can see, we do not need any external libraries to do any runtime modification to the ByteCode. As this is supported by the Java platform, it works on all the versions of Java.

Now, if you check the Proxy.newProxyInstance method, you will find that it only supports Interface proxy generation. There is no way to generate Proxy for a concrete class and that’s where the second way comes in picture.

Using ByteCode generation

Now, if you are using Concrete class instead of Interface, Spring needs to use libraries such as CGLib or ASM to modify behavior of these classes. Following is the way using CGLib we can modify the behavior of a concrete class,

public FileServiceImpl createProxy(MethodBeforeInterceptor interceptor) {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(FileServiceImpl.class);
    enhancer.setCallback(new MethodInterceptor() {
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            interceptor.executeBeforeTarget();
            return methodProxy.invoke(o, objects);
        }
    });
    return (FileServiceImpl) enhancer.create();
}

Now, you may say that “this seems easy” and don’t see any problems with this.

Problem is,

  1. This is highly dependent on the version of the Java. If the ByteCode generation or modification fails, we will find this problem at runtime.
  2. Additional library dependency in the project.
  3. Concrete classes may have final methods which cannot be intercepted.

Leave a Reply

Your email address will not be published. Required fields are marked *