1.简介
Java中的动态代理机制是一种在运行时生成代理类的技术,它可以在不修改原始代码的情况下对原始对象进行增强或拦截操作。动态代理机制通常用于实现AOP(面向切面编程)等功能。
Java中的动态代理机制主要涉及以下三个类:Proxy、InvocationHandler和Method。
其中,Proxy类是动态代理类的主类,InvocationHandler是代理类调用处理程序的接口,Method是Java反射中的类,用于描述类中的方法。
2.Java的动态代理机制的总体流程
-
定义接口:定义一个接口,该接口是被代理对象和代理对象都要实现的。
-
实现类:实现该接口的具体类,该类是被代理对象。
-
InvocationHandler接口:创建一个实现了InvocationHandler接口的类,该类用于在代理类中处理具体的操作。
-
Proxy类:使用Proxy类的静态方法newProxyInstance创建代理类实例,该方法需要传入被代理类的ClassLoader、接口列表和InvocationHandler对象。
-
调用方法:通过代理对象调用方法,代理对象会将方法调用转发给InvocationHandler对象进行处理,从而实现代理类的增强或拦截操作。
3.代码示例:
首先定义一个接口Subject:
public interface Subject {
void request();
}
然后定义一个实现了该接口的类RealSubject:
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject request.");
}
}
接下来,定义一个代理类DynamicProxy,该类实现InvocationHandler接口:
// 实现InvocationHandler接口的代理类DynamicProxy
public class DynamicProxy implements InvocationHandler {
private Object obj; // 目标对象
public DynamicProxy(Object obj) {
this.obj = obj;
}
// 代理类调用目标方法时,invoke方法会被调用
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before request"); // 在目标方法执行前进行操作,如打印日志、权限验证等
Object result = method.invoke(obj, args); // 调用目标方法
System.out.println("after request"); // 在目标方法执行后进行操作,如打印日志、处理返回值等
return result; // 返回目标方法的返回值
}
// 动态代理机制的使用示例
public static void main(String[] args) {
RealSubject realSubject = new RealSubject(); // 创建目标对象
DynamicProxy dynamicProxy = new DynamicProxy(realSubject); // 创建代理对象
Subject subject = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(), dynamicProxy); // 创建动态代理对象
subject.request(); // 调用代理对象的方法
}
}
在DynamicProxy类中,我们需要实现invoke方法,该方法在代理类调用目标方法时被调用,其中proxy表示代理类对象,method表示目标方法对象,args表示目标方法参数,obj表示目标对象。
在invoke方法中,我们可以在目标方法执行前后进行一些自定义的操作(如打印日志、权限验证等),然后调用目标方法,并将其返回值返回给代理类。
最后,在main方法中创建一个RealSubject对象,然后通过Proxy.newProxyInstance方法创建一个动态代理对象,并将该对象强制转换为Subject接口类型,然后调用request方法。
输出结果如下:
before request
RealSubject request.
after request
可以看到,在代理类调用目标方法前后,分别输出了“before request”和“after request”日志。
注意,动态代理机制只能代理接口类型的对象,而不能代理普通类类型的对象。因此,如果需要代理普通类类型的对象,需要使用CGLIB等第三方库。