JDK 内置的 Proxy 实现动态代理

JDK内置的动态代理只能够代理实现接口的类,因此需要先提供一个接口

1
2
3
4
public interface Interface {
void doSomething();
void somethingElse(String arg);
}

实现类:

1
2
3
4
5
6
7
8
9
10
11
public class RealObject implements Interface {
@Override
public void doSomething() {
System.out.println("doSomething");
}

@Override
public void somethingElse(String arg) {
System.out.println("something " + arg);
}
}

实现一个动态代理类,该类实现接口 InvocationHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class DynamicProxyHandler implements InvocationHandler {
private Object proxied;
public DynamicProxyHandler(Object proxied){
this.proxied = proxied;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("**** proxy: " + proxy.getClass() + ", method: " + method + ", args:" + args);
if (args != null)
for (Object arg : args)
System.out.println(" " + arg);
return method.invoke(proxied, args);
}
}

测试运行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class SimpleDynamicProxy{
public static void consumer(Interface iface){
iface.doSomething();
iface.somethingElse("bonobo");
}

public static void main(String[] args) {
RealObject real = new RealObject();
consumer(real);

// 创建动态代理
Interface proxy = (Interface) Proxy.newProxyInstance(
Interface.class.getClassLoader(),
new Class[]{Interface.class},
new DynamicProxyHandler(real));
consumer(proxy);
}
}

使用内置的 Proxy 实现动态代理存在一个问题:被代理的类必须实现接口,未实现接口则无法完成动态代理

如果项目中有些类没有实现接口,则不应该为了实现动态代理而可以去抽出一些没有实际意义的接口,但我们可以使用cglib解决该问题

使用 cglib 实现动态代理

CGLIB(Code Generation Library)是一个开源项目,是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口,通俗说cglib可以在运行时动态生成字节码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class DynamicProxy implements MethodInterceptor {

/**
* 被代理对象
*/
Object proxied;

/**
* 生成代理对象
*/
public Object getProxyObject(Object proxied){
this.proxied = proxied;
// 增强器,动态代码生成器
Enhancer enhancer = new Enhancer();
// 回调方法
enhancer.setCallback(this);
// 设置生成类的父类类型
enhancer.setSuperclass(proxied.getClass());
// 动态生成字节码并返回代理对象
return enhancer.create();
}

@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object result = methodProxy.invoke(proxied, objects);

return result;
}
}

测试:

1
2
3
4
public static void main(String[] args) {
Interface iface = (Interface) new DynamicProxy().getProxyObject(new RealObject());
iface.doSomething();
}

intercept 方法的参数:

  • Object o :cglib 动态生成的代理类。
  • Method method :实体类被调用的被代理的方法。
  • Object[] objects :参数值列表
  • MethodProxy methodProxy :生成的代理类对方法代理的代理引用
小结

使用 cglib 可以实现动态代理,即使被代理的类没有实现接口,但被代理的类必须不是 final 类。