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.
Related
I am using spring.factories to set bootstrap context
org.springframework.cloud.bootstrap.BootstrapConfiguration=sompePackage.MyBootstrapConfiguration
I was following what is mentioned in this link
https://cloud.spring.io/spring-cloud-commons/multi/multi__spring_cloud_context_application_context_services.html
I noticed 2 things hope you please can help me with
1- I cannot spy on any bean that is created through the bootstrap context, in other words, if I create a bean of type x in MyBootstrapConfiguration, spying on that bean with #SpyBean is not working, I can spy on all other beans but the bootstrap context ones (I am using springboottest)
2- If I inject ApplicationContext somewhere and print all the defined beans, i cannot see the beans that were created in the bootstrap context, in other words, the bean x that is created in MyBootstrapConfig is not there. However, #Autowired is working fine and the bean is injected correctly.
My questions are:
1- How can i spy or mock the bootstrap context beans?
2- If i cannot find these beans in ApplicationContext, where are they?
Thanks,
try to put break point where you are creating your bean and run with debug mode, then you will find out whether your bean is created or not
You could define your own context for the test scope you are trying to run:
This would look something like:
public class TestApplicationContext implements ApplicationContextAware {
private static ApplicationContext context;
#Override
public void setApplicationContext(final ApplicationContext context) throws
BeansException {
TestApplicationContext.context = context;
}
public static Object getBean(final String beanName) {
return context.getBean(beanName);
}
}
Then you can create a bean for the context in a #Configuration annotated class.
#Bean
public TestApplicationContext testApplicationContext() {
return new TestApplicationContext();
}
Then you can easily reference whatever bean you need by simply:
TestApplicationContext.getBean("someBean");
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.
}
}
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);
}
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).
I have a stateful Spring bean. How can I enforce its usage scope to prototype in my application?
How can I prevent another developper on my project of injecting this bean with the singleton scope?
I know you can configure scope either via annotation or via the xml configuration. Of what I have seen, when using Spring 3, the scope configured by annotation gets overriden by the scope defined manually in the xml. How can I enforce my scope, thru configuration or programatically, so my bean will never be used as a singleton?
I thought about inspecting the bean scope on the startup of the application, but it doesn't sound like an elegant solution.
This is not elegant, but AFAIK this is the only way to achieve what you are looking for
public class MyStatefulBean implements InitializingBean, ApplicationContextAware, BeanNameAware {
private String myName;
private ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
#Override
public void setBeanName(String s) {
this.myName = s;
}
#Override
public void afterPropertiesSet() throws Exception {
if(this.context.isSingleton(this.myName))
throw new RuntimeException("Bean CANNOT be singleton");
}
}
Document it? There's no way for it to know if someone is keeping a reference to the bean and reusing it or sharing it across threads when they should have been using getBean() to get the prototype.
Spring cannot stop your peers from writing code that is simply incorrect, which is all that such a usage would be.
If you don't want to rely on the API user doing what's expected of them, expose the bean via a factory.