Spring afterPropertiesSet invoke before Servlet init? - java

I want to do some database search after tomcat startup.
So I just implements InitializingBean and implement method afterPropertiesSet and put database operating in afterPropertiesSet.
And, my project is using proxool.
Then I startup tomcat to test afterPropertiesSet method. I got this error
org.logicalcobwebs.proxool.ProxoolException: Attempt to refer to a unregistered pool by its alias
I thought its some thing wrong with the order of startup of the components in web.xml
<servlet>
<servlet-name>ServletConfigurator</servlet-name>
<servlet-class>org.logicalcobwebs.proxool.configuration.ServletConfigurator</servlet-class>
<init-param>
<param-name>propertyFile</param-name>
<param-value>WEB-INF/classes/jdbc.properties</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>ProxoolAdmin</servlet-name>
<servlet-class>org.logicalcobwebs.proxool.admin.servlet.AdminServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ProxoolAdmin</servlet-name>
<url-pattern>/proxool/admin</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config/application-context-*.xml</param-value>
</context-param>
Then I set one breakpoint at the first line of afterPropertiesSet method, the second breakpoint at the init method of org.logicalcobwebs.proxool.configuration.ServletConfigurator.
To avoid the error before, I just type a single print operat in afterPropertiesSet.
Then I startup tomcat to check the order of afterPropertiesSet and ServletConfigurator.
afterPropertiesSet method is invoked before ServletConfigurator init.
I have been figure out why I got Attempt to refer to a unregistered pool by its alias error.
But, How to let afterPropertiesSet invoke after ServletConfigurator init?
EDIT
And there is class GoodsRecommendService
#Service
public class GoodsRecommendServiceImpl implements InitializingBean {
#Override
public void afterPropertiesSet() throws Exception {
System.out.println("There is invoked before servlet init!!");
}
}

The issue is being caused by the fact that ServletContextListeners are invoked before all Servlets of the context are created. As the API for ServletContextListener states:
Receives notification that the web application initialization process is starting.
All ServletContextListeners are notified of context initialization before any filters or servlets in the web application are initialized.
So in your configuration:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config/application-context-*.xml</param-value>
</context-param>
means that your Spring ApplicationContext is created before any of the Servlets. This is why you are getting your error.
To fix it you need to ensure that whatever you are trying to do in your bean, you do it once the Proxool servlet is properly initialised.
I think the easiest way to do this is to switch your Spring ApplicationContext to be loaded by DispatcherServlet and ensure that the load-on-startup value for DispatcherServlet is greater than that of the Proxool servlet.
For more information on DispatcherServlet, see here.

An alternative approach might be to make sure Spring application context will configure Proxool, as in the following example:
<bean id="proxoolProperties" class=" org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="classpath:proxool.properties"/>
</bean>
<bean id="proxoolConfiguration" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="org.logicalcobwebs.proxool.configuration.PropertyConfigurator" />
<property name="targetMethod" value="configure" />
<property name="arguments" ref="proxoolProperties" />
</bean>

Related

Spring Scheduling: #Scheduled annotation on a method inside a class annotated with #Controller runs twice

Consider the below code snippet:
#Controller
public class RestController {
#Scheduled(cron = "0 0 */* * * ?") // run every hour
public void runMeHourly() {
LOGGER.debug("RestController#runMeHourly triggered to run at: " + System.currentTimeMillis());
// Do your hourly work here
}
}
When I deploy this controller in a J2EE web server I see that the method RestController#runMeHourly() in triggered twice every hour.
I found a reference to something like this here on spring docs scheduling.
It says:
Make sure that you are not initializing multiple instances of the same #Scheduled annotation class at runtime, unless you do want to schedule callbacks to each such instance. Related to this, make sure that you do not use #Configurable on bean classes which are annotated with #Scheduled and registered as regular Spring beans with the container: You would get double initialization otherwise, once through the container and once through the #Configurable aspect, with the consequence of each #Scheduled method being invoked twice.
Is this related? Does this mean I need to Schedule the method runMeHourly() from outside the RestController?
[Edit 1: Looks like the #Configurable is something else and not contributing to the problem, and I have not used it anywhere. So there must be some other reason that is causing this behaviour]
[Edit 2:
My web.xml:
<web-app>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>com.company.module.ModuleContextListener</listener-class>
</listener>
</web.xml>
mvc-dispatcher-servlet.xml
<beans>
<mvc:annotation-driven />
<task:annotation-driven />
<context:component-scan base-package="com.company" />
<import resource="module/module-servlet.xml"/>
</beans>
module/module-servlet.xml
<beans>
<context:component-scan base-package="com.company.module"/>
</beans>
]
The com.company.module.ModuleContextListener is forcing the DispatcherServlet to look for a root application context, and since the root application context is same as mvc-dispatcher-servlet.xml its being loaded twice. Once as root context and again under DispatcherServlet with the name mvc-dispatcher.
Renaming the root context xml mvc-dispatcher-servlet.xml to applicationContext.xml and adding an empty mvc-dispatcher-servlet.xml solves the problem.
Thanks to #6ton for pointing this out.

Unable to use exposed bean which uses RequiredAnnotationBeanPostProcessor

I am creating a war which is going to use a class from a jar file.
Now this jar file has a exposed a bean in its associationApplicationContext.xml which uses the #Required annotation on some of its properties for initialization.
associationApplicationContext.xml
e.g.
<!-- processes #Required annotations-->
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
<!-- The client bean to access the association rest web service -->
<bean id="associationClient" class="com.springtest.client.AssociationClientImpl">
<property name="associationRestClient" ref="associationServiceRestClient" />
</bean>
So inside the AssociationClient the property associationRestClient has #Required tag over its setter method.
#Required
public void setAssociationRestClient(final AssociationRestClient associationRestClient) {
this.associationRestClient= associationRestClient;
}
Now, as when I try to use this bean in my war file -
I have already put the jar dependency in pom.xml of war file
Already put the contextConfigLocation in web.xml as
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:/associationApplicationContext.xml
</param-value>
</context-param>
Using the bean from inside the war file in another applicationcontext.xml file as
<import resource="classpath:/associationApplicationContext.xml"/>
<bean id="requestHandlerV1"
class="com.springtest.application.RequestHandlerV1">
<property name="associationClient" ref="associationClient"></property>
</bean>
Here the property associationClient is not getting initialized because it is not able to find the reference to bean associationRestClient which is associationServiceRestClient
I am getting
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'associationServiceRestClient' is defined
How can I get the object of associationClient initialized here ?
PS : I cannot change the implementation which uses #Required annotation
Assuming you have the following:
In web.xml:
<!-root application context-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:associationApplicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>JerseySpringWebApplication</servlet-name>
<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationcontext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!--URl for web service -->
<servlet-mapping>
<servlet-name>JerseySpringWebApplication</servlet-name>
<url-pattern>/service/*</url-pattern>
</servlet-mapping>
You don't have to import the associationApplicationContext.xml in applicationcontext.xml as now the root application beans will be visible in applicationcontext.xml. So application Context.xml will be like:
<mvc:annotation-config/>
<bean id="requestHandlerV1" class="com.springtest.application.RequestHandlerV1">
<property name="associationClient" ref="associationClient"></property>
</bean>
*Assuming you are invoking the controller through rest call.
If you still see issue with this, post your log.

Why Beans on spring-servlet.xml can't access beans in my applicationContext.xml

I have a question here, how beans defined in "applicationContext.xml" could be available to controllers defined in let's say "spring-servlet.xml", so i can skip this kind of errors i have.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name '/home' defined in ServletContext resource [/WEB-INF/mmapp-servlet.xml]: Cannot resolve reference to bean 'equipementService' while setting bean property 'equipementService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'equipementService' is defined
applicationContext.xml
<?xml version="1.0" ?>
<!DOCTYPE beans PUBLIC
"-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean name="equipementService"
class="mmapp.service.SimpleEquipementService" />
<bean name="equipement1"
class="mmapp.domain.Equipement" />
</beans>
mmapp-servlet.xml
<?xml version="1.0" ?>
<!DOCTYPE beans PUBLIC
"-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean name="/home" class="mmapp.web.HelloController">
<property name="equipementService" ref="equipementService" />
</bean>
</beans>
A Spring based web-application normally has multiple runtime Spring application contexts -
A root application context(which is loaded up during the start-up of the servlet container), here is where you normally put your beans for your services - the root application context is loaded up by using a ContextLoaderListener, typically using these entries in your web.xml file:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
</context-param>
One or more web application contexts, which is considered a child of the root application context, holding the beans related to the UI - controllers etc. This is configured by using a Dispatcher Servlet, a special servlet provided by Spring that knows to delegate the calls appropriately to the Spring Container. The beans in the root application context are visible to the beans defined here, BUT not the other way around - this way providing a level of separation between the UI layer and the services layer . This is a typical configuration entry in web.xml file:
<servlet>
<servlet-name>lovemytasks</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/mmapp-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
If you have defined the beans this way, the equipementService should be visible to your controller.
I'm not an expert and I'm not sure if this might be a problem, but I have a suggestion.
Could you post your web application descriptor (web.xml)? Does it contain the context-param?
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml</param-value>
</context-param>

JavaConfig problem in web application (Vaadin + Spring)

UPDATED
I found an suspicious log entry:
org.springframework.beans.factory.wiring.BeanConfigurerSupport:
BeanFactory has not been set on BeanConfigurerSupport: Make sure this configurer runs in a Spring container.
Unable to configure bean of type [com.mycompany.projectname.App]. Proceeding without injection.
/UPDATED
I'm working on an Vaadin + Spring application and I wish to use JavaConfig.
According to some tutorial I built them up separately, but when I merge them I got the following (see the first codesnipet App.java - logger.info(">>mainWindow is null");)
app postconstruct ---------
mainWindow is null
I tried several variation of configs for example in applicationContext and so forth.
So my question is: how can I find out real problem ?
Thanks for your time and effort in advance.
Csaba
App.java
#Configurable
public class App extends Application
{
public MainWindow mainWindow;
public MainWindow getMainWindow(...
public void setMainWindow(Main....
#PostConstruct
public void init()
{
logger.info(">>app postconstruct --------- ");
if(mainWindow==null) logger.info(">>mainWindow is null");
else logger.info(">>mainWindow is not null");
}
AppConfig.java
#Configuration
public class AppConfig {
...
#Bean
public MainWindow mainWindow(){
return new MainWindow();
}
....
}
web.xml based on this !tutorial link!
...
<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.mycompany.projectname.config.AppConfig</param-value>
</context-param>
...
<servlet>
<servlet-name>Vaadin Application Servlet</servlet-name>
<servlet-class>com.vaadin.terminal.gwt.server.ApplicationServlet</servlet-class>
<init-param>
<description>Vaadin application class to start</description>
<param-name>application</param-name>
<param-value>com.mycompany.projectname.App</param-value>
</init-param>
<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>com.mycompany.projectname.config.AppConfig</param-value>
</init-param>
</servlet>
Why are you using #Configurable? Do you mean to be using #Component instead?
#Configurable is typically used on domain objects (aka entities) that are not otherwise Spring-managed objects to allow them to receive dependency injection from the Spring container. This does not appear to be your goal. You should probably simply be wiring up your "App" class as another #Bean method, or otherwise marking it with #Component and picking it up via component-scanning (e.g. with #ComponentScan). Check out the related Javadoc and reference documentation for these annotations for more info.
Your annotations will not work if you didn't enabled them.
Do you have the following in your project spring context xml ?
<!-- Activate Spring annotation support -->
<context:spring-configured/>
<!-- Turn on #Autowired, #PostConstruct etc support -->
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />
<!-- Scans the classpath of this application for #Components to deploy as beans -->
<context:component-scan base-package="com.tc.poc.vaddinspring" />
Update: Look at this skeleton.

Spring AOP: Aspect triggering when configuration is in Servlet context, but not application context?

I'm using Spring 3.0.x with Spring AOP.
So, I have the following Aspect:
#Aspect
public class TestAspect {
#Pointcut(value="#annotation(Bar)", argNames="Bar")
public void pointCutMethod(Bar bar)
{
}
#Before(value="pointCutMethod(Bar)", argNames="Bar")
public void wrapPublishMethod(Bar bar) throws Throwable
{
// Do something crazy
}
}
And I have the following class and method:
public class Foo {
#Bar
public void doSomething() {
// do another thing
}
}
Now, here is my application context (without my AOP config):
<bean id="testAspect" class="org.xyz.TestAspect" />
<bean id="foo" class="org.xyz.Foo" />
I'm trying to wire up my aspect using the following declaration:
<aop:aspectj-autoproxy />
When I place <aop:aspectj-autoproxy /> in my application context, the pointcut/aspect is not getting triggered. However, if I place <aop:aspectj-autoproxy /> in my servlet configuration, all is well and everything works.
Why does my above setup work with <aop:aspectj-autoproxy /> in the servlet context, but not in the application context???
EDIT:
Here are the relevant web.xml lines:
<servlet>
<servlet-name>XYZ</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!-- Aspect works when config line is in this file -->
<param-value>/WEB-INF/classes/xyz-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<context-param>
<param-name>contextConfigLocation</param-name>
<!-- Aspect DOES NOT work when config line is in one of the files below -->
<param-value>/WEB-INF/classes/xyz-application-context.xml, /WEB-INF/classes/xyz-aspectConfig.xml</param-value>
</context-param>
The servlet context param is intended to be read by a ContextLoaderListener (if that is defined in your web.xml), not by the FrameworkServlet (or its derivatives, like DispatcherServlet).
The ContextLoaderListener would create a root application context (parent of all the servlet application contexts) from the config locations specified as servlet context parameter. If the servlets would read that too, the same beans would be re-defined within the servlet application context instead of just inheriting them from the parent app-ctx.

Categories