Skip to content

Support for EAR Parent Context Loader in Spring Framework 5.0 [SPR-16258] #20805

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
spring-projects-issues opened this issue Dec 3, 2017 · 16 comments
Labels
in: core Issues in core modules (aop, beans, core, context, expression) status: declined A suggestion or change that we don't feel we should currently apply type: enhancement A general enhancement

Comments

@spring-projects-issues
Copy link
Collaborator

sreekanth opened SPR-16258 and commented

I'm unable to upgrade our EAR project to use spring 5.0 only due to the fact that spring is no more supporting the parent context loader, the detail is same as given in the stackoverflow.

I understood it is removed intentionally from the spring core, but this decision is stopping us upgrading spring framework, though we can stick to 4.x of spring core, we were unable to upgrade the modules like spring data (elasticsearch, etc) due to the same reason.

I hope the world is still using non boot and non microservice projects with highest expectation from framework like spring. So, on behalf of all i would like to request spring team to add support for parent context loading back to spring project.

If its not possible, request someone to provide an alternative solution as a documentation or as an example on how to achieve this.


Affects: 5.0 GA

Reference URL: https://stackoverflow.com/questions/46902115/spring-framework-5-0-0-final-parent-context-not-getting-loaded

@spring-projects-issues spring-projects-issues added type: enhancement A general enhancement in: core Issues in core modules (aop, beans, core, context, expression) labels Jan 11, 2019
@spring-projects-issues spring-projects-issues added this to the 5.x Backlog milestone Jan 11, 2019
@mebigfatguy
Copy link
Contributor

I am hitting the same issue. there must be some alternative, no?

@haarli
Copy link

haarli commented Apr 10, 2019

Same problem here and no solution so far.

@schekuri503
Copy link

Hitting the same issue, Any alternative found?

@ashtonbatty
Copy link

Why isn't this mentioned in the 4 to 5 migration guide?

@20Biere
Copy link

20Biere commented Aug 14, 2020

Same blocking constraint here ... if a solution could be found, it would be great.

@santhoshkeka
Copy link

Same problem we are facing. Any fix or alternate solution?

@DustyP53
Copy link

DustyP53 commented Mar 26, 2021

We created a POC shim where we pulled into Spring5 the missing parent context loader. It worked on simple issues but we never got past that, we were pulled onto other projects.

It specifically pulled the classes required to restore the BeanFactoryLocator.class.

@WPietrzak
Copy link

facing the same issue. I badly need to upgrade spring from 4 to 5. When can we expect the solution?

@mgrafl
Copy link

mgrafl commented Apr 27, 2021

The mechanism was removed in #19720.
The Stackoverflow answer https://stackoverflow.com/a/54087660/107013 discusses a workaround.

But maybe @jhoeller could provide some insights how parent context loading should be achieved in Spring Framework 5.x?

@Staticsubh
Copy link

We are also stuck with the same issue. #28140 . Any help here @jhoeller ??

@Staticsubh
Copy link

Hi Team,

Any help here?

@jhoeller jhoeller modified the milestones: 6.x Backlog, General Backlog Nov 22, 2022
@skaluva
Copy link

skaluva commented Jan 17, 2023

Im also looking for the solution atleast alternate solution (instead of pulling 4.x classes and putting in our application) .. this is stopping us migrating to 5.x .. our infosec not allowing to use 4.x as its EOL ended 2yrs ago.. :(

@sgulve
Copy link

sgulve commented Jan 17, 2023

I have currently done the spring migration by adding spring 4 classes in our own application.
@skaluva Is there any specific reason that you are not using 4.x classes into your application?

@haarli
Copy link

haarli commented Jan 30, 2023

The usage of custom ContextLoaderListeners suggested before in https://stackoverflow.com/questions/54085902/sharing-parent-spring-context-with-child-in-spring-5/54087660#54087660 works fine for us in an EAR project with Spring 5. Imagine a project with the following structure:

  • foo.ear
    • fooLogic.jar
      • beanRefContext.xml
      • FooParentContextConfiguration.java
    • fooWeb1.war
      • FooContextLoaderListener1.java
      • FooWebInitializer1.java or web.xml
      • FooWebContextConfig1.java
    • fooWeb2.war
      • FooContextLoaderListener2.java
      • FooWebInitializer2.java or web.xml
      • FooWebContextConfig2.java

fooWeb1.war and fooWeb2.war should both use the same parent context, defined in
fooLogic.jar/FooParentContextConfiguration.java

fooLogic.jar

beanRefContext.xml

containing the XML Bean Factory:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
	<bean id="fooParentContext" class="org.springframework.context.annotation.AnnotationConfigApplicationContext">
		<constructor-arg>
			<list>
				<value type="java.lang.Class">FooParentContextConfiguration</value>
			</list>
		</constructor-arg>
	</bean>

</beans>
FooParentContextConfiguration

In this class, a static variable for the BeanFactory was added:

@Configuration
//...
public class FooParentContextConfiguration {
   //...
  public static final BeanFactory FOO_BEAN_FACTORY = new ClassPathXmlApplicationContext("beanRefContext.xml");
  //...

fooWeb1.war

Required in both wars each:

FooContextLoaderListener1.java
public class FooContextLoaderListener1 extends ContextLoaderListener{

    @Override
    protected ApplicationContext loadParentContext(ServletContext servletContext) {
        ApplicationContext parentContext = (ApplicationContext) FooParentContextConfiguration.FOO_BEAN_FACTORY.getBean("fooParentContext");
        return parentContext;
    }

}
FooWebInitializer1.java
public class FooWebAppInitializer1 implements WebApplicationInitializer {

  public void onStartup(ServletContext servletContext) throws ServletException {
     AnnotationConfigWebApplicationContext myctx = new AnnotationConfigWebApplicationContext();
     //Register your WebConfiguration, if required    
     myctx.register(FooWebContextConfig2.class);
     myctx.setServletContext(servletContext);

     // Spring
     servletContext.addListener(new FooCustomContextLoaderListener1(myctx));

    //...
  }

}

fooWeb2.war

Same as for fooWeb1.war

Maybe there's a more elegant way, but currently this seems to work for us without using and adding old Spring4 classes.

@jhoeller
Copy link
Contributor

jhoeller commented Aug 7, 2023

Using a custom ContextLoaderListener with an overridden loadParentContext method as shown above is exactly what we would recommend for such scenarios. Or preferably from our perspective, merge the shared context definition into each web application context, at the expense of duplicating those bean definitions in every web app deployment.

In any case, since the old EJB-oriented mechanism is not coming back, I'm closing this issue for good now.

@jhoeller jhoeller closed this as completed Aug 7, 2023
@jhoeller jhoeller removed this from the General Backlog milestone Aug 7, 2023
@sbrannen sbrannen closed this as not planned Won't fix, can't repro, duplicate, stale Aug 7, 2023
@sbrannen sbrannen added the status: declined A suggestion or change that we don't feel we should currently apply label Aug 7, 2023
@MalcolmLett-codec
Copy link

MalcolmLett-codec commented Apr 29, 2024

Just wanted to share some actual code for those trying to figure out how to do this.
In particular, in our app, we wanted the parent context to be closed automatically when the child apps are all closed, and none of the official docs mention any way to do this.

We're using vanilla Spring 5, without SpringBoot.

In our case, we have two WARs sharing the same parent Spring context in an EAR.
Importantly, the shared context classes are defined in a JAR within the EAR's /lib folder, so they're loaded by the EAR's class loader. This means that we can share static class state between the WARs.

We have a simple class with two methods for leasing and releasing the shared parent. Simplified/pseudo-code:

// Loaded via EAR class-loader
public class EarContextLocator {
  private static AnnotationConfigApplicationContext context;
  private static int leaseCount = 0;

  public static synchronized ApplicationContext lease() {
    if (context == null) {
      context = new AnnotationConfigApplicationContext(...);
      context.refresh();
    }
    leaseCount++
    return context;
  }

  public static synchronized void release() {
    leaseCount--;
    if (leaseCount == 0) {
      context.close();
    }
  }
}

Each WAR app has a WebApplicationInitializer by extending AbstractAnnotationConfigDispatcherServletInitializer. The problem is that the default registerContextLoaderListener isn't parent-aware. So we override that as follows:

public class MyAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

 ...

  @Override
  protected void registerContextLoaderListener(ServletContext servletContext) {
    // create this app's context
    WebApplicationContext rootAppContext = createRootApplicationContext();
  
    // customised parent-aware context loader
    ContextLoaderListener listener = new ContextLoaderListener(rootAppContext) {
      private ApplicationContext parentContext;
    
      @Override
      protected ApplicationContext loadParentContext(ServletContext servletContext) {
        parentContext = EarContextLocator.lease();
        return parentContext;
      }
    
      @Override
      public void closeWebApplicationContext(ServletContext servletContext) {
        try {
          super.closeWebApplicationContext(servletContext);
        } finally {
          if (parentContext != null) {
            EarContextLocator.release();
          }
        }
      }
    };
  
    listener.setContextInitializers(getRootApplicationContextInitializers());
    servletContext.addListener(listener);
  }
}

This comment is also available in the discussion of the following blog post:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) status: declined A suggestion or change that we don't feel we should currently apply type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests