You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java如何生成@Mapper、@FeignClient等注解实现?是否运行时生成类?

Java 接口动态实现:@Mapper、@FeignClient 原理与通用方案

一、@Mapper(MyBatis)与@FeignClient的实现类生成时机

两者都不会生成物理的.class文件,而是在运行时通过动态代理机制生成代理实例,来承接接口方法的具体逻辑。

1. @Mapper(MyBatis)的实现逻辑

MyBatis在应用启动时,通过MapperScannerConfigurer或MapperFactoryBean扫描所有带@Mapper注解的接口,然后用JDK动态代理为每个接口生成代理实例。当你调用Mapper接口的方法时,代理类会拦截调用,解析方法上的注解(或XML中的SQL配置),执行对应的JDBC操作,最后封装结果返回。

比如调用userMapper.selectById(1)时,代理类会把这个方法映射为对应的查询SQL,执行后将结果封装为User对象返回。

2. @FeignClient(Spring Cloud Feign)的实现逻辑

Spring Cloud Feign在应用启动阶段,扫描所有标注@FeignClient的接口,通过**Spring动态代理(默认JDK动态代理,可配置为CGLIB)**生成代理类。代理类会把接口方法的调用转换成HTTP请求:

  • 从@FeignClient的name/url属性确定目标服务地址
  • 解析@GetMapping/@PostMapping等注解确定请求路径和方法
  • 自动封装请求参数、发送HTTP请求、转换响应结果

二、Java运行时为接口生成实现类的通用方案

1. JDK动态代理

仅适用于代理接口,基于java.lang.reflect.Proxy和InvocationHandler实现:

public class ProxyHandler implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 这里实现接口方法的具体逻辑
        System.out.println("触发方法:" + method.getName());
        return "默认返回值";
    }
}

// 生成代理实例
MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
    MyInterface.class.getClassLoader(),
    new Class[]{MyInterface.class},
    new ProxyHandler()
);

2. CGLIB动态代理

可代理类(无接口也能生效),基于ASM字节码库生成目标类的子类:

public class CglibInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        // 方法执行前逻辑
        System.out.println("方法执行前");
        Object result = proxy.invokeSuper(obj, args);
        // 方法执行后逻辑
        System.out.println("方法执行后");
        return result;
    }
}

// 生成代理实例
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyClass.class);
enhancer.setCallback(new CglibInterceptor());
MyClass proxy = (MyClass) enhancer.create();

Spring、MyBatis等框架在需要代理类时会优先使用CGLIB。

3. 字节码直接生成(ASM/Javassist)

通过操作字节码直接生成类,灵活性最高但复杂度也高:

  • ASM:底层字节码操作,需要熟悉Java字节码指令
  • Javassist:提供上层API,支持用Java代码片段生成类

比如用Javassist生成接口实现类:

ClassPool pool = ClassPool.getDefault();
// 创建实现类
CtClass implClass = pool.makeClass("com.example.MyInterfaceImpl");
CtClass interfaceClass = pool.get("com.example.MyInterface");
implClass.addInterface(interfaceClass);

// 添加方法实现
CtMethod method = CtMethod.make(
    "public String sayHello() { return \"Hello from Javassist\"; }",
    implClass
);
implClass.addMethod(method);

// 加载类并创建实例
Class<?> clazz = implClass.toClass();
MyInterface instance = (MyInterface) clazz.getDeclaredConstructor().newInstance();

4. 框架封装的动态代理

很多框架已经封装了动态代理逻辑,直接使用即可:

  • Spring AOP:通过@Aspect定义切面,自动为目标类生成代理
  • MyBatis:自动为Mapper接口生成代理实例,无需手动处理

总结

  • @Mapper和@FeignClient都是在运行时生成代理实例,不会生成物理的.class文件
  • Java运行时生成接口实现类的核心是动态代理或字节码操作,常用方案包括JDK动态代理、CGLIB、ASM/Javassist,以及各类框架封装的现成方案

内容的提问来源于stack exchange,提问作者daniel-lopez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 06:00:19