确保从非弹簧环境加载春豆

问题描述 投票:8回答:2

我有弹簧应用程序(球衣2.6类和servlet)。

我需要从中获取Spring bean 球衣/ 非春天背景,

类似的question建议在上下文的静态包装中获取上下文

public static ApplicationContext getContext() {
    return context;
}

如何确定上下文已加载或不为null?

如果我不能,我应该等待/检查,直到它加载弹簧上下文?

如果是来电话 泽西上下文或调用bean来自 一个简单的HttpServlet代码

编辑

Jersey使用jersey-spring3依赖jar工作正常,所以我的问题只是关于Servlets的Spring控件

编辑2

该应用程序正在加载不同于@entpnerd建议的article 的弹簧

它注册了一个实现WebApplicationInitializer的Servlet

public class MyWebAppInitializer implements WebApplicationInitializer {

但是也要在web.xml中配置DispatcherServlet

DispatcherServlet如何才能在Spring加载后加载?

因为我们在其init方法上添加了自动装配功能:

WebApplicationContextUtils.getRequiredWebApplicationContext(config.getServletContext())
                    .getAutowireCapableBeanFactory().autowireBean(this);

在提供请求之前添加超时是最喜欢的解决方案还是在类加载中有一个可以处理它的调整?

编辑3

我找到了answersanswers注入,但不是为什么Spring在Servlet之前加载。

java spring servlets classloader autowired
2个回答
5
投票

这个想法很简单,虽然实际的实现可能会有所不同,具体取决于Spring引导和Jersery初始化的确切方式。

一个主意:

Spring启动,作为一个纯粹的运行时框架,就是正确加载应用程序上下文(从问题的角度来看)。

所以,底线,当它加载时,内存中有一个应用程序上下文,并且可以从这个应用程序上下文中访问bean。

现在,既然你说Jersey不是spring / spring-boot驱动的,那么这个应用程序上下文必须可以通过Jersey的某种静态全局变量来访问,它非常难看但是应该可行。

所以这个想法有两个步骤:

  1. 将应用程序上下文引用放到可从Jersey访问的某个静态持有者。
  2. 在Jersey组件的某些基础架构级代码中读取此值。

可能的实施

从技术上讲,第一步可以通过实现某种弹簧启动监听器来完成,该监听器将应用程序上下文存储在某种单例中:

enum ApplicationContextHolder {
   INSTANCE;
    private ApplicationContext ctx;
    void setApplicationContext(ApplicationContext ctx) {
        this.ctx = ctx;
    }

    ApplicationContext getCtx() {
        return this.ctx;
    }

}


// and a listener (spring boot provides many ways to register one, but the 
// implementation should be something like this):
// The main point is that its managed by spring boot, and hence and access to 
// the application context
class StartupListener implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {           
             ApplicationContextHolder
             .INSTANCE
             .setApplicationContext(event.getApplicationContext());
    }
}

现在第2步是:

class MyJerseyOrWhateverComponentThatWantsToAccessApplicationContext {

    public void foo() {
       ApplicationContext ctx = ApplicationContextHolder.INSTANCE.getCtx();
       ... 
       ctx.getBean(...);
    }
}

0
投票

因此,可行的解决方案可能分两个阶段进行:

  1. Spring bean获取ApplicationContext实例并将其发送到Spring上下文之外的静态单例。
  2. 您的独立servlet从静态单例中获取ApplicationContext实例,并验证是否已加载正确的bean。

请考虑以下代码作为示例:

spring meta bean.Java

// @Component so that it's part of the Spring context
// Implement ApplicationContextAware so that the ApplicationContext will be loaded
// correctly
@Component
public class SpringMetaBean implements ApplicationContextAware {
  private ApplicationContext appCtx;
  public setApplicationContext(ApplicationContext appCtx) {
    this.appCtx = appCtx;
  }

  // @PostConstruct so that when loaded into the Spring context, this method will
  // automatically execute and notify ApplicationContextHolder with a reference to
  // the ApplicationContext
  @PostConstruct
  public void setup() {
    ApplicationContextHolder.set(this.appCtx);
  }
}

application context holder.Java

public class ApplicationContextHolder {
  // ensure the reference is thread-safe because Spring and standalone Servlet will
  // probably be running on different threads.
  private final AtomicReference<ApplicationContext> appCtxContainer = new AtomicReference<>();

  public void set(ApplicationContext appCtx) {
    this.appCtxContainer.set(appCtx);
  }

  public ApplicationContext get() {
    return this.appCtxContainer.get();
  }
}

my standalone Servlet.Java

public class MyStandaloneServlet {
  // my request handler method
  public void getResponse(HttpServletRequest rq) {
    ApplicationContext springAppCtx = ApplicationContextHolder.get();
    // if not null, we know that Spring has been loaded and we can dig into the
    // application context.
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.