简体   繁体   English

如何在Spring Boot 2中检索应用程序上下文

[英]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。

tl;dr: You don't need the context; tl; dr:您不需要上下文; there's a better way. 有更好的方法。

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.

相关问题 Spring boot 中的父应用程序上下文 - Parent Application Context in Spring boot 应用程序中的每个类应如何检索Spring应用程序上下文? - How should each class in an application retrieve the Spring application context? 如何从外部应用程序检索Tomcat中加载的Spring上下文 - How to retrieve Spring context loaded in Tomcat from outside application 如何在 Spring Boot 中使用应用程序上下文获取 bean - How to get bean using application context in spring boot 如何在 Spring Boot 中连接多个数据源,初始化应用程序上下文后? - How to connect to multiple datasources in Spring Boot, after the initialisation of the application context? 如何在运行时向 spring 启动应用程序上下文添加属性 - How to add properties to a spring boot application context on run time Spock Framework如何测试Spring Boot应用程序上下文 - Spock Framework how to test spring boot application context 多上下文 spring-boot 应用程序:如何为每个子上下文定义标准的 spring-boot 属性 - Multi-context spring-boot application: how to define standard spring-boot properties for each child context 使用 Camel 的 Spring Boot 无法加载应用程序上下文 - Spring Boot with Camel failed to load application context Spring Boot - Web 应用程序上下文 Bean 范围 - Spring Boot - Web Application Context Bean Scope
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM