Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/http/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java spring中条件注释的排序计算_Java_Spring_Spring Boot_Spring Annotations_Operator Precedence - Fatal编程技术网

Java spring中条件注释的排序计算

Java spring中条件注释的排序计算,java,spring,spring-boot,spring-annotations,operator-precedence,Java,Spring,Spring Boot,Spring Annotations,Operator Precedence,我有三个类,所有这些类都需要根据@ConditionalOnExpression注释启用/禁用。所有这些都在单独的.java文件中 例: 现在,我在另一个类中有一个init函数,它首先执行,我将enable/disable值设置为类CxProperties。 注意:假设所有设置器都是静态的 class setvalues{ public void init(){ /*Read config values from a file*/

我有三个类,所有这些类都需要根据@ConditionalOnExpression注释启用/禁用。所有这些都在单独的.java文件中

例:

现在,我在另一个类中有一个init函数,它首先执行,我将enable/disable值设置为类CxProperties。 注意:假设所有设置器都是静态的

class setvalues{

        public void init(){
             /*Read config values from a file*/
             CxProperties.setAEnabled(true/false);
             CxProperties.setBEnabled(true/false);
             CxProperties.setCEnabled(true/false);
        }
}
现在,这些条件的评估发生在程序开始时(甚至在执行init之前),此时根本没有设置启用/禁用

在春天,有没有什么可能的方法来对这些条件进行评估,比如说,在某个执行点之后进行评估


非常感谢任何提示。

我建议您不要为此使用
@ConditionalOnExpression
注释

考虑改用
@PreAuthorize
。是的,是spring security的

这样,您就可以保护每个未启用的服务不被使用,并动态切换其启用/禁用状态:

@SpringBootApplication
public class So44462763Application {

    public static void main(String[] args) {
        SpringApplication.run(So44462763Application.class, args);
    }

    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)  // <-- this is required for PreAuthorize annotation to work
    public static class SecurityConfiguration extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable();
        }
    }

    interface CxProperties {
        boolean isServiceAEnabled();
        boolean isServiceBEnabled();
        boolean isServiceCEnabled();

        boolean enableService(String service);
        boolean disableService(String service);
    }

    @Component("cx")
    public static class CxPropertiesImpl implements CxProperties {
        private static final ConcurrentHashMap<String, Boolean> services = new ConcurrentHashMap<>(); //could be database/redis/property file/etc

        @PostConstruct
        private void init() {
            //services.put("serviceA", true); //initial population from property file/network resource/whatever
        }

        public boolean isServiceAEnabled() {
            return services.getOrDefault("serviceA", false);
        }

        public boolean isServiceBEnabled() {
            return services.getOrDefault("serviceB", false);
        }

        public boolean isServiceCEnabled() {
            return services.getOrDefault("serviceC", false);
        }
        //just a sample how you can dynamically control availability for each service
        @Override
        public boolean enableService(String service) {
            services.put(service, true);
            return services.getOrDefault(service, false);
        }

        @Override
        public boolean disableService(String service) {
            services.put(service, false);
            return services.getOrDefault(service, false);
        }
    }

    interface BusinessService {
        String doSomething();
    }

    @Service("serviceA")
    @PreAuthorize("@cx.serviceAEnabled")
    public static class ServiceA implements BusinessService {

        @Override
        public String doSomething() {
            return this.getClass().getSimpleName() + " doing some work";
        }
    }

    @Service("serviceB")
    @PreAuthorize("@cx.serviceBEnabled")
    public static class ServiceB implements BusinessService {

        @Override
        public String doSomething() {
            return this.getClass().getSimpleName() + " doing some work";
        }
    }

    @Service("serviceC")
    @PreAuthorize("@cx.serviceCEnabled")
    public static class ServiceC implements BusinessService {

        @Override
        public String doSomething() {
            return this.getClass().getSimpleName() + " doing some work";
        }
    }

    @RestController
    @RequestMapping("/api/work")
    public static class WorkApi {
        private static final Logger log = LoggerFactory.getLogger(WorkApi.class);

        private final List<BusinessService> businessServices;

        @Autowired
        public WorkApi(final List<BusinessService> businessServices) {
            this.businessServices = businessServices;
        }

        @GetMapping
        public String doWork() {
            final StringJoiner joiner = new StringJoiner(",");
            for (BusinessService service : businessServices) {
                try {
                    joiner.add(service.doSomething());
                } catch (AccessDeniedException e) {
                    log.warn("Service {} is disabled.", service);
                }
            }
            return joiner.toString();
        }
    }

    @RestController
    @RequestMapping("/api/control")
    public static class ControlApi {

        private final CxProperties cxProperties;

        @Autowired
        public ControlApi(final CxProperties cxProperties) {
            this.cxProperties = cxProperties;
        }

        @PostMapping("{service}/enable")
        public boolean enable(@PathVariable("service") String serviceName) {
            return cxProperties.enableService(serviceName);
        }

        @PostMapping("{service}/disable")
        public boolean disable(@PathVariable("service") String serviceName) {
            return cxProperties.disableService(serviceName);
        }
    }
}
使用这种方法,即使不重新启动,也可以控制服务的可访问性


所有这些都可以在没有spring security的情况下完成,但需要更多的手动操作,可能会略微降低代码的整体可读性。

那么
@ConditionalOnProperty
呢?请看,我没有使用任何application.yml或属性文件。我从项目中定制的文件中读取配置数据。所以需要对类对象求值。但是无论如何,即使在@ConditionalOnProperty的情况下,我们如何延迟/订购评估?我认为这是不可能的,至少以您描述的方式是不可能的。但这可能是一些变通办法。你能解释一下你想在更大范围内实现什么吗?作为我们项目的一部分,我们提供三种服务。用户可以从自定义UI启用或禁用其中任何一个,然后自定义UI使用这些值创建自定义配置文件。我们的后端进程是一个守护进程,一旦配置被更改,它就会被重新启动。当这个过程(jar)启动时,上面提到的init方法具有读取配置文件的逻辑,并将值设置为CxProperties类。现在,我希望在调用init方法后有条件地启用这三个服务(3个类)。它是一个守护进程,因此一旦启动,它应该从文件中读取值并启用/禁用该类,然后它不会以任何形式接受其他输入。动态切换服务是一件好事,但有没有其他方法可以做到这一点?就像在ConditionalOnPression求值之前调用init方法(读取配置文件)一样,您可以在CxProperties中实现interface
ApplicationListener
,然后在ApplicationEvent(ContextRefreshedEvent ContextRefreshedEvent)方法中加载属性。这是spring应用程序的最新可能状态,当整个应用程序上下文完全初始化时会发生此事件。
@SpringBootApplication
public class So44462763Application {

    public static void main(String[] args) {
        SpringApplication.run(So44462763Application.class, args);
    }

    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)  // <-- this is required for PreAuthorize annotation to work
    public static class SecurityConfiguration extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable();
        }
    }

    interface CxProperties {
        boolean isServiceAEnabled();
        boolean isServiceBEnabled();
        boolean isServiceCEnabled();

        boolean enableService(String service);
        boolean disableService(String service);
    }

    @Component("cx")
    public static class CxPropertiesImpl implements CxProperties {
        private static final ConcurrentHashMap<String, Boolean> services = new ConcurrentHashMap<>(); //could be database/redis/property file/etc

        @PostConstruct
        private void init() {
            //services.put("serviceA", true); //initial population from property file/network resource/whatever
        }

        public boolean isServiceAEnabled() {
            return services.getOrDefault("serviceA", false);
        }

        public boolean isServiceBEnabled() {
            return services.getOrDefault("serviceB", false);
        }

        public boolean isServiceCEnabled() {
            return services.getOrDefault("serviceC", false);
        }
        //just a sample how you can dynamically control availability for each service
        @Override
        public boolean enableService(String service) {
            services.put(service, true);
            return services.getOrDefault(service, false);
        }

        @Override
        public boolean disableService(String service) {
            services.put(service, false);
            return services.getOrDefault(service, false);
        }
    }

    interface BusinessService {
        String doSomething();
    }

    @Service("serviceA")
    @PreAuthorize("@cx.serviceAEnabled")
    public static class ServiceA implements BusinessService {

        @Override
        public String doSomething() {
            return this.getClass().getSimpleName() + " doing some work";
        }
    }

    @Service("serviceB")
    @PreAuthorize("@cx.serviceBEnabled")
    public static class ServiceB implements BusinessService {

        @Override
        public String doSomething() {
            return this.getClass().getSimpleName() + " doing some work";
        }
    }

    @Service("serviceC")
    @PreAuthorize("@cx.serviceCEnabled")
    public static class ServiceC implements BusinessService {

        @Override
        public String doSomething() {
            return this.getClass().getSimpleName() + " doing some work";
        }
    }

    @RestController
    @RequestMapping("/api/work")
    public static class WorkApi {
        private static final Logger log = LoggerFactory.getLogger(WorkApi.class);

        private final List<BusinessService> businessServices;

        @Autowired
        public WorkApi(final List<BusinessService> businessServices) {
            this.businessServices = businessServices;
        }

        @GetMapping
        public String doWork() {
            final StringJoiner joiner = new StringJoiner(",");
            for (BusinessService service : businessServices) {
                try {
                    joiner.add(service.doSomething());
                } catch (AccessDeniedException e) {
                    log.warn("Service {} is disabled.", service);
                }
            }
            return joiner.toString();
        }
    }

    @RestController
    @RequestMapping("/api/control")
    public static class ControlApi {

        private final CxProperties cxProperties;

        @Autowired
        public ControlApi(final CxProperties cxProperties) {
            this.cxProperties = cxProperties;
        }

        @PostMapping("{service}/enable")
        public boolean enable(@PathVariable("service") String serviceName) {
            return cxProperties.enableService(serviceName);
        }

        @PostMapping("{service}/disable")
        public boolean disable(@PathVariable("service") String serviceName) {
            return cxProperties.disableService(serviceName);
        }
    }
}
$ curl -u user:123 -XGET 'localhost:8080/api/work'
$ curl -u user:123 -XPOST 'localhost:8080/api/control/serviceC/enable'
true% 
$ curl -u user:123 -XGET 'localhost:8080/api/work'                    
ServiceC doing some work%
$ curl -u user:123 -XPOST 'localhost:8080/api/control/serviceA/enable'
true%
$ curl -u user:123 -XGET 'localhost:8080/api/work'                    
ServiceA doing some work,ServiceC doing some work%