To be able to deal with scopes , transactions and other mechanisms related to the beans creation, spring has to use proxies to accomplish that. There are 2 ways that spring deals with proxy

  • JDK Proxy
  • CGLIB

JDK Proxy

This is the default approach but there are some limitations.

  • Requires proxy object to implement the interface
  • Only interface methods will be proxied
  • No support for self-invocation

To make it more clear you can see how this can be done manually. so you understand


ItemsRepository itemsRepository = (PersonDao) Proxy.newProxyInstance(
                ItemsRepository.class.getClassLoader(), ItemsRepositoryImpl.class.getInterfaces(),
                new ItemsRepositoryInvocationHandler(
                        new ItemsRepositoryImpl()
                )
        );

Using the approach above you create a proxy which will intercept the invocations using the class ItemsRepositoryInvocationHandler. You can check the class below:


public class ItemsRepositoryInvocationHandler implements InvocationHandler {

    private final ItemsRepository target;

    public ItemsRepositoryInvocationHandler(ItemsRepository target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
        System.out.println("before execution " + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("after  execution " + method.getName());
        return result;
    }
}


CGLIB

If you are not implementing an interface, spring will pick the CGLIB approach to create your proxies, but there are also some limitations:

  • Does not work for final classes
  • Does not work for final methods
  • Only public/protected/package methods will be proxied, private methods are not proxied
  • No support for self-invocation

One example of CGLIB code manually implemented you can see below



 public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setCallback(new ItemsRepositoryMethodInterceptor());
        enhancer.setSuperclass(ItemsRepository.class);
        ItemsRepository itemsRepository = (ItemsRepository) enhancer.create();

        Item item = itemsRepository.findById(5);
        itemsRepository.save(item);
    }

And the interceptor .


public class DepartmentDaoMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("before call" + method.getName());
        Object result = methodProxy.invokeSuper(object, args);
        System.out.println("after call" + method.getName());
        return result;
    }
}