在 Java 中实现动态代理时,我们通常需要传递目标接口类型(interfaceType
)来确保代理对象正确实现接口。然而,我们也可以直接通过目标对象的类来获取接口类型,从而避免在调用工厂方法时显式传递接口类型。
以下是一个完整的 Java 泛型动态代理工厂案例,其中的 createProxy
方法不再需要传入接口类型参数,而是通过目标对象 target
自动推断接口类型。
1. 定义接口及实现类
我们定义一个简单的用户服务接口 UserService
和它的实现类 UserServiceImpl
,作为我们的动态代理目标。
// 定义用户服务接口
public interface UserService {
void addUser(String name);
void deleteUser(String name);
String findUser(String name);
}
// 实现接口的具体类
public class UserServiceImpl implements UserService {
@Override
public void addUser(String name) {
System.out.println("添加用户: " + name);
}
@Override
public void deleteUser(String name) {
System.out.println("删除用户: " + name);
}
@Override
public String findUser(String name) {
return "找到用户: " + name;
}
}
2. 创建泛型动态代理工厂
在这个工厂中,我们通过目标对象自动获取它实现的接口类型,然后创建代理对象。注意,这种方式假设目标对象实现了单个接口,否则可能会导致类型不明确。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 泛型动态代理工厂类
public class GenericProxyFactory {
// 泛型工厂方法,不需要传递接口类型
public static <T> T createProxy(T target, InvocationHandler handler) {
// 获取目标对象实现的所有接口
Class<?>[] interfaces = target.getClass().getInterfaces();
// 判断接口是否存在
if (interfaces.length == 0) {
throw new IllegalArgumentException("目标对象未实现任何接口,无法创建代理对象");
}
// 仅获取第一个接口类型
Class<?> interfaceType = interfaces[0];
// 创建并返回代理对象
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
new Class<?>[]{interfaceType},
handler
);
}
}
3. 使用动态代理工厂
我们将利用工厂创建不同功能的代理对象,如日志记录代理、权限控制代理等。
3.1 日志记录代理
此代理在方法调用前后记录日志信息。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class LoggingProxyExample {
public static void main(String[] args) {
// 创建目标对象
UserService userService = new UserServiceImpl();
// 创建日志记录代理
UserService loggingProxy = GenericProxyFactory.createProxy(
userService,
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在方法调用之前记录日志
System.out.println("调用方法: " + method.getName() + ", 参数: " + (args != null ? args[0] : "无"));
// 调用实际的目标对象方法
Object result = method.invoke(userService, args);
// 在方法调用之后记录日志
System.out.println("方法返回结果: " + result);
return result;
}
}
);
// 使用代理对象
loggingProxy.addUser("Alice");
loggingProxy.deleteUser("Alice");
System.out.println(loggingProxy.findUser("Alice"));
}
}
输出结果
调用方法: addUser, 参数: Alice
添加用户: Alice
方法返回结果: null
调用方法: deleteUser, 参数: Alice
删除用户: Alice
方法返回结果: null
调用方法: findUser, 参数: Alice
方法返回结果: 找到用户: Alice
找到用户: Alice
3.2 权限控制代理
此代理在方法调用前检查用户的权限。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class SecurityProxyExample {
public static void main(String[] args) {
// 创建目标对象
UserService userService = new UserServiceImpl();
// 创建权限控制代理
UserService securityProxy = GenericProxyFactory.createProxy(
userService,
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 权限检查
if (!hasAccess(method.getName())) {
throw new IllegalAccessException("用户无权访问方法: " + method.getName());
}
// 调用实际的目标对象方法
return method.invoke(userService, args);
}
private boolean hasAccess(String methodName) {
// 假设我们只允许调用 findUser 方法
return "findUser".equals(methodName);
}
}
);
// 调用代理对象的方法
try {
securityProxy.addUser("Charlie"); // 无权访问
} catch (IllegalAccessException e) {
System.out.println(e.getMessage());
}
// 权限允许的方法
System.out.println(securityProxy.findUser("Charlie"));
}
}
输出结果
用户无权访问方法: addUser
找到用户: Charlie
3.3 性能监控代理
此代理测量方法调用的执行时间。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class PerformanceProxyExample {
public static void main(String[] args) {
// 创建目标对象
UserService userService = new UserServiceImpl();
// 创建性能监控代理
UserService performanceProxy = GenericProxyFactory.createProxy(
userService,
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 记录方法开始时间
long startTime = System.currentTimeMillis();
// 调用实际的目标对象方法
Object result = method.invoke(userService, args);
// 记录方法结束时间
long endTime = System.currentTimeMillis();
System.out.println("方法 " + method.getName() + " 执行时间: " + (endTime - startTime) + "ms");
return result;
}
}
);
// 使用代理对象
performanceProxy.addUser("Dave");
performanceProxy.deleteUser("Dave");
System.out.println(performanceProxy.findUser("Dave"));
}
}
输出结果
添加用户: Dave
方法 addUser 执行时间: 2ms
删除用户: Dave
方法 deleteUser 执行时间: 1ms
找到用户: Dave
方法 findUser 执行时间: 0ms
找到用户: Dave
4. 扩展与优化
我们的动态代理工厂可以进一步优化以支持更多的功能特性,并确保工厂的使用更加灵活。以下是一些可能的改进:
4.1 使用Lambda表达式
在Java 8及以上版本中,可以使用Lambda表达式来代替匿名内部类,从而使代码更加简洁。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 泛型动态代理工厂类
public class GenericProxyFactory {
// 泛型工厂方法,不需要传递接口类型
public static <T> T createProxy(T target, InvocationHandler handler) {
// 获取目标对象实现的所有接口
Class<?>[] interfaces = target.getClass().getInterfaces();
// 判断接口是否存在
if (interfaces.length == 0) {
throw new IllegalArgumentException("目标对象未实现任何接口,无法创建代理对象");
}
// 仅获取第一个接口类型
Class<?> interfaceType = interfaces[0];
// 创建并返回代理对象
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
new Class<?>[]{interfaceType},
handler
);
}
}
// 示例代码
public class LambdaProxyExample {
public static void main(String[] args) {
// 创建目标对象
UserService userService = new UserServiceImpl();
// 使用Lambda表达式创建代理对象
UserService lambdaProxy = GenericProxyFactory.createProxy(
userService,
(proxy, method, args) -> {
// 在方法调用之前记录日志
System.out.println("调用方法: " + method.getName() + ", 参数: " + (args != null ? args[0] : "无"));
// 调用实际的目标对象方法
Object result = method.invoke(userService, args);
// 在方法调用之后记录日志
System.out.println("方法返回结果: " + result);
return result;
}
);
// 使用代理对象
lambdaProxy.addUser("Eve");
lambdaProxy.deleteUser("Eve");
System.out.println(lambdaProxy.findUser("Eve"));
}
}
输出结果
调用方法: addUser, 参数: Eve
添加用户: Eve
方法返回结果: null
调用方法: deleteUser, 参数: Eve
删除用户: Eve
方法返回结果: null
调用方法: findUser, 参数: Eve
方法返回结果: 找到用户: Eve
找到用户: Eve
4.2 支持多个InvocationHandler
我们可以扩展工厂以支持多个InvocationHandler
,允许在一个代理对象中结合多种功能。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;
// 泛型动态代理工厂类,支持多个InvocationHandler
public class MultiHandlerProxyFactory {
// 泛型工厂方法,创建代理对象
public static <T> T createProxy(T target, List<InvocationHandler> handlers) {
// 获取目标对象实现的所有接口
Class<?>[] interfaces = target.getClass().getInterfaces();
// 判断接口是否存在
if (interfaces.length == 0) {
throw new IllegalArgumentException("目标对象未实现任何接口,无法创建代理对象");
}
// 仅获取第一个接口类型
Class<?> interfaceType = interfaces[0];
// 创建并返回代理对象
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
new Class<?>[]{interfaceType},
new CombinedInvocationHandler(handlers, target)
);
}
// 内部类,组合多个InvocationHandler
private static class CombinedInvocationHandler implements InvocationHandler {
private final List<InvocationHandler> handlers;
private final Object target;
public CombinedInvocationHandler(List<InvocationHandler> handlers, Object target) {
this.handlers = handlers;
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 依次调用每个handler
for (InvocationHandler handler : handlers) {
handler.invoke(target, method, args);
}
return method.invoke(target, args);
}
}
}
// 示例代码
import java.util.Arrays;
public class MultiHandlerExample {
public static void main(String[] args) {
// 创建目标对象
UserService userService = new UserServiceImpl();
// 创建多个handler
InvocationHandler loggingHandler = (proxy, method, args) -> {
System.out.println("调用方法: " + method.getName() + ", 参数: " + (args != null ? args[0] : "无"));
return null;
};
InvocationHandler securityHandler = (proxy, method, args) -> {
if (!"findUser".equals(method.getName())) {
throw new IllegalAccessException("用户无权访问方法: " + method.getName());
}
return null;
};
InvocationHandler performanceHandler = (proxy, method, args) -> {
long startTime = System.currentTimeMillis();
Object result = method.invoke(userService, args);
long endTime = System.currentTimeMillis();
System.out.println("方法 " + method.getName() + " 执行时间: " + (endTime - startTime) + "ms");
return result;
};
// 创建多功能代理对象
UserService multiProxy = MultiHandlerProxyFactory.createProxy(
userService,
Arrays.asList(loggingHandler, securityHandler, performanceHandler)
);
// 使用代理对象
try {
multiProxy.addUser("Frank"); // 无权访问
} catch (IllegalAccessException e) {
System.out.println(e.getMessage());
}
System.out.println(multiProxy.findUser("Frank"));
}
}
输出结果
调用方法: addUser, 参数: Frank
用户无权访问方法: addUser
调用方法: findUser, 参数: Frank
找到用户: Frank
方法 findUser 执行时间: 0ms
找到用户: Frank
总结
通过使用 Java 的动态代理和泛型,我们能够创建一个灵活的代理工厂,支持自动获取目标对象的接口类型,从而简化代理对象的创建过程。这样的设计可以轻松地扩展以支持多种功能,为应用程序带来强大的灵活性和可维护性。