Can't get Spring bean - spring

I have a Spring project in which I want to get a specific Spring bean defined in my Spring beans XML File. My Spring bean XML file is located at /WEB-INF/spring/root-context.xml.
Here is my code in the Service class:
ApplicationContext context = new ClassPathXmlApplicationContext("/WEB-INF/spring/root-context.xml");
Here is the error I get when I compile :
parsing XML document from class path resource [WEB-INF/spring/root-context.xml]; nested exception is java.io.FileNotFoundException: class path resource [WEB-INF/spring/root-context.xml] cannot be opened because it does not exist

Probably WEB-INF is not inside your classpath. I suggest to move the xml file in the classpath (for example src/main/resources/spring/root-context.xml). Then you can access it with: ApplicationContext context = new ClassPathXmlApplicationContext("/spring/root-context.xml"); If you're inside web application, Spring Mvc looks for th context in WEB-INF/<the name of the dispatcher servlet>-servlet.xml
If you want to access the context from WEB-INF you can load it using
GenericApplicationContext ctx = new GenericApplicationContext();
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
xmlReader.loadBeanDefinitions(new FileSystemResource(path));
A better way is using WebApplicationContextUtils or implement ApplicationContextAware. Not sure what your use case is...

Related

Using both WebApplicationInitializer and web.xml in spring mvc+spring security+spring session redis web application

I'm trying to implement Spring redis session in an existing Spring MVC (ver 5.1.6) application. In web.xml we have ContextLoaderListener, DispatcherServlet and contextConfigLocation are all defined.
After required dependencies are included and suggested code changes are done, i'm getting below error:
Caused by: java.lang.IllegalStateException: Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader definitions in your web.xml!"}}*
As part of code changes i'm extending the class "AbstractHttpSessionApplicationInitializer",(from Spring session core library) which internally implements WebApplicationInitializer. Seems like that is trying to create another context and throwing the above error. We cannot avoid extending this class, as this does the job of registering redisHttpSession to context.
Most of the examples available are all with spring boot. So there they wouldn't have faced this issue.
Any solution, other than completely replacing web.xml and use only WebApplicationInitializer?
Just want to provide an update. Instead of extending AbstractHttpSessionApplicationInitializer abtract class, i have taken a different approach by initializing bean RedisHttpSessionConfiguration thru XML bean definition.
This approach worked.
Followed the steps mentioned in the below thread;
How to configure Spring sessions to work with Redis in xml?
Along with that we need to serialize the cookie as well;
#Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("SESSIONID");
serializer.setCookiePath("/");
serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$");
return serializer;
}

Spring ClassPathXmlApplicationContext cannot load xml

I want to load applicationContext xml by ClassPathXmlApplicationContext.
I use this method can load
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
but After I create a folder, Spring can't load applicationContext
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("venom/spring/study/spring-context.xml");
this is my module struct
I dont think you need to specify the path as long as those folders are inside resources folder, you just need to specify the XML file name like this:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");

How to add beans loaded via FileSystemXmlApplicationContext to an existing context loaded via ClassPathXmlApplicationContext?

I have an old application that has all its spring batch beans in class path; these beans get loaded in application context using ClassPathXmlApplicationContext. Now, there is a need where I can put these spring batch beans outside my war/classpath.
If you could please help me here? I can not change existing code and if I load these new definitions using FileSystemXmlApplicationContext, how could I merge them with existing context?
Thanks !
You could try using #ImportResource in your new application to load the bean definitions from an XML resource:
#Configuration
#ImportResource({
"classpath:your-old-applicationContext.xml",
"classpath:another-old-applicationContext.xml"
})
public class NewApplicationConfig {
}

SpringBoot/Spring Cloud Config Client multiple application contexts (root & servlet) with RefreshScope annotated beans

I have a couple of questions regarding Spring Cloud Config in a web application.
Context
I'm working on an SpringBoot web application where I have a Root application context (parent) and a Servlet application context (child), I'm adding Spring Cloud Config capabilities to this application (of course this app connects to a Spring Cloud Config server via http).
When I annotate a bean that is registered in the Root application context with the RefreshScope annotation everything works as expected, the problems started when I tried to annotate a spring bean that is registered in the Servlet application context.
First problem: an IllegalStateException was thrown when the #RefreshScope annotated bean in the servlet application context was tried to be accessed, the following is the meaningful part of the stacktrace:
ERROR: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: No Scope registered for scope name 'refresh'] with root cause
java.lang.IllegalStateException: No Scope registered for scope name 'refresh'
Solution: the error above was solved by registering the refresh scope to the Servlet application context
#Bean
public CustomScopeConfigurer servletCustomScopeConfigurer(org.springframework.cloud.context.scope.refresh.RefreshScope refreshScope) {
CustomScopeConfigurer customScopeConfigurer = new CustomScopeConfigurer();
customScopeConfigurer.addScope("refresh", refreshScope);
return customScopeConfigurer;
}
Question: Assuming that this way to model a web application is still relevant (I think it is), why I couldn't find any documentation stating that it's necessary to register the refresh scope to the servlet application context and I should register the org.springframework.cloud.context.scope.refresh.RefreshScope bean from the root application context?
Second problem: Once I had the refresh scope registered in the servlet application context the application started fine, and everything seemed to be working, however when I tried to update a property from the refreshable beans I had mixed results, when I refresh a property that would modify a bean in the root application context I could see the bean being updated, so all good, however when I update a property that would modify a bean in the servlet application context I could set the bean being refreshed but the new property value was not being reflected in the bean.
Solution: After some tests I realised that the ConfigurableEnvironment in both contexts are not the same, at some point the parent ConfigurableEnvironment is merged to the child ConfigurableEnvironment that is how beans in the servlet context get initialised correctly at startup, but when the ContextRefresher.refresh() is called by the RefreshEndpoint only the parent ConfigurableEnvironment is updated, and the child ConfigurableEnvironment is not leaving it with the old values, what I did now was to inject the parent ConfigurableEnvironment when creating the servlet application context and everything worked as expected, relevant code:
#Bean
public DispatcherServlet dispatcherServlet(ConfigurableEnvironment parentEnvironment) {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(WebConfiguration.class);
applicationContext.setEnvironment(parentEnvironment);
dispatcherServlet.setApplicationContext(applicationContext);
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
return dispatcherServlet;
}
Question: Again I was surprised by the lack of documentation on the expected behaviour of a Spring application declaring parent and child application contexts, maybe I just didn't find it and it exists and is amazing. Is the approach of setting the parent ConfigurableEnvironment to the child servlet context the correct one?
In the default case where (parent ConfigurableEnvironment NOT set in the servlet context.) would be the fact that the child ConfigurableEnvironment is not refreshed if is intentional or a bug?
If you are still reading this, thanks! Answers to the questions above will be very appreciated!
Hopefully this helps other people dealing with these issues.

Spring, using new ClassPathXmlApplicationContext and getting error being unable to find applicationContext.xml and others?

I am trying to follow this tutorial: http://www.vogella.de/articles/SpringDependencyInjection/article.html to use annotation dependency injection in my application. I set up the bean, etc like in the tutorial and then am trying to get an instance of the bean within my MainController class (a controller class that handles generating a specific page for my spring web mvc app).. I keep getting
SEVERE: Servlet.service() for servlet spring threw exception
java.io.FileNotFoundException: class path resource [WEB-INF/applicationContext.xml] cannot be opened because it does not exist
I am doing this in my MainController:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BeanFactory factory = context;
BeanIRPlus beanirPlus = (BeanIRPlus) factory
.getBean("BeanIRPlus");
IRPlusInterface irPlus = beanirPlus.getIRPlus();
I have searched and searched on this and yet to find an answer that fixes my problem. My applicationContext in in webapp/WEB-INF/ and my spring app seems to be working otherwise as it was handling requests, etc before this. I have tried putting the applicationContext.xml in WEB-INF classes but still nothing. Is there any workaround to make this not search the path this way as I think its doing a relative path search. Thanks for any advice
Not a direct answer, but here goes.
The tutorial you have referred is for dependency injection in a standalone application and not a web application. In case of web application, spring automatically loads the context files and initializes the beans. So you would not need any of the lines specified in the MainController.
Instead, you could do something like this to use beanIRPlus bean in your controller.
#Autowired
private BeanIRPlus beanIRPlus;

Resources