自定义注解本身不执行拷贝,需结合反射实现:通过@CopyField声明映射规则,反射遍历字段并依据ignore/deep/converter等属性动态执行深拷贝,支持嵌套路径、类型转换与循环引用防护。

Java 中注解本身不能直接实现对象属性的自动拷贝映射,它只是元数据标记;真正完成映射的是配合注解使用的反射 + 字节码处理逻辑(如手动反射、或借助 MapStruct、Dozer、BeanUtils 等框架),或者通过编译期生成代码(如 MapStruct 的注解处理器)。
用自定义注解 + 反射实现简易映射
你可以定义一个注解标记字段对应关系,再写一个通用拷贝工具类解析该注解,通过反射读取源对象属性值、写入目标对象同名或指定映射的属性中。
- 定义注解:// 指定目标字段名,支持别名映射
@Target(ElementType.FIELD)<br> @Retention(RetentionPolicy.RUNTIME)<br> public @interface MapTo {<br> String value() default "";<br> } - 在源对象字段上使用:
public class User {<br> private String userName;<br> @MapTo("nickName")<br> private String name;<br> } - 编写映射工具(核心是遍历源字段,查注解,找目标字段,set/get):
利用Field.setAccessible(true)访问私有字段,用PropertyDescriptor或直接Field.set()赋值。注意类型兼容性判断和基本类型包装处理。
用 MapStruct 实现编译期类型安全映射
这是目前最推荐的方式:声明式注解 + 编译期生成实现类,零反射开销、类型安全、支持嵌套、集合、格式转换等。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 添加依赖(Maven):
<dependency><br> <groupId>org.mapstruct</groupId><br> <artifactId>mapstruct</artifactId><br> <version>1.5.5.Final</version><br> </dependency>
- 定义映射接口并加
@Mapper:
@Mapper<br> public interface UserMapper {<br> UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);<br> UserDTO toDto(User user);<br> @Mapping(source = "name", target = "nickName")<br> UserDTO toDtoWithAlias(User user);<br> } - 编译后自动生成实现类,调用
UserMapper.INSTANCE.toDto(user)即可,性能接近手写赋值。
用 Spring BeanUtils.copyProperties 的局限与技巧
Spring 自带的 copyProperties 默认按字段名匹配拷贝,不支持注解驱动的别名映射,但可通过扩展 BeanWrapper 或自定义 PropertyEditor 增强能力。
立即学习“Java免费学习笔记(深入)”;
- 它不识别自定义注解,仅依赖 getter/setter 和字段名一致;
若需字段名不同(如userName → username),需配合setCustomEditor或改用BeanUtils.copyProperties(src, target, ignoreProperties)手动排除+补全。 - 适合简单场景(字段名完全一致、类型兼容),不适合复杂映射逻辑。
运行时动态代理或字节码增强(进阶)
如使用 ByteBuddy、Javassist,在类加载时注入 copy 方法;或基于注解生成 ASM 字节码。这类方案隐蔽性强、性能高,但开发维护成本大,一般框架内部使用(如 Lombok 的 @Data 就是编译期生成 getter/setter)。
- 普通业务项目不建议自行实现,优先选用 MapStruct 或 ModelMapper。
- 若需深度定制(如根据环境开关字段映射、运行时规则引擎驱动),可结合注解 + 策略模式 + 工厂,把映射逻辑外置配置化。

















