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;}@Overridepublic 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;}@Overridepublic Class<?> getObjectType() {return interfaceType;}@Overridepublic boolean isSingleton() {return true;}
}
这里最核心的代码就是 getObject 方法,这里我们使用 jdk 的代理方法,代理了接口。
2.2 实现 InvocationHandler
这个是代理类真正工作的类。
/*** 自定义调用处理器 - 记录方法执行时间*/
public class TimingInvocationHandler implements InvocationHandler {@Overridepublic 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;}
}
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接口的代理*/@Beanpublic 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 {@Autowiredprivate 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 {@Resourceprivate BusinessService businessService;@Testpublic void executeBusinessLogic(){businessService.executeBusinessLogic();}}