【Java】泛型动态代理工厂使用案例

在 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 的动态代理和泛型,我们能够创建一个灵活的代理工厂,支持自动获取目标对象的接口类型,从而简化代理对象的创建过程。这样的设计可以轻松地扩展以支持多种功能,为应用程序带来强大的灵活性和可维护性。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java泛型在方法中的使用非常广泛,它提供了一种在方法级别上使用类型安全的能力。通过泛型,我们可以在编译时期检测类型的正确性,避免在运行时期发生类型转换的异常。 一个常见的泛型方法的例子是数组排序。以下是一个使用泛型来实现排序的示例: ```java public static <T extends Comparable<T>> void bubbleSort(T[] array) { int n = array.length; T temp; for (int i = 0; i < n-1; i++) { for (int j = 0; j < n-i-1; j++) { if (array[j].compareTo(array[j+1]) > 0) { temp = array[j]; array[j] = array[j+1]; array[j+1] = temp; } } } } ``` 该方法使用泛型类型"T",它必须是可比较的类型,即实现了Comparable接口。通过使用泛型,该方法在排序任何类型的数组时都可以使用。因此,我们可以直接执行以下方法来对Integer类型数组排序: ```java Integer[] intArray = {4, 2, 1, 5, 3}; bubbleSort(intArray); ``` 另一个示例是在集合中查找最大值。以下是使用泛型来实现查找集合中最大值的示例: ```java public static <T extends Comparable<T>> T findMax(Collection<T> collection) { T max = null; for (T item : collection) { if (max == null || item.compareTo(max) > 0) { max = item; } } return max; } ``` 该方法也使用泛型类型"T",它必须是可比较的类型。该方法接受一个集合作为参数,并返回集合中的最大值。由于该方法使用泛型,因此可以在任何类型的集合中使用。 ```java List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5); Integer max = findMax(intList); ``` 总的来说,Java泛型在方法中的使用非常灵活,可以让我们以更加类型安全的方式处理不同类型的数据结构。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值