How to load applicationContext.xml - spring

I trying to load an applicationContext.xml from java class in a web application using
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
and
ApplicationContext context = new FileSystemXmlApplicationContext("applicationContext.xml");
My question is how to load applicationContext.xml from a java class. The applicationContext.xml is WEB-INF. Is that possible?

You can use the ContextLoaderListener in your web.xml file:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Then you can use the WebApplicationContext to load the context:
WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(servlet.getServletContext());
Hope this helps.

A ContextLoaderListener is used when you want to load a specific context that will act as your context root. If you want to load additional contexts for whatever reason, you can define your own ServletContextListener, create your ApplicationContext instances, and put them in the ServletContext attributes so that they are available to the web application
public class AdditionalContextListener implements ServletContextListener {
#Override
public void contextDestroyed(ServletContextEvent sce) {
// destroy those contexts maybe
}
#Override
public void contextInitialized(ServletContextEvent sce) {
ApplicationContext context = ...; // get your context
sce.getServletContext().setAttribute("someContextIdentifier", context);
}
}

Related

How call a method in a spring bean on web context initialization

I have a war file that includes the following
Spring Bean
public class DataLoader {
private static Logger log = Logger.getLogger(DataLoader.class.getName());
public void init() {
log.info("DataLoader init called");
}
}
applicationContext.xml
<bean id="dataLoader" class="com.example.DataLoader"
init-method="init" lazy-init="false">
</bean>
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
I want the init method in the DataLoader to be called when I deploy the war file to a web container. However, it does not get called.
I thought that the init method would get called after the bean is initialized because of init-method="init" in the bean configuration, and that the bean would be initialized on deployment because of lazy-init="false".
What am I doing wrong?
Are you sure your bean is being initialized at all? You probably want to make your DataLoader class extend InitializingBean, and rename init to afterPropertiesSet. The more modern way of doing this, however, would be to drop the XML configuration for the bean, and alter you class in this way:
#Component
public class DataLoader {
private static Logger log = Logger.getLogger(DataLoader.class.getName());
#PostConstruct
public void init() {
log.info("DataLoader init called");
}
}

Spring autowiring fails in RESTeasy service

I have a simple service which fails to autowire bean.
Although getting the same bean through context succeeds.
So the bean creation and registration in repository is working, but autowiring does not.
Changing class of the field in the service (MyRepository -> YourRepository), there is an error thrown that such bean does not exists, so the autowiring mechanism is working.
Any ideas what might be missing?
#Component
#Path("/")
public class RestService {
#Autowired
private MyRepository myRepository; // is not autowired and is null
#GET
#Path("/{param}")
#Produces(MediaType.APPLICATION_JSON)
public Response printMessage(#PathParam("param") String msg) {
return Response.ok(
AppContext.getContext().getBean("myRepository") == myRepository)
.build(); // false
}
public void setMyRepository(MyRepository myRepository) {
this.myRepository = myRepository;
}
}
AppContext above is my simple implementation of ApplicationContextAware
Repository
#Repository
public interface MyRepository extends MongoRepository<MyEntity, String> {
}
There is no .xml configuration and spring is initialized through
public class MyInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) throws ServletException {
container.addListener(new ResteasyBootstrap());
final AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
ContextLoaderListener springListener = new ContextLoaderListener(rootContext);
rootContext.register(MyConfiguration.class);
container.addListener(springListener);
}
}
And configuration class
#Configuration
#EnableMongoRepositories("my.package.repository")
#ComponentScan("my.package")
public class MyConfiguration {
#Bean
public MongoTemplate mongoTemplate() throws UnknownHostException {
return new MongoTemplate(new MongoClient("localhost"), "db");
}
}
EDIT after 2 comments
I'm using the following library for RESTeasy - spring integration.
Do I need some other?
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-spring</artifactId>
<version>3.0.8.Final</version>
</dependency>
I think JAX-RS and RESTeasy is working correctly, because service is working and I can access it through web when deployed on JBoss
EDIT for workaround
Service is initialized correctly if I create the following constructor, but it feels more like a workaround
public RestService() {
this.myRepository = MyContext.getContext().getBean(MyRepository.class);
}
And MyContext class for more clarity
#Component
public class MyContext implements ApplicationContextAware {
private static ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static ApplicationContext getContext() {
return context;
}
}
Spring might be setup correctly, but that doesn't necessary mean that Spring+RestEasy integration is setup correctly.
The code I am posting is the web.xml configuration that I have used (with RestEasy 3.0.6 and Spring 3.2.8) and correctly sets up the integration between RestEasy and Spring and also sets up Spring MVC (everything under /api is handled by RestEasy, everything else is handled by Spring MVC).
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>my.package.config.ApplicationConfig</param-value>
</context-param>
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>web</param-value>
</context-param>
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/api</param-value>
</context-param>
<!-- Spring + RESTEasy -->
<listener>
<listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>
<listener>
<listener-class>org.jboss.resteasy.plugins.spring.SpringContextLoaderListener</listener-class>
</listener>
<!-- RESTEasy Servlet-->
<servlet>
<servlet-name>Resteasy</servlet-name>
<servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Resteasy</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
<!-- Spring MVC Servlet -->
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>my.package.config.MvcConfig</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file></welcome-file>
</welcome-file-list>
<error-page>
<error-code>404</error-code>
<location>/WEB-INF/jsp/error404.jsp</location>
</error-page>
</web-app>
Managed to solve the issue myself.
The correct solution is either to replace
public class MyInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) throws ServletException {
container.addListener(new ResteasyBootstrap());
final AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
ContextLoaderListener springListener = new ContextLoaderListener(rootContext);
rootContext.register(MyConfiguration.class);
container.addListener(springListener);
}
}
with
public class MyInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) throws ServletException {
container.addListener(new ResteasyBootstrap());
container.addListener(new SpringContextLoaderListener());
}
}
but in this case I'm losing possibility to use AnnotationConfigWebApplicationContext.
Also the initializer can be changed as follows to preserve annotation context.
public class MyInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) throws ServletException {
container.addListener(new ResteasyBootstrap());
final AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
ContextLoaderListener springListener = new ContextLoaderListener(rootContext) {
#Override
protected ContextLoader createContextLoader() {
return new SpringContextLoader();
}
};
rootContext.register(MyConfiguration.class);
container.addListener(springListener);
}
}

Strange behaviour of #Configuration with #Configurable in Spring

I've been using XML based configuration for a while - we've got a Vaadin application with Spring used as DI, but we are not interested in DispacherServlet - only root context, which we use to inject global (not user owned dependencies).
The way it works
I've defined root-context.xml file with content:
<context:annotation-config />
<context:spring-configured />
<context:load-time-weaver />
<context:component-scan base-package="com.example" />
And my web.xml has in it:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Then, some of my classes are defined with #Component annotation and others with #Configurable (the latter mostly belong to user session, so require DI for each instance created with new keyword).
I've got context.xml file with line:
<Loader delegate="false" loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader" />
And spring-instrument-tomcat-3.2.1.RELEASE.jar in Tomcat's lib directory.
All the dependencies are injected (with #Autowire) to my #Configurable classes correctly.
The way it doesn't work
Recently I've tried to get rid of root-context.xml and move context initialisation to Java #Configuration class.
I've created a class as follows:
#Configuration
#EnableSpringConfigured
#EnableLoadTimeWeaving
#ComponentScan("com.example")
public class BeansConfiguration
{
}
In addition I changed web.xml entries:
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.example.spring.BeansConfiguration</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Unfortunately, strange things started to happen. Let me show you an example. Simplifying my class structure looks as follows:
#Component
public class ComponentA
{
}
#Configurable
public class BeanB
{
#Autowired
private ComponentA componentA;
}
#Configurable
public class BeanC
{
#Autowired
private ComponentA componentA;
private BeanB beanB;
public BeanC(BeanB beanB)
{
this.beanB = beanB;
}
}
#Configurable
public class Application
{
#Autowired
private ComponentA componentA;
public Application()
{
}
public void init()
{
BeanC beanC = new BeanC(new BeanB());
}
}
With the XML setup, when it does work, ComponentA is correctly injected by Spring into all my #Configurable objects.
Strangely, with annotation-only configuration BeanC doesn't get the ComponentA injected (it's always null), howewer BeanB and Application do get that!
Have you got any ideas why would it happen? As soon as I comment out lines in web.xml to go back to my previous (XML-based) configuration all starts to work.
My happy guess is that XML Spring entries register something more under the cover than their annotation based counterparts. I've spend half a day trying to find out, what could that be, but I gave up. I would appreciate any suggestions.

Spring - context scan fail with requestfactory (gwt)

in a gwt web application i use spring.
if i use in my applicationContext.xml file
<context:component-scan base-package="com.test.**"/>
my bean is not found, i need to manually declare it in the applicationContext file.
my web.xml file
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>gwtRequest</servlet-name>
<servlet-class>com.google.web.bindery.requestfactory.server.RequestFactoryServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>gwtRequest</servlet-name>
<url-pattern>/gwtRequest</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>welcomeGWT.html</welcome-file>
</welcome-file-list>
Is there any reason why component scan fail?
Locator class
public class AccountLocator extends Locator<Account, Long> {
#Autowired
private AccountDAO accountDAO;
...
}
Spring service locator
public class SpringServiceLocator implements ServiceLocator {
#Override
public Object getInstance(Class<?> clazz) {
HttpServletRequest request = RequestFactoryServlet.getThreadLocalRequest();
ServletContext servletContext = request.getSession().getServletContext();
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);
return context.getBean(clazz);
}
}
Server layer
#Service
public class AccountServiceImpl implements AccountService{
#Autowired
private AccountDAO accountDAO;
...
}
Dao layer
#Repository
public class AccountDAOImpl implements AccountDAO{
...
}

Using ApplicationContext in Spring MVC.

I have a spring.xml file where in all the bean definitions are listed, where i have listed all the dependencies using beans, specified messageSource, dataSource etc. Also i have a class ApplicationContext class where iam using the context to get all the beans.
The code is ::
package models;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ApplicationContextClass {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
AbstractApplicationContext context = new ClassPathXmlApplicationContext("Spring.xml");
context.registerShutdownHook();
ATTModel attmodel = (ATTModel) context.getBean("att");
//ProjectModel project = (ProjectModel)context.getBean("project");
//project.call1();
attmodel.call();
System.out.println(context.getMessage("insertiondone",null, "Default greeting",null));
}
}
and i have Dao class where an applicationContext is used to access JDBCtemplate related bean. I have to develop a web application now using spring MVC and i need to use this applicationContext. How can i use these applicationContext classes in SpringMVC. I knw i need to use applicationcontextlisteners but where to write them ? Thanks..
You have two ways. In web.xml define this.
<servlet>
<servlet-name>yourapp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
And to your WEB-INF folder add yourapp-servlet.xml with your beans and mvc configuration.
Other way is. In web.xml define this.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
And to your WEB-INF add applicationContext.xml with your beans.
You can also combine these approaches.

Resources