[英]How to retrieve the Application Context in Spring Boot 2
I have this ApplicationContextProvider
class defined along with the MyApplication.java
(entry point where the application is run): 我已经定义了这个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;
}
}
Have the package restapi
with two classes in it ( Greeting
is just a class to hold data): 包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));
}
}
Finally the MyApplication
class is: 最后, 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);
}
}
When I run the app and call http://localhost:8081/greeting
in my browser, it crashes printing app context is NULL
. 当我运行应用程序并在浏览器中调用http://localhost:8081/greeting
时,它会崩溃,打印app context is NULL
。 How do I get the application context? 如何获得应用程序上下文? I need it to retrieve the simple counter bean. 我需要它来检索简单的计数器bean。
ApplicationContextAware
is an artifact from much older versions of Spring, before many of the now-standard features were available. ApplicationContextAware
是Spring的许多早期版本中的产物,在许多现在标准的功能可用之前。 In modern Spring, if you need the ApplicationContext
, just inject it like any other bean. 在现代Spring中,如果需要ApplicationContext
,则像其他任何bean一样注入它。 However, you almost certainly shouldn't interact with it directly, especially for getBean
, which should be replaced with injecting whatever you were getting. 但是,您几乎可以肯定不应该直接与它进行交互,尤其是对于getBean
,应该将其替换为注入所获取的内容。
In general, when you need a Spring bean, you should declare it as a constructor parameter. 通常,当您需要Spring bean时,应将其声明为构造函数参数。 (If you have multiple constructors, you need to annotate one with @Autowired
, but if there's only a single constructor, Spring is smart enough to know to use it.) If you're using Lombok, you can use @Value
to automatically write the constructor, and Groovy and Kotlin have similar features. (如果您有多个构造函数,则需要使用@Autowired
注释一个,但是如果只有一个构造函数,Spring足够聪明,可以使用它。)如果您使用的是Lombok,则可以使用@Value
自动编写构造函数,和Groovy和Kotlin具有相似的功能。
In the specific case of Micrometer, which you're showing here, it is not conventional to declare individual metrics as beans because they are fine-grained tools intended to apply to specific code paths. 在此处显示的Micrometer的特定情况下,将单个度量标准声明为bean是不常规的,因为它们是旨在应用于特定代码路径的细粒度工具。 (Some services might have 10 separate metrics to track various possible scenarios.) Instead, you inject the MeterRegistry
and select the counters or other metrics that you need as part of your constructor. (某些服务可能具有10个单独的指标来跟踪各种可能的情况。)相反,您注入MeterRegistry
并选择作为构造函数一部分所需的计数器或其他指标。 Here, your controller class should look like this. 在这里,您的控制器类应如下所示。 (I've eliminated the duplicate AtomicLong
, but you could add it back in as you showed if there's a specific reason you need it.) (我已经删除了重复的AtomicLong
,但是如果有特定原因,您可以按照显示的方式将其重新添加。)
@RestController
public class GreetingController {
private static final Logger LOG = LoggerFactory.getLogger(GreetingController.class);
private static final String template = "Hello, %s!";
private final Counter counter;
public GreetingController(MeterRegistry meterRegistry) {
counter = meterRegistry.counter("my.counter");
}
@RequestMapping("/greeting")
public Greeting greeting(@RequestParam(value="name", defaultValue="World") String name) {
counter.increment();
long count = (long) counter.count();
return new Greeting(count, String.format(template, name));
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.