面试题答案
一键面试1. 动态代理工厂设计
- 接口定义:
首先定义一个动态代理工厂接口,例如
DynamicProxyFactory
,它包含一个创建代理实例的方法。public interface DynamicProxyFactory { <T> T createProxy(T target, InvocationHandler handler); }
- 实现类:
实现
DynamicProxyFactory
接口,使用Proxy.newProxyInstance
方法创建代理实例。public class DefaultDynamicProxyFactory implements DynamicProxyFactory { @Override public <T> T createProxy(T target, InvocationHandler handler) { return (T) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler); } }
2. 反射动态加载和配置代理逻辑
- 代理逻辑抽象:
将事务管理、权限控制、日志记录等横切关注点抽象为独立的
InvocationHandler
实现类。例如,TransactionInvocationHandler
、PermissionInvocationHandler
、LoggingInvocationHandler
。public class TransactionInvocationHandler implements InvocationHandler { private final Object target; public TransactionInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 开启事务 try { Object result = method.invoke(target, args); // 提交事务 return result; } catch (Exception e) { // 回滚事务 throw e; } } }
- 配置文件:
使用配置文件(如XML或properties)来定义哪些类需要应用哪些代理逻辑。例如,在XML文件中:
<config> <service name="UserService"> <proxy type="Transaction"/> <proxy type="Permission"/> <proxy type="Logging"/> </service> </config>
- 动态加载:
使用反射机制根据配置文件动态加载和实例化
InvocationHandler
。public class ProxyConfigLoader { public static List<InvocationHandler> loadHandlers(String serviceName) { List<InvocationHandler> handlers = new ArrayList<>(); // 解析配置文件,获取代理类型列表 List<String> proxyTypes = parseConfigFile(serviceName); for (String type : proxyTypes) { try { Class<?> handlerClass = Class.forName("com.example." + type + "InvocationHandler"); Constructor<?> constructor = handlerClass.getConstructor(Object.class); // 假设目标对象已获取 Object target = getTargetObject(serviceName); InvocationHandler handler = (InvocationHandler) constructor.newInstance(target); handlers.add(handler); } catch (Exception e) { e.printStackTrace(); } } return handlers; } }
3. 处理代理冲突和性能瓶颈
- 代理冲突:
- 优先级设定:在配置文件中为不同类型的代理逻辑设定优先级。例如,在XML配置中添加
priority
属性。
<config> <service name="UserService"> <proxy type="Transaction" priority="1"/> <proxy type="Permission" priority="2"/> <proxy type="Logging" priority="3"/> </service> </config>
- 合并逻辑:对于某些可能冲突的代理逻辑,可以考虑合并实现。例如,事务管理和日志记录在某些情况下可以在同一个
InvocationHandler
中处理。
- 优先级设定:在配置文件中为不同类型的代理逻辑设定优先级。例如,在XML配置中添加
- 性能瓶颈:
- 缓存代理实例:对于频繁使用的代理对象,使用缓存机制,避免重复创建代理实例。
public class ProxyCache { private static final Map<Object, Object> cache = new ConcurrentHashMap<>(); public static <T> T getProxy(T target, InvocationHandler handler) { if (cache.containsKey(target)) { return (T) cache.get(target); } DynamicProxyFactory factory = new DefaultDynamicProxyFactory(); T proxy = factory.createProxy(target, handler); cache.put(target, proxy); return proxy; } }
- 异步处理:对于一些非关键的横切关注点(如日志记录),可以采用异步方式处理,减少对业务方法执行的影响。可以使用Java的
CompletableFuture
或线程池来实现异步处理。
public class AsyncLoggingInvocationHandler implements InvocationHandler { private final Object target; private static final ExecutorService executor = Executors.newSingleThreadExecutor(); public AsyncLoggingInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { CompletableFuture.runAsync(() -> { // 记录日志逻辑 System.out.println("Logging method call: " + method.getName()); }, executor); return method.invoke(target, args); } }