spring boot中通过开发jar包,检查目标应用的注解的非法使用

来源:互联网 发布:法国达索软件 编辑:程序博客网 时间:2024/05/24 05:45

背景

在spring boot工程中,@FeignClient和@RequestMapping可能被错误得加到同一个方法上,当用户这么使用的情况下,如何能够在程序启动的过程中警告用户并抛出异常呢?本文将给出这个问题的解决方法。

思路

  1. 通过提供一个jar包,任何引入该jar包的应用在启动过程中自动执行注解使用检查
  2. jar包需要添加一个Listener,监听应用启动的过程,执行检查工作

步骤

  1. 实现注解检查Listener
  2. 启动spring boot自动配置
  3. 目标应用启动@EnableAutoCongiguration自动配置

代码

Listener定义
@Component@ConditionalOnClass(FeignClient.class)public class AnnotationCheckListener implements ApplicationListener<ContextRefreshedEvent> {  @Autowired  public ApplicationContext applicationContext;  @Override  public void onApplicationEvent(ContextRefreshedEvent event) {    String[] beanNamesForAnnotation = applicationContext.getBeanNamesForAnnotation(RequestMapping.class);    Arrays.stream(beanNamesForAnnotation)        .filter(beanName -> applicationContext.findAnnotationOnBean(beanName, FeignClient.class) != null)        .forEach(beanName -> throwAnnotationConfigurationException(beanName));  }  static void throwAnnotationConfigurationException(String beanName) {    throw new AnnotationConfigurationException("Cannot have both @RequestMapping and @FeignClient on " + beanName);  }}
配置spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.swagger.starter.AnnotationCheckListener

总结

  1. SpringFactoriesLoader
    SpringFactoriesLoader
     loads and instantiates factories of a given type from "META-INF/spring.factories" files which may be present in multiple JAR files in the classpath. The spring.factories file must be in Properties format, where the key is the fully qualified name of the interface or abstract class, and the value is a comma-separated list of implementation class names.
  2. @EnableAutoCongiguration Spring Boot提供的@EnableAutoCongiguration功能很强大,所有的配置似乎都被包含进来而无需开发者显式声明。EnableAutoConfigurationImportSelector使用的是spring-core模块中的SpringFactoriesLoader#loadFactoryNames()方法,它的作用是在类路径上扫描并加载META-INF/spring.factories文件中定义的类。
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Import({ EnableAutoConfigurationImportSelector.class,        AutoConfigurationPackages.Registrar.class })public @interface EnableAutoConfiguration {    /**     * Exclude specific auto-configuration classes such that they will never be applied.     */    Class<?>[] exclude() default {};}

备选

@Component@ConditionalOnClass(FeignClient.class)@Slf4jpublic class FeignClientBeanProcessor implements BeanPostProcessor{  @Override  public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {    return null;  }  @Override  public Object postProcessAfterInitialization(Object bean, String s) throws BeansException {    final Class<?> beanClass = bean.getClass();    if(beanClass.isAnnotationPresent(RequestMapping.class) && beanClass.isAnnotationPresent(FeignClient.class)) {      log.error("RequestMapping and FeignClient annotation could not be added to the same class.");      return new BeanCreationException("RequestMapping and FeignClient annotation could not be added to the same " +          "class");    }    return null;  }}



0 0
原创粉丝点击