Closed spring-projects-issues closed 7 years ago
John Blum commented
Hi Juergen Hoeller-
In fact, the BeanFactoryLocator
facility was used in more places than EJB-based, Java EE environments.
Spring Data GemFire (SDG) makes fairly extensive use of this facility to bridge the world of Spring config and GemFire's native cache.xml
config. Costin Leau added this functionality in the very beginning of the SDG project, with the GemfireBeanFactoryLocator.
The idea is to let users auto-wire GemFire objects (e.g. CacheLoaders
, CacheWriters
, etc) defined/declared in GemFire's cache.xml
with beans defined in the Spring ApplicationContext
when cache.xml
is still/also used.
While Spring is generally moving away from XML config, and while I have made several efforts to move SDG in the same direction, GemFire on the other hand is still largely configured with XML (i.e. cache.xml
). Even GemFire's more modern approach to configuration, using the (relatively) new Cluster Configuration Service applied via commands executed in GemFire's Shell (Gfsh) tool, is backed by cache.xml
(ironically).
As a result, this has led a few Pivotal customers (e.g. CDI, Citi, etc) to utilize a combination of both Spring config and GemFire config (whether that be with a node specific cache.xml
file or by using the new Cluster Configuration Service) when configuring and adding a new, often times Spring (Boot) based, peer member (application) to the cluster (embedded UC).
Even in the more typical client/server scenarios, customers can use cache.xml
to configure their GemFire cache client applications, which are typically Spring (Boot) applications. Using Spring Boot to create GemFire cache client applications will definitely be the norm in PCF.
Nearly all GemFire configuration can be expressed in Spring config (using SDG) largely because GemFire exposes an API for it. However, there are a few places, such as the GemFire to Greenplum Connector (G2C), that cannot be configured using Spring yet. Part of the reason for this is that GemFire does not expose appropriate configuration extensions in their API.
Long story short, robwinch caught this problem in the Spring Session build, which integrates with GemFire (as a Session Repository provider) via SDG. There will (possibly) be a few other Spring projects using SDG affected by this as well.
The good new is...
I think I have a solution to this (SDG) problem without having to propose re-introducing the BeanFactoryLocator
back into Spring Framework 5.
Sometime ago (in SDG 1.4, actually), at the request of the Spring XD team at the time, I introduced the SpringContextBootstrappingInitializer along with the ability to lazy-wire GemFire objects declared in cache.xml
(or even in Cluster Config; SDG doesn't care).
This was needed in UCs where GemFire bootstraps a Spring ApplicationContext
in the runtime of a GemFire JVM process, which customers do as well. This is the exact inverse of what users typically do (i.e. having a Spring container bootstrap GemFire using SDG and Spring Boot).
So, I think I can repurpose this Initializer
to do the work of the BeanFactoryLocator
. However, I am very open to any alternate ideas or suggestions you may have.
Anyway, I just wanted to make you aware of this feature in SDG that was based on the BeanFactoryLocator
.
Thanks for your time.
Juergen Hoeller commented
John Blum, I wasn't aware of that; thanks for raising it.
From my perspective, BeanFactoryLocator
is an outdated mechanism in several respects: Not only its typical use cases date back to ten years ago, its design is equally old and rather over-generalized. Also, the lifecycle of the contained factories isn't well-defined in such a static registry model with weak reference cleanup.
There are simpler ways to achieve the same, in particular if it doesn't have to be as overly flexible as BeanFactoryLocator
was meant to be. I'd rather recommend a custom static holder class for one or more ApplicationContexts
, keyed by something that has a meaning for your use case, and with a proper lifecycle.
John Blum commented
Thank you for the quick response Juergen Hoeller.
I'd rather recommend a custom static holder class for one or more
ApplicationContexts
, keyed by something that has a meaning for your use case, and with a proper lifecycle.
Sounds reasonable and kind of similar to how Costin originally implemented the GemfireBeanFactoryLocator.
Additionally, as I mentioned, I introduced the SpringContextBootstrappingInitializer for the lazy-wiring, GemFire bootstrapping Spring UC, that keeps a static holder to a ApplicationContext
. It could probably due with some more work around proper lifecycle handling, but then it's original intent was tied to the lifecycle of GemFire.
Anyway, I am currently trying to build on this and replace all uses of GemfireBeanFactoryLocator
.
I will post back here if I have anymore related questions since others might have similar problems and would look for ways on how to replace their BeanFactoryLocator
implementation behavior.
Thanks again.
Michael Minella commented
Sorry to be commenting on a resolved issue, but why was this never depricated and just dropped without any formal guidance as to what to do in it's place? For the record, Batch is using this as well to bootstrap the infrastructure required for JSR-352.
Juergen Hoeller commented
Michael Minella, commenting here is fine, this is not released yet after all: It's waiting for 5.0 M5 in February.
The reason for BeanFactoryLocator
not having been deprecated is that we're still considering WebSphere 7 and EJB 3.0 environments in general as a first-class citizen in the Spring Framework 4.3.x line. It would be odd to have to recommend a deprecated mechanism there, even if it effectively was deprecated for any other usage already.
Now, as of Spring Framework 5.0 with its EE 7 baseline, there is no supported EE environment left where the BeanFactoryLocator
mechanism is actually useful. I admit that it was a bit harsh to just remove it, but hey, otherwise we wouldn't even have this discussion ;-) In my obversation, deprecating leads to almost no feedback, but hard CI build failures obviously trigger it indeed. And in 5.0, we generally opt for removal over deprecation, trying to create a clean plate for the entire 5.x generation.
What lifecycle have you been using BeanFactoryLocator
with? Could you replace it with direct ClassPathXmlApplicationContext
setup, managing the ApplicationContext
in a custom static field of yours, and also shutting it down at a well-defined point? Any such option would have a clearer lifecycle than BeanFactoryLocator
's over-generalized static registry of factories which was only really designed for environments where no other lifecycle can be enforced.
Michael Minella commented
Juergen Hoeller, Thanks for the quick response. Let me explain the use case I'm using it for and maybe you can guide me down a better path (or at least help me see the path I should be on).
Per JSR-352, the way jobs are launched is via the following code:
JobOperator jobOperator = BatchRuntime.getJobOperator();
jobOperator.start("myJobName", null);
BatchRuntime
is a class provided by the specification so I cannot customize that. It uses a ServiceLoader
to load a JobOperator
instance (our JsrJobOperator
in this case) and return it so I'm limited as to how I can customize the building of the JobOperator
in the first place.
Currently, in the no-arg constructor for the JobOperator
, I have the following:
BeanFactoryLocator beanFactoryLocactor = ContextSingletonBeanFactoryLocator.getInstance();
BeanFactoryReference ref = beanFactoryLocactor.useBeanFactory("baseContext");
baseContext = (ApplicationContext) ref.getFactory();
This code allows me to bootstrap a new base context if one hasn't been created and reference it if it has. That base context contains all of the shared batch infrastructure components (JobRepository
, etc) and serves as the parent context for any of the job specific ApplicationContext
that are boostrapped when an actual job is run. As for shutdown, there are no well defined mechanisms within the JSR around that so JVM shutdown is the only sensible option as to when to close the context.
Is the right way going forward for me to handle what the ContextSingletonBeanFactoryLocator
was accomplishing via a static reference to a context in the JsrJobOperator
going forward (old school singleton style)? Again, any insight you can provide is appreciated.
Michael Minella commented
Juergen Hoeller, I wanted to give this a bump. I have downgraded the version of Spring Framework to 4.3.6 in Batch 4 because our build breaks without a solution to this. I'd like to get this addressed before my next milestone which I'm targeting for before DevNexus (in a couple weeks). Any insight you can provide is appreciated. Thanks in advance!
John Blum commented
Hi Michael Minella-
Spring Data GemFire had similar problems, as I described above.
In the end, my solution was to keep yet simplify as much of the existing behavior, based on the original BeanFactoryLocator
concepts, as possible. But, it really is as Juergen Hoeller recommended...
... a custom static holder class for one or more ApplicationContexts, keyed by something that has a meaning for your use case, and with a proper lifecycle.
To see how I implemented this for Spring Data GemFire see the GemfireBeanFactoryLocator
class before and after.
While this may or may not work for Spring Batch, hopefully it will give you some ideas.
Cheers, John Blum
I'm also facing similar issue while migrating to Spring 5.x. What all the possible solutions for this ? we are using EJB2
If anyone still needs this, here is how we reintroduced the locator mechanism into our code.
I am still not able to upgrade from Spring 4 to Spring 5 because of this issue only. Please go through the issue #28140 . Just for the information I have made changes as mentioned in the above comment by @MarcinCieslak
Juergen Hoeller opened SPR-15154 and commented
The
BeanFactoryLocator
facility and itsbeanRefContext.xml
-based default variant are outdated mechanisms for locating a statically sharedApplicationContext
, only really useful for old-school EAR deployment layouts prior to EJB 3.1. While it still makes sense for this to be available in the 4.3.x line with its EJB 3.0 support, let's get rid of the entire mechanism for Spring 5 with its EE 7 baseline.This means that existing users of
SpringBeanAutowiringInterceptor
on custom EJB classes need to migrate either away from EJB altogether, or to an EJB 3.1 + CDI layer with a CDI-Spring bridge, or to a custom interceptor variant which locates the SpringApplicationContext
from an application-specific holder, e.g. an EJB 3.1 Singleton Bean or a simple static variable in an application class.Issue Links:
19234 Drop NativeJdbcExtractor mechanism in favor of java.sql.Connection.unwrap()
19725 Remove outdated abstractions/delegates from org.springframework.core/util