我在ApplicationContextProvider
(运行应用程序的入口点)中定义了这个MyApplication.java
类:
package com.company.my.app;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class ApplicationContextProvider implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public ApplicationContext getContext() {
return applicationContext;
}
}
包含restapi
包,其中包含两个类(Greeting
只是一个用于保存数据的类):
package com.company.my.app.restapi;
import com.company.my.app.ApplicationContextProvider;
import io.micrometer.core.instrument.Counter;
import java.util.concurrent.atomic.AtomicLong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class GreetingController {
private static final Logger LOG = LoggerFactory.getLogger(GreetingController.class);
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
@RequestMapping("/greeting")
public Greeting greeting(@RequestParam(value="name", defaultValue="World") String name) {
ApplicationContextProvider acp = new ApplicationContextProvider();
ApplicationContext context = acp.getContext();
if (context == null) LOG.info("app context is NULL");
Counter bean = context.getBean(Counter.class);
bean.increment();
return new Greeting(counter.incrementAndGet(),
String.format(template, name));
}
}
最后MyApplication
类是:
package com.company.my.app;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.binder.MeterBinder;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Counter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@SpringBootApplication
public class MyApplication {
@Bean
public MeterBinder exampleMeterBinder() {
return (meterRegistry) -> Counter.builder("my.counter")
.description("my simple counter")
.register(meterRegistry);
}
@Configuration
public class CounterConfig {
@Bean
public Counter simpleCounter(MeterRegistry registry) {
return registry.counter("my.counter");
}
}
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
当我运行该应用程序并在浏览器中调用http://localhost:8081/greeting
时,它会导致打印app context is NULL
崩溃。如何获得应用程序上下文?我需要它来检索简单的计数器bean。
答案 0 :(得分:0)
ApplicationContextAware
是Spring的许多早期版本中的产物,在许多现在标准的功能可用之前。在现代Spring中,如果您需要ApplicationContext
,只需像注入其他任何bean一样注入它即可。但是,几乎可以肯定,您不应该直接与它进行交互,尤其是对于getBean
,应该用注入您得到的任何东西代替它。
通常,当您需要Spring bean时,应将其声明为构造函数参数。 (如果有多个构造函数,则需要用@Autowired
进行注释,但是如果只有一个构造函数,Spring足够聪明地知道可以使用它。)如果您使用的是Lombok,则可以使用{{ 1}}自动编写构造函数,并且Groovy和Kotlin具有类似的功能。
在这里显示的Micrometer的特定情况下,将单个度量标准声明为bean是不常规的,因为它们是旨在应用于特定代码路径的细粒度工具。 (某些服务可能具有10个单独的指标来跟踪各种可能的情况。)相反,您注入@Value
并选择作为构造函数一部分所需的计数器或其他指标。在这里,您的控制器类应如下所示。 (我已经删除了重复的MeterRegistry
,但是如果有特殊原因,您可以按照显示的方式将其重新添加。)
AtomicLong