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

时间:2017-11-22 12:28:01

标签: java spring servlets classloader autowired

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

我需要从 jersey / 非弹簧上下文中获取Spring bean,

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

public static ApplicationContext getContext() {
    return context;
}

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

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

如果从 jersey上下文调用或从调用bean,则需要一个简单的HttpServlet代码

修改

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

编辑2

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

的弹簧

它注册一个实现WebApplicationInitializer

的Servlet
public class MyWebAppInitializer implements WebApplicationInitializer {

但是在web.xml中配置了DispatcherServlet

如何在Spring加载后加载DispatcherServlet

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

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

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

编辑3

我发现answersanswers注入,但为什么 Spring在Servlet之前加载。

2 个答案:

答案 0 :(得分:5)

这个想法很简单,尽管实际的实现可能会根据Spring引导和Jersery初始化的确切方式而有所不同。

一个想法:

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

因此,最重要的是,在加载时,在内存中的某个位置存在一个应用程序上下文,并且可以从该应用程序上下文访问bean。

现在,由于您说Jersey不是由spring / spring-boot驱动的,因此必须通过Jersey的某种静态全局变量可以访问此应用程序上下文,这非常难看,但应该可以。

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

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

可能的实施方式

技术上第一步”可以通过实现某种类型的spring boot侦听器来完成,该侦听器将以某种单例形式存储应用程序上下文:

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(...);
    }
}

答案 1 :(得分:0)

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

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

以下面的代码为例:

SpringMetaBean.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);
  }
}

ApplicationContextHolder.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();
  }
}

MyStandaloneServlet.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.
  }
}