代理

1. 静态代理

静态代理是 Java 中一种常见的代理模式实现方式,属于结构型设计模式。它的核心思想是:为一个对象提供一个代理对象,并由代理对象控制对原对象的访问。下面使用代码来展示一下静态代理对一个实现类进行代理增强。

接口:

1
2
3
public interface UserService{
void show();
}

实现类:

1
2
3
4
5
6
public class UserServiceImpl implements UserService{
@Override
public void show() {
System.out.println("我要看电视了");
}
}

代理类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class UserPoxy implements UserService{

private UserService userService;

public UserPoxy(UserService userService) {
this.userService = userService;
}

@Override
public void show() {
System.out.println("代理增强:先打开电视");
userService.show();
System.out.println("代理增强:关闭电视");

}
}

测试类:

1
2
3
4
5
6
7
8
public class App {
public static void main( String[] args ) {
UserService userService = new UserServiceImpl();
UserPoxy userPoxy = new UserPoxy(userService);
userPoxy.show();
}
}

输出:

1
2
3
4
5
6
代理增强:先打开电视
我要看电视了
代理增强:关闭电视

进程已结束,退出代码为 0

虽然这种方式可以对实现类进行代理增强,但是代码的复用性不高,同时比如需要100个代理类,就需要写100个。这样不好,下面进行介绍动态代理,可以完美的解决这个问题。

2. 动态代理

现在使用最多的就是JDK动态代理和CGLIB动态代理。

  • JDK动态代理:这个是对接口进行的代理模式,由JDK内部提供,通过java.lang.reflect.Proxy 类和 InvocationHandler 接口实现。当代理的类调用方法时进行拦截代理。
  • CGLIB 动态代理:这个是由外部方式引入,比JDK动态代理更加强大(可以直接代理没有接口的类)。

1. JDK动态代理演示

接口:

1
2
3
public interface UserService{
void show();
}

实现类:

1
2
3
4
5
6
public class UserServiceImpl implements UserService {
@Override
public void show() {
System.out.println("我要看电视了");
}
}

代理拦截器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class UserProxyHandler implements InvocationHandler {

private Object target;

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

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

System.out.println("JDK动态代理:先打开电视");
Object object = method.invoke(target, args);
System.out.println("JDK动态代理:关闭电视");
return object;
}
}

测试类:

1
2
3
4
5
6
7
8
9
10
public class test {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
//使用JDK代理类
UserService proxy = (UserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(),
userService.getClass().getInterfaces(),
new UserProxyHandler(userService));
proxy.show();
}
}

输出:

1
2
3
4
5
JDK动态代理:先打开电视
我要看电视了
JDK动态代理:关闭电视

进程已结束,退出代码为 0

JDK底层实现原理:Proxy.newProxyInstance()会在运行时通过字节码技术(如 ASM 或内部的sun.misc.ProxyGenerator)动态生成一个$Proxy0类(名字可能不同),该类:

  • 继承 java.lang.reflect.Proxy
  • 实现了传入的所有接口
  • 接口中每个方法的实现都会调用 InvocationHandler.invoke()

JDK 动态代理是一种轻量级、无需额外依赖的代理方式,适用于基于接口编程的场景。它的核心思想是:将方法调用统一拦截到 InvocationHandler.invoke() 中进行增强处理,从而实现如日志、事务、权限控制等 AOP 功能。

2. CGLIB动态代理演示

首先先引入CGLIB的依赖:

1
2
3
4
5
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>

编写需要代理的类:

1
2
3
4
5
public class UserServiceImpl {
public void show() {
System.out.println("我要看电视了");
}
}

测试类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class test {
public static void main(String[] args) {
//创建字节码增强器
Enhancer enhancer = new Enhancer();
//告诉CGLIB需要代理哪个类
enhancer.setSuperclass(UserServiceImpl.class);
//设置回调函数
enhancer.setCallback(new UserProxyInterceptor());
//创建代理对象
UserServiceImpl userService = (UserServiceImpl) enhancer.create();

//调用
userService.show();
}
}

代理拦截器:

1
2
3
4
5
6
7
8
9
public class UserProxyInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("CGLIB代理:先打开电视");
Object object = methodProxy.invokeSuper(o, objects);
System.out.println("CGLIB代理:关闭电视");
return object;
}
}

注意:需要在VM中这样配置,不然会报错!!!!

1
2
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/sun.net.util=ALL-UNNAMED

image-20251203192901085

输出:

1
2
3
4
5
6
CGLIB代理:先打开电视
我要看电视了
CGLIB代理:关闭电视

进程已结束,退出代码为 0

调用过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
main()


enhancer.create() → 动态生成 UserService$$EnhancerByCGLIB


proxy.saveUser("张三")


UserService$$EnhancerByCGLIB.saveUser()


MyInterceptor.intercept(...)


proxy.invokeSuper() → 调用 UserService.saveUser()(原始方法)


返回结果