Java 如何在spring中动态禁用特定API?

Java 如何在spring中动态禁用特定API?,java,spring,annotations,Java,Spring,Annotations,我有一个标志DISABLE_flag,我想用它来控制不同控制器中的多个特定API @RestController public final class Controller1 { @RequestMapping(value = "/foo1", method = RequestMethod.POST) public String foo1() } @RestController public final class Controller2 { @RequestMappin

我有一个标志
DISABLE_flag
,我想用它来控制不同控制器中的多个特定API

@RestController
public final class Controller1 {
    @RequestMapping(value = "/foo1", method = RequestMethod.POST)
    public String foo1()
}
@RestController
public final class Controller2 {
    @RequestMapping(value = "/foo2", method = RequestMethod.POST)
    public String foo2()
}

我可以使用拦截器来处理所有的URL。有没有一种简单的方法可以像注释一样做到这一点?

我不认为有直接的方法可以禁用构造的请求映射,但我们可以在某些条件下以多种方式禁用API

以下是通过spring概要文件或JVM属性禁用的两种方法

public class SampleController {
    @Autowired
    Environment env;

    @RequestMapping(value = "/foo", method = RequestMethod.POST)
    public String foo(HttpServletResponse response) {
        // Using profile
        if (env.acceptsProfiles("staging")) {
            response.setStatus(404);
            return "";
        }

        // Using JVM options
        if("true".equals(System.getProperty("DISABLE_FOO"))) {
            response.setStatus(404);
            return "";
        }

        return "";
    }
}
如果您认为使用云配置的未来解决方案是最好的方法

使用条件组件

这允许使用条件构建bean,如果条件在启动时失败,则永远不会构建整个组件。将所有可选请求映射分组到新控制器并添加条件注释

@Conditional(ConditionalController.class)
public class SampleController {
    @Autowired
    Environment env;

    @RequestMapping(value = "/foo", method = RequestMethod.POST)
    public String foo(HttpServletResponse response) {
        return "";
    }

    public static class ConditionalController implements Condition {

        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            return context.getEnvironment().acceptsProfiles("staging"); // Or whatever condition
        }

    }
}

您可以使用AOP来做类似的事情

创建自己的注释

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Maybe { }
以及相应的方面

@Aspect
public class MaybeAspect {

  @Pointcut("@annotation(com.example.Maybe)")
  public void callMeMaybe() {}

  @Around("callMeMaybe()")
  public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    // do your logic here..
    if(DISABLE_FOO) {
      // do nothing ? throw exception?
      // return null;
      throw new IllegalStateException();
    } else {
      // process the request normally
      return joinPoint.proceed();
    }
  }
}

您可以通过使用弹簧配置文件使用注释来解决此问题。您定义了两个配置文件,一个用于启用标志,另一个用于禁用标志。您的示例如下所示:

@Profile(“禁用的_标志”)
@RestController
公共期末班控制员1{
@RequestMapping(value=“/foo1”,method=RequestMethod.POST)
公共字符串foo1()
}
@配置文件(“已启用的_标志”)
@RestController
公共期末班控制员2{
@RequestMapping(value=“/foo2”,method=RequestMethod.POST)
公共字符串foo2()
}
以下是此功能的spring框架文档链接:

我按如下方式操作:

@Retention(RUNTIME)
@Target(ElementType.METHOD)
public @interface DisableApiControl {
}
这个类是我的定制语句。在使用AOP之后:

对于AbstractBaseServiceImpl:

public abstract class AbstractBaseServiceImpl {

    private static boolean disableCheck = false;

    public void setDisableChecker(boolean checkParameter) {
        disableCheck = checkParameter;
    }

    public boolean getDisableChecker() {
        return disableCheck;
    }
}
:上述课程旨在提供动态结构

@Aspect
@Component
public class DisableApiControlAspect extends AbstractBaseServiceImpl {

    @Autowired
    private HttpServletResponse httpServletResponse;

    @Pointcut(" @annotation(disableMe)")
    protected void disabledMethods(DisableApiControl disableMe) {

        // comment line 
        
    }

    @Around("disabledMethods(disableMe)")
    public Object dontRun(ProceedingJoinPoint joinPoint, DisableApiControl disableMe) throws Throwable {
        if (getDisableChecker()) {
            httpServletResponse.sendError(HttpStatus.NOT_FOUND.value(), "Not found");
            return null;
        } else {
            return joinPoint.proceed();
        }
    }
}
检查器参数此时添加为全局。如果在需要时将该值指定为true/false,则其余部分将更容易实现

@GetMapping("/map")
@DisableApiControl
public List<?> stateMachineFindMap() {
    return new ArrayList<>;
}
@GetMapping(“/map”)
@解除控制
公共列表stateMachineFindMap(){
返回新的ArrayList;
}

问题是我必须使用该标志来控制多个API。那么,仅仅使用拦截器似乎更容易。@伊利用条件注释更新了另一种方法。我也更新了我的问题。我无法将这些API组合在一起。