MST

星途 面试题库

面试题:Java动态代理中InvocationHandler的深度剖析及应用

在Java动态代理中,`InvocationHandler`起着关键作用。请详细说明`InvocationHandler`接口的各个方法的作用及工作机制,并且举例说明如何在一个实际的企业级项目场景(如事务管理、权限控制)中利用`InvocationHandler`实现代理逻辑。
21.1万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

InvocationHandler接口方法作用及工作机制

InvocationHandler接口只有一个方法:

Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
  • 方法作用
    • 当通过代理对象调用方法时,实际会调用到该invoke方法。
    • proxy:指被代理的对象,在实际使用中可以用于某些情况下对代理对象自身的操作,但通常较少使用。
    • method:指被代理对象上被调用的方法对象,通过该对象可以获取方法的名称、参数类型等信息。
    • args:指调用方法时传入的参数数组,如果方法没有参数则为null
  • 工作机制:在动态代理创建代理对象时,会将InvocationHandler实例关联到代理对象上。当代理对象的方法被调用,JVM会将方法调用转发到InvocationHandlerinvoke方法中。在invoke方法内,可以根据methodargs进行自定义的逻辑处理,比如方法调用前的预处理,方法调用后的后处理等,处理完成后返回相应的结果。

在事务管理场景中利用InvocationHandler实现代理逻辑

假设我们有一个简单的服务层接口UserService及其实现类UserServiceImpl,现在要在UserService方法调用前后添加事务管理逻辑。

  1. 定义服务层接口和实现类
public interface UserService {
    void addUser(String username);
}

public class UserServiceImpl implements UserService {
    @Override
    public void addUser(String username) {
        // 实际添加用户逻辑,这里简单打印
        System.out.println("Adding user: " + username);
    }
}
  1. 定义事务管理工具类
public class TransactionManager {
    public void beginTransaction() {
        System.out.println("Transaction started.");
    }

    public void commitTransaction() {
        System.out.println("Transaction committed.");
    }

    public void rollbackTransaction() {
        System.out.println("Transaction rolled back.");
    }
}
  1. 实现InvocationHandler
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class TransactionInvocationHandler implements InvocationHandler {
    private Object target;
    private TransactionManager transactionManager;

    public TransactionInvocationHandler(Object target, TransactionManager transactionManager) {
        this.target = target;
        this.transactionManager = transactionManager;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        transactionManager.beginTransaction();
        try {
            Object result = method.invoke(target, args);
            transactionManager.commitTransaction();
            return result;
        } catch (Exception e) {
            transactionManager.rollbackTransaction();
            throw e;
        }
    }
}
  1. 创建代理对象
import java.lang.reflect.Proxy;

public class TransactionProxyFactory {
    public static Object createTransactionProxy(Object target, TransactionManager transactionManager) {
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new TransactionInvocationHandler(target, transactionManager)
        );
    }
}
  1. 测试事务管理代理
public class Main {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        TransactionManager transactionManager = new TransactionManager();
        UserService proxy = (UserService) TransactionProxyFactory.createTransactionProxy(userService, transactionManager);
        proxy.addUser("testUser");
    }
}

在权限控制场景中利用InvocationHandler实现代理逻辑

假设我们有一个DocumentService接口及其实现类,现在要在调用DocumentService方法前进行权限检查。

  1. 定义服务层接口和实现类
public interface DocumentService {
    void readDocument(String documentId);
}

public class DocumentServiceImpl implements DocumentService {
    @Override
    public void readDocument(String documentId) {
        System.out.println("Reading document with id: " + documentId);
    }
}
  1. 定义权限检查工具类
public class PermissionChecker {
    public boolean hasPermission(String userId, String action) {
        // 这里简单返回true模拟有权限,实际需要根据业务逻辑检查
        return true;
    }
}
  1. 实现InvocationHandler
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class PermissionInvocationHandler implements InvocationHandler {
    private Object target;
    private PermissionChecker permissionChecker;
    private String userId;

    public PermissionInvocationHandler(Object target, PermissionChecker permissionChecker, String userId) {
        this.target = target;
        this.permissionChecker = permissionChecker;
        this.userId = userId;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String action = method.getName();
        if (permissionChecker.hasPermission(userId, action)) {
            return method.invoke(target, args);
        } else {
            throw new RuntimeException("No permission to perform this action.");
        }
    }
}
  1. 创建代理对象
import java.lang.reflect.Proxy;

public class PermissionProxyFactory {
    public static Object createPermissionProxy(Object target, PermissionChecker permissionChecker, String userId) {
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new PermissionInvocationHandler(target, permissionChecker, userId)
        );
    }
}
  1. 测试权限控制代理
public class Main {
    public static void main(String[] args) {
        DocumentService documentService = new DocumentServiceImpl();
        PermissionChecker permissionChecker = new PermissionChecker();
        String userId = "123";
        DocumentService proxy = (DocumentService) PermissionProxyFactory.createPermissionProxy(documentService, permissionChecker, userId);
        proxy.readDocument("doc1");
    }
}