Spring 框架支持两种主要的动态代理技术:JDK 动态代理和 CGLIB 代理。它们都可以用于实现面向切面编程(AOP)功能。下面将详细介绍这两种代理的实现方式,并提供示例代码。

1. JDK 动态代理

JDK 动态代理要求被代理的对象实现一个或多个接口。Spring 使用 java.lang.reflect.Proxy 类来创建代理实例。

步骤:

定义接口

public interface GreetingService {
    void greet(String name);
}

实现接口

public class GreetingServiceImpl implements GreetingService {
    @Override
    public void greet(String name) {
        System.out.println("Hello, " + name);
    }
}

创建 InvocationHandler

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class LoggingInvocationHandler implements InvocationHandler {
    private final Object target;

    public LoggingInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method: " + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("After method: " + method.getName());
        return result;
    }
}

使用代理

public class Main {
    public static void main(String[] args) {
        GreetingService service = new GreetingServiceImpl();
        GreetingService proxy = (GreetingService) Proxy.newProxyInstance(
            service.getClass().getClassLoader(),
            service.getClass().getInterfaces(),
            new LoggingInvocationHandler(service)
        );
        proxy.greet("Alice");
    }
}

2. CGLIB 代理

CGLIB 代理不需要目标对象实现接口,而是通过继承目标类来创建代理。Spring 使用 CGLIB 来实现对非接口类的代理。

步骤:

创建目标类

public class GreetingService {
    public void greet(String name) {
        System.out.println("Hello, " + name);
    }
}

创建 MethodInterceptor

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class LoggingMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before method: " + method.getName());
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("After method: " + method.getName());
        return result;
    }
}

使用 CGLIB 代理

import org.springframework.cglib.proxy.Enhancer;

public class Main {
    public static void main(String[] args) {
        GreetingService service = new GreetingService();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(GreetingService.class);
        enhancer.setCallback(new LoggingMethodInterceptor());
        
        GreetingService proxy = (GreetingService) enhancer.create();
        proxy.greet("Bob");
    }
}

Spring 动态代理通过 JDK 动态代理和 CGLIB 代理提供了强大的功能。JDK 动态代理适用于实现了接口的类,而 CGLIB 代理则可以用于没有实现接口的类。通过动态代理,你可以在不修改目标对象代码的情况下,添加横切关注点(如日志、事务管理等)。