这段Java代码使用了Java的Proxy
类来动态地创建一个代理实例。代理模式是设计模式中的一种,用于在不修改原始类的情况下增加额外的功能或控制对原始对象的访问。在Java中,我们可以使用Proxy
类和InvocationHandler
接口来实现这种动态代理。
目录
一、目录结构
二、各个部分
(1)首先定义UserService
接口和UserServiceImpl
类,并且UserServiceImpl
类实现了UserService
接口。
public interface UserService {
public void add();
public void delete();
}
public class UserServiceImpl implements UserService{
@Override
public void add() {
System.out.println("增加了一个用户");
}
@Override
public void delete() {
System.out.println("删除了一个用户");
}
}
(2)定义了一个名为 ProxyInvocationHandler
的类,该类实现了 Java 的 InvocationHandler
接口。这个类用于创建动态代理,并处理代理对象上的方法调用。动态代理是一种在运行时创建代理类和对象的技术,而不需要在编译时生成额外的类文件。
InvocationHandler
是Java动态代理的核心接口,用于处理代理实例上的方法调用,并将其转发到指定的对象。
import java.lang.annotation.Target;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyInvocationHandler implements InvocationHandler {
private Object target; // 被代理的接口
public void setTarget(Object target){
this.target = target;
}
// 生成得到的代理类:一个新的代理对象被创建出来,它实现了target的所有接口,并且所有的方法调用都会被转发到当前对象的invoke方法
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), // 需要用来加载新创建的代理类的类加载器
target.getClass().getInterfaces(), // 被代理的接口
this); // 当前类实现了InvocationHandler接口
}
// 处理代理实例,并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
Object result = method.invoke(target, args);
return result;
}
public void log(String str){
System.out.println("调用了" + str + "方法");
}
}
setTarget()方法:用于设置 target
成员变量的值,即被代理的对象。
log()方法: 用于在控制台上打印日志,表明哪个方法被调用了。
getProxy()方法:使用 Proxy.newProxyInstance
方法来创建一个新的代理对象。这个代理对象实现了 target
对象所实现的所有接口,并且所有的方法调用都会被转发到当前对象的 invoke
方法。
invoke(Object proxy, Method method, Object[] args)方法:是 InvocationHandler
接口中必须实现的方法。当代理对象上的方法被调用时,这个方法会被执行。
参 数说明:
this.getClass().getClassLoader()
:这是获取当前对象类(this
)的类加载器。类加载器用于动态加载类,Proxy.newProxyInstance
的第一个参数就是需要用来加载新创建的代理类的类加载器。target.getClass().getInterfaces()
:这里获取了target
对象类实现的所有接口。Proxy.newProxyInstance
的第二个参数是一个接口数组,这些接口会被代理类实现。通常,被代理的对象(即target
)是一个接口的实现,这样代理就可以和被代理对象有相同的接口。this
:这里假定当前类实现了InvocationHandler
接口,并将当前对象(this
)作为InvocationHandler
的实例传递给Proxy.newProxyInstance
。InvocationHandler
是处理代理实例上方法调用的接口,其invoke
方法会被调用来处理每个方法调用。整个调用的结果是,一个新的代理对象被创建出来,它实现了target
的所有接口,并且所有的方法调用都会被转发到当前对象的invoke
方法。
请注意,
this
必须是一个InvocationHandler
的实现,而target
应该是一个实现了至少一个接口的对象。如果这些前提条件不满足,代码将无法正常工作。
(3)
public class Client {
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl(); // 真实角色
ProxyInvocationHandler pih = new ProxyInvocationHandler(); // 代理角色,不存在
pih.setTarget(userService); // 设置要代理的对象
UserService proxy = (UserService) pih.getProxy(); // 动态生成代理类
proxy.add();
}
}
流程:
- 创建了一个
UserServiceImpl
对象,它是真实的服务实现类(即被代理的对象) - 创建一个
ProxyInvocationHandler
对象 - 这里将
userService
设置为代理要转发方法调用的目标对象。这意味着当我们通过代理调用方法时,这些方法调用实际上会被转发到userService
对象上。 - 从
ProxyInvocationHandler
对象获取一个动态生成的代理对象
三、测试
运行代码的结果:
这是一个使用动态代理的简单例子,你可以通过它来拦截和修改对被代理对象的方法调用。这在很多场景中都非常有用,比如AOP(面向切面编程)、RPC(远程过程调用)框架等。