1.概述
我们在使用mybatis 的时候,我们发现实际上我们就是使用接口,没有实现类,但是spring 容器一样可以正常使用接口操作数据,这个是怎么做到的呢,实际上这里使用了代理模式和 spring的FactoryBean。
本文就用一个简单的例子来实现一个接口注入。
2.实现过程
2.1实现接口代理工厂
package com.redxun.proxydemo.config;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
/**
* 接口代理工厂 - 用于创建基于接口的动态代理实例
* @param <T> 接口类型
*/
public class InterfaceProxyFactory<T> implements FactoryBean<T> {
private final Class<T> interfaceType;
private InvocationHandler customInvocationHandler;
public InterfaceProxyFactory(Class<T> interfaceType) {
if (!interfaceType.isInterface()) {
throw new IllegalArgumentException("Class " + interfaceType.getName() + " is not an interface");
}
this.interfaceType = interfaceType;
}
/**
* 设置自定义的调用处理器
*/
public void setCustomInvocationHandler(InvocationHandler customInvocationHandler) {
this.customInvocationHandler = customInvocationHandler;
}
@Override
public T getObject() {
// 使用JDK动态代理创建接口实例
T t = (T) Proxy.newProxyInstance(
interfaceType.getClassLoader(),
new Class<?>[]{interfaceType},
createInvocationHandler()
);
return t;
}
private InvocationHandler createInvocationHandler() {
// 优先使用自定义的调用处理器
if (customInvocationHandler != null) {
return customInvocationHandler;
}
// 默认的调用处理器
return null;
}
@Override
public Class<?> getObjectType() {
return interfaceType;
}
@Override
public boolean isSingleton() {
return true;
}
}
这里最核心的代码就是 getObject 方法,这里我们使用 jdk 的代理方法,代理了接口。
2.2 实现 InvocationHandler
这个是代理类真正工作的类。
/**
* 自定义调用处理器 - 记录方法执行时间
*/
public class TimingInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long startTime = System.currentTimeMillis();
try {
System.out.println("【性能监控】开始执行: " + method.getName());
// 这里可以添加真实的业务逻辑,或者返回模拟数据
Object result = simulateBusinessLogic(method, args);
return result;
} finally {
long endTime = System.currentTimeMillis();
System.out.println("【性能监控】方法 " + method.getName() + " 执行耗时: " + (endTime - startTime) + "ms");
}
}
private Object simulateBusinessLogic(Method method, Object[] args) {
// 模拟业务逻辑,返回适当的默认值
Class<?> returnType = method.getReturnType();
if (returnType == String.class) {
return "模拟返回结果";
} else if (returnType == int.class || returnType == Integer.class) {
return 42;
} else if (returnType == boolean.class || returnType == Boolean.class) {
return true;
}
return null;
}
}
当用户调用接口方法的时候,实际调用代理方法。
# proxy 代理服务类
# mothod调用的方法
# args 如果有参数就使用
Object invoke(Object proxy, Method method, Object[] args)
2.3 增加一个接口
#用户实体类
public class User {
private Long id;
private String name;
// getters and setters
}
# 用户接口类
public interface UserService {
String getUserById(Long id);
boolean saveUser(User user);
User[] listUsers();
void deleteUser(Long id);
}
2.4 实例化代理类并注入
@Configuration
public class ProxyConfig {
/**
* 注册UserService接口的代理
*/
@Bean
public InterfaceProxyFactory<UserService> userServiceProxy() {
InterfaceProxyFactory<UserService> factory = new InterfaceProxyFactory<>(UserService.class);
// 可以设置自定义的调用处理器
factory.setCustomInvocationHandler(new TimingInvocationHandler());
return factory;
}
}
- 容器中实际存储的是代理对象,而非原始的 InterfaceProxyFactory 实例
- 任何注入 UserService 的地方都会获得这个动态生成的代理实例
- 代理会通过 TimingInvocationHandler 来处理所有方法调用,实现额外的功能(如计时)
2.5注入接口类
@Service
public class BusinessService {
@Autowired
private UserService userService;
public void executeBusinessLogic() {
// 使用代理接口
String user = userService.getUserById(1L);
System.out.println("获取用户: " + user);
boolean saved = userService.saveUser(new User());
System.out.println("保存结果: " + saved);
}
}
2.6 单元测试
@SpringBootTest
public class BusinessServiceTest {
@Resource
private BusinessService businessService;
@Test
public void executeBusinessLogic(){
businessService.executeBusinessLogic();
}
}
浙公网安备 33010602011771号