Where do I put my beans?
Posted by davidnewcomb on 09 Dec 2008 in Java
Where do I put my beans? What beans? Coffee beans? Java beans? No - Spring beans!
When running a servlet container, such as Apache Tomcat, you must define all your java beans in such a way as to facilitate the separation of the live and development system and yet allows you to remain within what is accepted as a “standard approach".
There isn’t much advice or documentation online to help with this, so there follows an out-line of collected knowledge absorbed from reading lots of configuration files.
When a servlet container starts up, it reads the
/WEB-INF/web.xml
file which defines the configuration of the servlet. This file is typically a pointer to 2 other files. The first is named /WEB-INF/myproj-webapp-config.xml
and the second is named /WEB-INF/myproj-servlet-config.xml
.
Lets take a look at the /WEB-INF/web.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID"
version="2.5"
>
<display-name>My Project</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/myproj-webapp-config.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>myproject</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/myproj-servlet-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>myproj</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
</web-app>
After the Java EE header and standard configuration comes the first of the 2 file pointers. The contextConfigLocation
is described in the /WEB-INF/myproj-webapp-config.xml
. This file contains the beans for the application. These are the Java beans that in the most part “do all the work". This file is laid out in a way that separates the business logic from the live application infrastructure.
Below is a typical example to help explain this:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<!-- Configuration -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<value>file:C:/Data/conf/bigsoft.properties</value>
</property>
</bean>
<!-- application beans -->
<import resource="classpath:uk/co/bigsoft/myproj/config/application-config.xml"/>
<!-- Data source Access -->
<import resource="classpath:uk/co/bigsoft/myproj/config/database.xml"/>
<!-- Real Dao -->
<import resource="classpath:uk/co/bigsoft/myproj/config/dao.live.xml"/>
<!-- Transaction support -->
<import resource="classpath:uk/co/bigsoft/myproj/config/tx.xml"/>
<!-- JMS support -->
<import resource="classpath:uk/co/bigsoft/myproj/config/jms.xml"/>
</beans>
The header says that this is a file containing spring beans. It is split into several sections.
The first bean (PropertyPlaceholderConfigurer
) is a configuration post-processor which substitutes variables given as part of the definition of other beans, and is really handy because this properties file can exist anywhere.
The application-config.xml
file contains the business logic. This is the logic of the application that remains the same in the live and the development system, because it has been abstracted away from the infrastructure which follows. Each import
pulls in a configuration file containing beans which take care of an infrastructural aspect of the application while it runs in the live environment. In the case above I have split them up by technologies. Using database.xml
as an example, I may have one file which uses MySQL and another that uses Oracle depending on my deployment strategy at that location.
The second file pointer from /WEB-INF/web.xml
points to the Servlet Dispatcher which is in charge of routing web traffic (or web services) to beans within my application. There is not much in here really. The file is the interface layer which utilizes the servlet container. The configuration file would change (somewhat) depending on what servlet container (or application server) you were using.
/WEB-INF/myproj-servlet-config.xml
is included for completeness
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd"
>
<context:component-scan base-package="uk.co.bigsoft.myproj" />
<!-- Resolves logical view names to JSP views -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- Returns messages based on a resource bundle -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="/WEB-INF/messages/validation" />
</bean>
</beans>
The main idea behind this layout is to promote the separation of concerns. The application-config.xml
file will almost certainly be split into several other files, to allow a more modular test approach. As you can see the components relating to the database, transaction model, JMS and other infrastructural aspects of the application are split away from the business logic. The business beans are not concerned with these behaviours, in fact the more decoupled from the rest of the system the better.
Now that infrastructure is split from business the test environment can take full advantage of Spring’s Inversion of Control mechanism by faking up (or mocking) the infrastructural components and injecting them into the business beans. The mocks implement the same interfaces as the real beans and so test harnesses can be easily written.No feedback yet
Form is loading...