How don't duplicate the dataSource in Spring xml files? - java

I have two files which contain the dataSource definitions. There are /WEB-INF/applicationContext.xml and src/main/resources/hibernateContext.xml
it's my dataSource definition:
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost/fullproject"
p:username="root"
p:password="admin" />
This definition is necessary in every file for using with different services; Can i don't duplicate this code and only definite it only in one place????

Yes, it's possible to factor out commons snippets into dedicated Spring XML file and then include them like this:
<!-- Import shared bean definitions -->
<import resource="classpath:shared.env.xml"/>

Those two "dataSource" beans can be shared. So you only need one definition.
In your web.xml, load the "master" configuration file:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:/applicationContext.xml
classpath*:/hibernateContext.xml
</param-value>
</context-param>

Related

Problem with replacing placeholders in xml configured in contextConfigLocation param

When I put placeholder in web.xml then it is correctly replaced by value defined in catalina.properties or -D param from vm options. But don't work when i put placeholder into xml which is loaded by ContextLoaderListener.
web.xml snippet:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
${placeholder}, <!-- WORKS -->
/WEB-INF/applicationContext.xml <!-- DON'T WORK, WHEN PLACEHOLDER IS DEFINED INSIDE XML -->
</param-value>
</context-param>
Problem solved. Xml defined in contextConfigLocation is loaded by spring and it is required to define bean from class org.springframework.beans.factory.config.PropertyPlaceholderConfigurer. Properties file can be empty. Values will be loaded from catalina.properties or vm options.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<value>classpath:example.properties</value>
</property>
</bean>

Externalize web.xml params in a Spring application

I have few parameters in web.xml file to be externalized. Application is in spring 4.0. Is there a spring way to do this?
More precisely, if I define PropertyPlaceholderConfigurer in context file, is there a way to use that for fetching properties in web.xml?
This is what I tried:
In applicationContext.xml:
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property
name="location"
value="classpath:/test.properties" />
<property
name="ignoreUnresolvablePlaceholders"
value="true" />
</bean>
Then in web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
</param-value>
</context-param>
But the below code returns param value as ${app.url}
<init-param>
<param-name>appUrl</param-name>
<param-value>${app.url}</param-value>
</init-param>
This is not possible as web.xml will be loaded before context initialization. The only solution for this is to move these properties to application server specific properties files.
I am using Tomcat and I moved this property to catalina.properties. Now it's working.

JSF + Spring integration [duplicate]

This question already has answers here:
Spring JSF integration: how to inject a Spring component/service in JSF managed bean?
(4 answers)
Closed 6 years ago.
I have a webmodule with JSF 2 end Spring 4.3. In a backing bean I use #Autowired for DI of a service of a JAR. In EAR module there are WAR, JAR with #Service Spring and JAR with Spring configuration file.
Below a web.xml snippet:
<context-param>
<param-name>locatorFactorySelector</param-name>
<param-value>classpath:beanRefContext.xml</param-value>
</context-param>
<context-param>
<param-name>parentContextKey</param-name>
<param-value>sharedContext</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
applicationContext.xml:
<context:annotation-config />
<context:spring-configured />
<!-- package of #Service class in jar module in EAR-- >
<context:component-scan base-package="com.ipdb.service" />
beanRefContext.xml:
<bean id="sharedContext" class="org.springframework.context.support.ClassPathXmlApplicationContext"> <constructor-arg>
<list>
<value>spring-ctx.xml</value>
</list>
</constructor-arg> </bean>
When I Use #Autowired(required=null) in a Backing Bean the value is null (there is not any exception). My JSF bean
#Component
#ManagedBean
#ViewScoped
public class PortfolioController {
#Autowired(required = true)
private PortfolioService portfolioService;
...
Can you help me, please.
PortfolioController is considered a JSF context bean adding #Component to #ManagedBean is totally wrong you can't mark same class as bean in two different contexts (JSF and Spring ).
Two solutions either make PortfolioController a spring bean thus remove the #ManagedBean and #ViewScoped or inject PortfolioController via JSF injection annotation #ManagedProperty
#ManagedProperty("#{portfolioService}")
private PortfolioService portfolioService;
if the applicationContext.xml is in your jar dependency, then you need to add asterisk after classpath:
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml</param-value>
</context-param>
With the asterisk spring search files applicationContext.xml anywhere in the classpath not only the current project.

How to prevent multiple bean instances?

I have a Spring-based web application, with two servlets - one for MVC and one for spring-ws. There are several beans used in the application, and they are autowired using annotations. Each time the application starts, it creates 3 instances of each bean type - even though they are singleton-scoped. The #PostConstruct methods are also called three times for each of them.
I understand that there are 3 application contexts = 1 common + 2 servlets, but each bean, controller, endpoint, etc. is created three times. At least the common beans, loaded in the parent application context should be instanced only once.
The base-package attribute of component-scan points to disjoint packages.
I've used a class to dump the context information (https://gist.github.com/1347171) and it appears there are three different contexts with identical structure (same beans). Their id's are "/project/", "/project/rest", "/project/soap".
I tried commenting out the ContextLoaderListener, removing the soap servlet and their associated XML files (applicationContext & soap-servlet) and moving the common stuff into the rest servlet (so that there is only one config xml and only one component-scan), and I still get 3 instances of each bean. In this case the application context id's are "/Project/" (exact casing), "/project/" and "/project/".
web.xml
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<servlet>
<servlet-name>rest</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>rest</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>soap</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>transformWsdlLocations</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>soap</servlet-name>
<url-pattern>/soap/*</url-pattern>
</servlet-mapping>
applicationContext.xml
<context:annotation-config/>
<context:component-scan base-package="test.common"/>
<task:annotation-driven/>
rest-servlet.xml
<mvc:annotation-driven/>
<context:component-scan base-package="test.rest"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<util:list id="beanList">
<ref bean="formHttpMessageConverter"/>
</util:list>
</property>
</bean>
<bean id="formHttpMessageConverter"
class="org.springframework.http.converter.FormHttpMessageConverter"/>
<mvc:interceptors>
<bean class="test.rest.Interceptor"/>
</mvc:interceptors>
soap-servlet.xml
<sws:annotation-driven/>
<context:component-scan base-package="test.soap"/>
<sws:dynamic-wsdl
id="service"
portTypeName="service"
locationUri="/soap/service"
targetNamespace="http://server/soap">
<sws:xsd location="/WEB-INF/SoapService.xsd"/>
</sws:dynamic-wsdl>
<sws:interceptors>
<bean id="validatingInterceptor"
class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
<property name="schema" value="/WEB-INF/SoapService.xsd"/>
<property name="validateRequest" value="true"/>
<property name="validateResponse" value="true"/>
</bean>
</sws:interceptors>
use the javax.ejb.Singleton annotation on your bean.
Well the reason is the slightly confusing documentation on spring mvc context initialization and these magical annotation defaults :(.
You probably have three copies because of the following:
your contextConfigLocation definition creates a root webapp context loading (only one per application) that is shared across all servlets. Each of your -servlet-config.xml files can access these beans but not vice versa.
Difference between applicationContext.xml and spring-servlet.xml in Spring Framework
so the second instance is coming from your -servlet application context because you defined the annotation-driven explicitly again.
Not sure which spring framework version you are using, but by defining both annotation-driven and custom request mapping adapter, you are pretty much creating two.
https://jira.spring.io/browse/SPR-8648
In fact, <mvc:annotation-driven> has all the tags to customize your adapter, check the schema which is what you want. Yet anther way to figure this out is by painful debugging in trace mode and looking at which bean is actually creating your adapter. Put a breakpoint in your adapter constructor and then look at the stack in DispatcherServlet->mapperHandler->interceptor->mapping->context->configFileLocation to see which file is creating this bean
If you do want to customize the message converters, you should be doing this:
<mvc:annotation-driven
content-negotiation-manager="contentNegotiationManager">
<mvc:message-converters register-defaults="false">
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="afterBurnerObjectMapper"/>
</bean>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>

No bean named '...' is defined and Spring #Resource annotation

I use #Resource to annotate bean classes, #Autowired to autowire dependencies,
and in Spring configuration file these things:
context:component-scan base-package="package1,package2"
tx:annotation-driven
So, it works fine (tested). Spring scans package1, package2, classes with #Resource annotation
and then I can get them using getBean() IF TESTED FROM CONSOLE APPLICATION [say, with main() function].
But when I try to use next approach (to use Spring in container managed environment = with Tomcat):
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:beans.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
compile a jar with all the bean classes and put this jar into WEB-INF/lib
then what I see? I cannot getBean() any of those #Resource annotated beans!
Spring simply cannot find them.
Still I can getBean() beans that are explicitly present in beans.xml.
Where's the problem?
Is missing <context:annotation-config/>?
<context:annotation-config/>
<context:component-scan base-package="package1"/>
<context:component-scan base-package="package2"/>
<tx:annotation-driven transaction-manager="transactionManager" />
or
<context:annotation-config/>
<context:component-scan base-package="package1, package2"/>
<tx:annotation-driven transaction-manager="transactionManager" />
I'm not sure how it's working in standalone mode, but the "" element in your Spring context allows the use "#Resource" annotations. Look at the Spring doc for more information.

Categories