目录
💻业务场景
🔧应用技术
⚙概要流程
❗开发注意
服务类上标注了 自定义注解 却无法直接利用getDeclaredAnnotation 获取
*Spring代理机制
代理机制的工作原理
代理的工作机制
代理的使用场景
已获取EmrXXXServiceImpl 的Class,如何获取public class EmrXXXServiceImpl extends ServiceImpl implements EmrXXXService 泛型类型:EmrXXX,>
💻业务场景
某医院急诊系统需要于诊断列表关联相关疾病报卡,并且当诊断提交后,支持医生进行报卡的维护,可与HIS系统端的公卫下疾病报卡管理模块进行联动。
经调研,考虑各个报卡的新增操作的数据流(各个报卡对应的数据库表不一)有出入,相关业务流一致,则可利用设计模式中的策略+工厂模式,以及泛型、反射、注解等技术实现相关上层API的设计。到达代码简洁,避免硬编码,且更易于扩展和支持更多类型的报卡的目的。
利用自定义报卡标识注解将每个服务的实例化逻辑封装成不同的策略类;利用仿写Spring Bean工厂的方式,通过依赖注入和组件扫描来自动管理 Bean 的创建和查找,利用符合单一性原则自定义注解,服务类自行声明它们所支持的疾病类型,工厂可动态根据已报卡的服务去初始化报卡服务实例。
🔧应用技术
- 枚举:报卡相关固化数据的常量(提高代码可读性和可维护性、增强类型安全、简化代码)
- 泛型:API设计,以此提供更加灵活和通用的接口,实现接口通用。注意泛型擦除机制
- 反射:灵活获取指定类对象,进行类之父类上的泛型Type的获取等操作
- 注解:是标识各个报卡服务,支持后续Bean工厂初始化集合存储报卡Service Bean
- 框架:Spring、Mybatis Plus
⚙概要流程
❗开发注意
服务类上标注了 自定义注解 却无法直接利用getDeclaredAnnotation
获取
已知注解于类的声明处,并且继承链无误(Java 的注解默认不会被继承,除非使用 @Inherited
元注解),注解作用范围为 ElementType.TYPE
,并且保留策略是 RetentionPolicy.RUNTIME
。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SupportedDiseaseType {String value();
}
最终定位错误为Spring 使用代理机制来管理 Bean,从而导致注解无法直接通过 getDeclaredAnnotation
获取。特别是当使用 CGLIB 代理时,代理类不会继承原始类的注解。
则利用Spring 提供了 AnnotatedElementUtils
工具类,它可以更可靠地获取注解,包括处理代理类的情况。
SupportedDiseaseType annotation = AnnotatedElementUtils.findMergedAnnotation(service.getClass(), SupportedDiseaseType.class);
*Spring代理机制
Spring 使用代理机制来管理 Bean,主要是为了实现 AOP(面向切面编程)和事务管理等功能。Spring 的代理机制允许在不修改原有代码的基础上,动态地为目标对象添加额外的功能,比如日志记录、性能监控、事务管理等。
代理机制的工作原理
Spring 中的代理有两种常见的方式:
1. JDK 动态代理(基于接口):
- 通过反射机制创建一个实现目标对象接口的代理类,并将代理类与目标对象绑定。
- 适用于目标类实现了接口的情况。
2. CGLIB 代理(基于子类):
- 通过继承目标类,动态创建一个目标类的子类,并在该子类中织入增强代码。
- 适用于目标类没有实现接口的情况,或者目标类没有实现接口但需要增强的情况。
Spring 通过这两种代理方式在运行时动态地生成代理对象,来增强目标对象的行为。代理对象和目标对象的使用是透明的,开发者只需要关注接口或原有类,Spring 会自动为其注入代理功能。
代理的工作机制
- **生成代理对象**:Spring 使用 JDK 动态代理或 CGLIB 代理创建一个代理对象,这个对象通常是目标对象的一个包装。
- **拦截方法调用**:每次调用代理对象的方法时,Spring 会通过代理对象执行相关的增强逻辑,例如日志、事务、权限控制等。
- **目标方法执行**:增强逻辑执行完毕后,代理对象会调用目标对象的实际方法。
代理的使用场景
1. AOP(面向切面编程):
- 使用 Spring 的 AOP 可以在运行时动态地为对象添加横切关注点(如日志、事务等),而不修改目标对象的源代码。
2. 事务管理:
- Spring 可以通过代理机制来自动管理数据库事务,确保在方法执行过程中根据需要进行事务的开启、提交或回滚。
3. 懒加载:
- 代理对象可以通过懒加载的方式,在实际调用方法时才去创建目标对象,从而提高系统性能。
已获取EmrXXXServiceImpl 的Class,如何获取public class EmrXXXServiceImpl extends ServiceImpl<EmrXXXMapper, EmrXXX> implements EmrXXXService 泛型类型:EmrXXX
直接上代码!
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;public class Main {public static void main(String[] args) {// 假设你已经通过 AOP 得到了 `EmrXXXServiceImpl` 的 Class 对象Class<?> targetClass = EmrXXXServiceImpl.class;// 获取父类的类型参数Type genericSuperclass = targetClass.getGenericSuperclass();// 检查是否是带有泛型的类if (genericSuperclass instanceof ParameterizedType) {ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;// 获取泛型参数类型Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();// 这里假设第一个泛型参数是 `EmrXXXMapper`// 第二个泛型参数是 `EmrXXX`Type secondGenericType = actualTypeArguments[1];// 输出泛型类型的类if (secondGenericType instanceof Class<?>) {Class<?> EmrXXXClass = (Class<?>) secondGenericType;System.out.println("泛型中的 EmrXXX 的类是: " + EmrXXXClass.getName());}}}
}