Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ensure spring bean loaded from non spring context

I have spring application alongside (jersey 2.6 classes and ) servlets .

I need to get Spring bean(s) from jersey/non spring context,

Similar question suggested to get context in a static wrapper of context

public static ApplicationContext getContext() {
    return context;
}

How can I be sure the context is already loaded or not null?

If I can't, how should I wait/check until it spring context is loaded?

In case of calling from jersey context or calling bean from a simple HttpServlet code

EDIT

Jersey is working fine using jersey-spring3 dependency jar, so my question is only about Servlets out of Spring control

EDIT 2

The application is loading spring different than @entpnerd suggested article

It register a Servlet implementing a WebApplicationInitializer

public class MyWebAppInitializer implements WebApplicationInitializer {

But also have DispatcherServlet configured in web.xml

How can the DispatcherServlet loaded only after Spring loaded?

Because we add Autowiring capabilities on its init method:

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

Is adding a timeout before serving requests is the most prefer solution or is there a tweak in class loading that can take care of it?

EDIT 3

I found answers and answers of injecting, but not why Spring is loaded before Servlet.

like image 453
user7294900 Avatar asked Nov 22 '17 12:11

user7294900


1 Answers

The idea is quite simple, although the actual implementation may vary depending on an exact way of Spring boot and Jersery initialization.

An idea:

Spring boot, as being a purely runtime framework, is all about proper loading the application context (from the question standpoint).

So, bottom line, when it's loaded there is an application context somewhere in memory, and its possible to access beans from this application context.

Now, since you say that Jersey is not spring/spring-boot driven, this application context has to be reachable from some kind of static global variable by Jersey, it's quite ugly but should work.

So the idea has two steps:

  1. Put an application context reference to some static holder accessible from Jersey.
  2. Read this value in some infrastructure level code from Jersey component.

A Possible Implementation

Technically step one can be done by implementing some kind of spring boot listener that will store application context in some kind of singleton:

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

Now the step 2 is:

class MyJerseyOrWhateverComponentThatWantsToAccessApplicationContext {

    public void foo() {
       ApplicationContext ctx = ApplicationContextHolder.INSTANCE.getCtx();
       ... 
       ctx.getBean(...);
    }
}
like image 146
Mark Bramnik Avatar answered Sep 29 '22 13:09

Mark Bramnik