โ† Back to list

Method Interception/Proxy in Java (Spring Boot Internals ๐Ÿง)

Have you ever wondered how Spring Boot does its magic with data stuff and method interception for AOP, JPA, Transaction Handling, etc.? Iโ€ฆ

Vinod Atwal ยท 2024-12-25 05:25 ยท 2 claps ยท 2.0 min read
#spring-boot #java #reflections #cglib #proxy
Open on Medium โ†—

Method Interception/Proxy in Java (Spring Boot Internals ๐Ÿง)

Have you ever wondered how Spring Boot does its magic with data stuff and method interception for AOP, JPA, Transaction Handling, etc.? I was curious too, so I messed around with dynamic proxies in Java. Turns out, there are a couple of ways to do it:

  • Java Dynamic Proxies: Needs interfaces.
  • CGLIB Proxies: Works directly with classes.

Before this, knowledge Refresher

-> https://medium.com/@vinodatwal/java-annotations-b2d2e61ad2ae

Basically, you can intercept method calls and do some cool stuff by checking method names, etc., kind of like Spring AOP, and JPA.

Adding some code snippets here

public interface EmployeeRepo {
    String getEmployee();
}

// dummy imp
public class EmployeeRepoImpl implements EmployeeRepo{
    @Override
    public String getEmployee() {
        System.out.println("In dummy impl ๐Ÿฅธ");
        return "fake emp {empId: 000-000-000-0000}";
    }
}

// without interface dummyImpl
public class DepartmentRepo {
    public String getDepartments(){
        System.out.println("In dummy Repo ๐Ÿฅธ");
        return "fake departments {depId: 000-000-000-0000}";
    }
}

//CglibProxy
public class CglibProxy implements Runnable{
    @Override
    public void run() {
        MethodInterceptor interceptor = new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                System.out.println("Before CGLIB Proxy: " + method.getName());
                /*
                 * Similar to AOP but we can also do some custom code impl on runtime
                 * */
                /* we can uncomment below for AOP behaviour
                 * */
//                Object result = proxy.invokeSuper(obj, args); // Important: Use invokeSuper!
                System.out.println("After CGLIB Proxy: " + method.getName());
                return "cglib departments {depId: 123-123-123-1234}";
            }
        };
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(DepartmentRepo.class);
        enhancer.setCallback(interceptor);
        DepartmentRepo cglibProxy = (DepartmentRepo) enhancer.create();

        String cglibProxyResult = cglibProxy.getDepartments();
        System.out.println("Result from CGLIB Proxy call: " + cglibProxyResult);
    }
}

 // Dynamic Proxy
public class DynamicProxy implements Runnable {

    @Override
    public void run() {
        EmployeeRepo realObject = new EmployeeRepoImpl();

        /*
        *
        * It intercepts the invocation of method via class
        * can be written in Lambda โœŒ
        * */
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("Before Java Dynamic Proxy: " + method.getName());
                /*
                * Similar to AOP but we can also do some custom code impl on runtime
                * */
                /* we can uncomment below for AOP behaviour
                * */
                //Object result = method.invoke(realObject, args);
                System.out.println("After Java Dynamic Proxy: " + method.getName());

                return  "Vinod Atwal {empId: 123-123-123-1234 }";
            }
        };

        EmployeeRepo proxy = (EmployeeRepo) Proxy.newProxyInstance(
                EmployeeRepo.class.getClassLoader(),
                new Class<?>[]{EmployeeRepo.class},
                handler);
        String dynamicProxyResult = proxy.getEmployee();
        System.out.println("Result from Dynamic Proxy call: " + dynamicProxyResult);

    }
} 
$ java -jar proxy-1.0-SNAPSHOT.jar dynamic-proxy
Before Java Dynamic Proxy: getEmployee
After Java Dynamic Proxy: getEmployee
Result from Dynamic Proxy call: Vinod Atwal {empId: 123-123-123-1234 }

$ java --add-opens java.base/java.lang=ALL-UNNAMED -jar proxy-1.0-SNAPSHOT.jar cglib-proxy 
Before CGLIB Proxy: getDepartments
After CGLIB Proxy: getDepartments
Result from CGLIB Proxy call: cglib departments {depId: 123-123-123-1234}

Repository: https://github.com/VinodAtwal/ObjectProxy

References:


๋ฉ”ํƒ€๋ฐ์ดํ„ฐ
post_id
0ee4dbfc5d56
slug
method-interception-proxy-in-java-spring-boot-internals-0ee4dbfc5d56
url
https://medium.com/@vinodatwal/method-interception-proxy-in-java-spring-boot-internals-0ee4dbfc5d56
canonical_url
https://medium.com/@vinodatwal/method-interception-proxy-in-java-spring-boot-internals-0ee4dbfc5d56
author_url
https://medium.com/@vinodatwal
status
ok
fetched_at
2026-07-21 13:27:14