how to access spring beans from objects not created by spring [duplicate] - java

This question already has answers here:
spring autowiring not working from a non-spring managed class
(10 answers)
Closed 1 year ago.
In my web application i use hibernate and spring. Entity classes that are returned from Hibernate layer need to access other service classes in some scenarios. Entity classes are not just DTO's they contains some business logic, and to perform some business logic (like may be send out emails etc when some conditions are met) these need to access service classes. Service classes are spring beans. so what's the recommended method in such scenarios to get hold of spring beans from within these entity classes which are created outside spring context?

You are looking for Service-locator pattern,
Implementation in Spring
You can register ApplicationContextAware and get reference to ApplicationContext and statically serve bean
public class ApplicationContextUtils implements ApplicationContextAware {
private static ApplicationContext ctx;
private static final String USER_SERVICE = "userServiceBean";
#Override
public void setApplicationContext(ApplicationContext appContext)
throws BeansException {
ctx = appContext;
}
public static ApplicationContext getApplicationContext() {
return ctx;
}
public static UserService getUserService(){return ctx.getBean(USER_SERVICE);}
}

Read about #Configurable annotation that allows to configure beans using AspectJ:
Spring reference
Spring blogs
If you don't want to use AspectJ, you could use the
ApplicationContext.getAutowireCapableBeanFactory().autowireBean()
method to configure beans that live outside the spring container. (see java docs).

Related

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.
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:
Put an application context reference to some static holder accessible from Jersey.
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(...);
}
}
So a viable solution for this could happen in two stages:
A Spring bean gets the ApplicationContext instance and sends it to a static singleton outside of the Spring context.
Your standalone servlet gets the ApplicationContext instance from the static singleton and verifies that the right beans have been loaded.
Consider the following code as an example:
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.
}
}

can we implement Spring Autowiring in Java Standalone Application (Swing)

I have created an application using Java Swing. Now, i want to integrate Spring Autowiring(Dependency Injection) in this application.
Doubt in mind is that to create UI(User Interface), i would be using "new" keyword, but to use DAO and POJO classes, i want them to auto-wired.
Can somebody suggest and help me out.
Not sure if I understood you right. I assume, that you want to autowire your DAOs, Services etc. in UI classes. But in order do to that, these UI classes would have to be Spring Beans themselves.
What you could do, is to register each UI class in the Spring application context, when its created. To do that, you could create the following class:
public class BeanProvider {
private static ApplicationContext applicationContext;
/**
* Autowires the specified object in the spring context
*
* #param object
*/
public static void autowire(Object object) {
applicationContext.getAutowireCapableBeanFactory().autowireBean(object);
}
#Autowired
private void setApplicationContext(ApplicationContext applicationContext) {
BeanProvider.applicationContext = applicationContext;
}
}
and then in the constructor of each UI class:
public MyUiClass(){
BeanProvider.autowire(this);
}

Create servlet context without autowiring in spring

I have a singleton class and one its private members is ServletContext object.
I made it singleton to remove spring dependency since I am trying to write in pure java code.
public class Utils {
private static Utils utils = null;
public Utils() {
// Exists only to defeat instantiation.
}
public synchronized static Utils getInstance() {
if (utils == null) {
utils = new Utils();
}
return utils;
}
#Autowired
private ServletContext servletContext;
public void makeUtils() {
// output csv path
String outputFile = servletContext.getRealPath("/util");
}
}
But here servletContext will be null because I am creating the object of Utils class wherever I needed manually. Not by using #Autowired. So spring is not injecting the dependency. How can I solve this.
#Autowired is a spring annotation.
If you want something to happen in response to that annotation, then you need to use spring. If you want to remove the dependency on spring, then you can't use Autowired. You need to pick one - are you depending on spring for your wiring, or not?
Some solutions you could follow:
Using Spring
Make Utils a spring bean and inject it
Put Utils into your spring context (bean factory) and then inject it (using #Autowired, or another wiring strategy) into every other class that wants to use it.
Make Utils a spring bean and look it up.
There's really not much reason to do it this way, but if you want, you can get access to your spring bean factory (probably via the ApplicationContext) and lookup a bean by type using BeanFactory.getBean(Class<T>)
Use Spring to autowire an existing Utils object
Again, there's not many good reasons to do this, but if you have an instance of AutowireCapableBeanFactory (which you can get via ApplicationContext) then you can call autowireBean(Object existingBean) to get spring to wire up your #Autowired fields.
Note: My method/class references are from Spring 3.2 because it's what's open in my IDE right now. You may need to make adjustments if you have a different spring version)
Without Spring
Instantiate Utils within a Servlet (or Listener)
Create a configure method on Utils that takes the ServletContext.
Inside a Servlet (or a ServletContextListener) call that configure method to set the servletContext field on Utils.
Store a static global ServletContext
Create an object like ServletContextHolder that has a static field on which you can store the ServletContext
Inside a Servlet (or a ServletContextListener) call the setContext method on that holder set the servletContext field.
Inside Utils call ServletContextHolder.getContext()

Spring application context

Is there any other way in J6SE to get spring (spring 3.0) application context than implement ApplicationContextAware interface?
Sorry I must improve my question. I have running application context in my J6SE app and in some classes I need it.
After reading your question, I know you're looking for an alternative to ApplicationContextAware but I read it that you have a goal of many classes using the ApplicationContext but want to avoid implementing the interface for all these classes. This approach still uses the ApplicationContextAware but encapsulates it into a single class for reuses.
I typically load the configuration at application start up via a ContextLoaderListener in the web.xml. After this occurs, I set "MyApplicationContext" as the contextApplicationContextProvider.
<bean id="contextApplicationContextProvider" class="pkg.MyApplicationContext"></bean>
The class must implement ApplicationContextAware as you already suggested:
public class MyApplicationContext implements ApplicationContextAware {
private static ApplicationContext appContext;
/* (non-Javadoc)
* #see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
#Override
public void setApplicationContext(ApplicationContext globalAppContext)
throws BeansException {
this.appContext = globalAppContext;
}
public static ApplicationContext getApplicationContext() {
return appContext;
}
}
The key here is that you now have a static reference to the single instance of the ApplicationContext object. Retrieving it is simple by using the static method call MyApplicationContext.getApplicationContext() for any class, spring-managed or not.
You can load it from the CLASSPATH.
new FileSystemXmlApplicationContext(APPLICATION_CONTEXT_FILE);
#Inject
private ApplicationContext ctx;
(or #Autowired instead of #Inject). This is the annotation replacement of ApplicationContextAware. This of course mean that the objects needs to be a spring bean.

Good way to access Spring singleton from within domain objects?

I have a domain model that consists of fairly large object graphs, where domain objects are creating other domain objects and so forth. Each of these domain objects needs access to a small handful of singleton-type helper objects for various purposes.
I was about to implement them using the Java singleton pattern when I remembered that I am already using Spring and I can use Spring to instantiate one of each of these helpers at application startup.
My question is how to I find them from within my domain objects? These are all objects that are created via the "new" operator and are not under the control of Spring.
I'm thinking I could use the "getBean" method if I had my hands on the Spring application context (which I don't) -- but is the performance of this good? I need this stuff to be fast... And how to quickly get the application context?
In a typical Spring application, the kind of cross-entity logic you're describing is usually implemented in the business service layer (i.e. the Spring-managed singletons), not the domain objects. Domain classes in Spring apps tend to be fairly simple data containers, perhaps with some methods for performing basic operations on the data they encapsulate, but stopping well short of managing complex object graphs outside of themselves. So business service objects manage domain objects, not the other way around.
If you insist on injecting singletons into your domain objects, though, you can achieve this using AspectJ. Spring itself does not support this very well.
public class SpringApplicationContextProvider implements ApplicationContextAware {
public void setApplicationContext(ApplicationContext ctx)
throws BeansException {
// Wiring the ApplicationContext into a static method
SpringApplicationContext.setApplicationContext(ctx);
}
}
And define SpringApplicationContext as,
public class SpringApplicationContext {
private static ApplicationContext ctx;
public static void setApplicationContext(
ApplicationContext applicationContext) {
ctx = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return ctx;
}
private SpringApplicationContext(){
}
}
Define SpringApplicationContextProvider as a spring bean in your config file. Now the application context can be accessed using this provider.
look at the answer to the question # Injecting beans into a class outside the Spring managed context

Categories

Resources