-
Notifications
You must be signed in to change notification settings - Fork 2
Spring configuration
New Spring files should be placed in the standard location within each module (src/main/resources/spring/com/<project>/<module>). Access to these files via the classpath is then the same regardless of the start-up methodology (test, command-line, war file, or os wrapper). Spring files are loaded with ClassPathXmlApplicationContext, which takes an array of classpath locations, which means you can load multiple Spring configurations at one time.
new ClassPathXmlApplicationContext("com/<project>/foundation/foundation.xml", "com/<project>/foundation/logging.xml", "com/<project>/<module>/application.xml");Of course, Spring files may also refer to each other internally, via import tags as well, in which case the files will be loaded recursively, and do not need to be listed individually in the context constructor. As a general rule, it's better to list the files within the context constructor than to use imports. Why, I hear you say? Isn't listing the files over and over again both redundant and error prone? Yes, it is. However, when Spring iterates recursively through imported config files, from multiple sources, it's forced to re-define those contexts, over and over again, which is worse. That being said, when one config file references the beans from another, and the referenced files are imported, your IDE will probably verify those files for you, and allow you to navigate from one bean definition to the next, or to the referenced code. That's very convenient, and a good reason to import. When to use which method is then left as an exercise for the reader, and you'll need to use your best judgment.
This Spring bean sets the value of environment variables available to Spring and Java code via System.getProperty() calls. This works on a 'first set value wins' basis. That means that the first value actually set is the one used, and any later attempt to override that value will be ignored. Which means that any value set on the command line via a '-D' command line parameter will take precedence over anything set within a Spring config file.
There are a couple of Spring config files which are loaded, and therefore listed, within every context. These are...
- application.xml - Sets up the application id and database in use for the application (see Property Files).
- foundation.xml - From the foundation module, this sets up the property file inheritance scheme and defaults for system property variables (see Property Files).
- logging.xml - Uses the previous information to set up the loggers, files locations, and filtering levels.
Let's take a closer look at these...
<?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-3.0.xsd">
<bean class="org.smallmind.nutsnbolts.spring.SystemPropertyInitailizingBean">
<property name="order" value="0"/>
<property name="propertyMap">
<map>
<entry key="<project>_APPLICATION" value="<module name>"/>
</map>
</property>
</bean>
</beans>Please take note of the order property. Setting this to 0 denotes that these properties will be used fist, and take precedence over anything except command line parameters. 0 is the lowest priority that any client code should use, as Spring reserves negative values for itself and its internal processing. In this case, application.xml simply sets the name of the application within this instance of the JVM.
<?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-3.0.xsd">
<import resource="classpath:com/<project>/foundation/logging.xml"/>
<bean class="org.smallmind.nutsnbolts.spring.SystemPropertyBeanFactoryPostProcessor">
<property name="order" value="1"/>
<property name="propertyMap">
<map>
<entry key="<project>_ENVIRONMENT" value="de"/>
<entry key="<project>_DATABASE" value="mysql"/>
<entry key="<project>_APPLICATION" value="foundation"/>
<entry key="<project>_PRODUCT" value="any"/>
</map>
</property>
</bean>
<bean id="allProperties" class="org.smallmind.nutsnbolts.spring.PropertyPlaceholderConfigurer">
<property name="order" value="2"/>
<property name="ignoreResourceNotFound" value="true"/>
<property name="ignoreUnresolvableProperties" value="false"/>
<property name="systemPropertyMode" value="OVERRIDE"/>
<property name="searchSystemEnvironment" value="true"/>
<property name="locations">
<list>
<value>classpath:com/<project>/foundation/global.properties</value>
<value>classpath:com/<project>/foundation/database-${PROJECT_DATABASE}.properties</value>
<value>classpath:com/<project>/foundation/${PROJECT_ENVIRONMENT}/environment.properties</value>
<value>classpath:com/<project>/foundation/${PROJECT_ENVIRONMENT}/database-${PROJECT_DATABASE}.properties</value>
<value>classpath:com/<project>/${PROJECT_APPLICATION}/application.properties</value>
<value>classpath:com/<project>/${PROJECT_APPLICATION}/database-${PROJECT_DATABASE}.properties</value>
<value>classpath:com/<project>/${PROJECT_APPLICATION}/${PROJECT_ENVIRONMENT}/application.properties</value>
<value>classpath:com/<project>/${PROJECT_APPLICATION}/${PROJECT_ENVIRONMENT}/database-${PROJECT_DATABASE}.properties</value>
<value>classpath:com/<project>/${PROJECT_APPLICATION}/${PROJECT_PRODUCT}/application.properties</value>
<value>classpath:com/<project>/${PROJECT_APPLICATION}/${PROJECT_PRODUCT}/database-${PROJECT_DATABASE}.properties</value>
<value>classpath:com/<project>/${PROJECT_APPLICATION}/${PROJECT_PRODUCT}/${PROJECT_ENVIRONMENT}/application.properties</value>
<value>classpath:com/<project>/${PROJECT_APPLICATION}/${PROJECT_PRODUCT}/${PROJECT_ENVIRONMENT}/database-${PROJECT_DATABASE}.properties</value>
<value>file:/home/im/config/${PROJECT_APPLICATION}/local.properties</value>
<value>file:${user.home}/.m2/local.properties</value>
<value>file:${user.home}/.m2/database-${PROJECT_DATABASE}.properties</value>
</list>
</property>
</bean>
</beans>This file grants default values to any system property variables not yet set (note the order of 1), and creates the property file inheritance structure (note the order of 2). Unlike the system property setup, later property file values will override those in files listed earlier.
- Note - These base system properties are ill-named, as they use the linux environment variable convention, as opposed to a proper dot notated Java convention. Please, do not follow this example in any other case. Use the standard Java convention. The base system properties are named this way to allow them to be set from the os shell on linux systems, which will choke on a dot notated convention.
<?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-3.0.xsd">
<!-- Logging Templates -->
<bean id="defaultTemplate" class="org.smallmind.scribe.pen.DefaultTemplate" init-method="register">
<property name="appenders">
<list>
<ref bean="consoleAppender"/>
<ref bean="fileAppender"/>
<ref bean="errorFileAppender"/>
</list>
</property>
<property name="level" value="INFO"/>
</bean>
<!-- Logging Framework Setup -->
<bean id="shortTimestamp" class="org.smallmind.scribe.pen.DateFormatTimestamp">
<property name="dateFormat">
<bean class="java.text.SimpleDateFormat">
<constructor-arg index="0" value="yyyy-MM-dd"/>
</bean>
</property>
</bean>
<bean id="fullTimestamp" class="org.smallmind.scribe.pen.DateFormatTimestamp">
<property name="dateFormat">
<bean class="java.text.SimpleDateFormat">
<constructor-arg index="0" value="yyyy-MM-dd'T'HH:mm:ss.SSSZ"/>
</bean>
</property>
</bean>
<bean id="xmlFormatter" class="org.smallmind.scribe.pen.XMLFormatter">
<property name="timestamp" ref="fullTimestamp"/>
</bean>
<bean id="patternFormatter" class="org.smallmind.scribe.pen.PatternFormatter">
<property name="timestamp" ref="fullTimestamp"/>
<property name="format" value="%d %n %+5l (%F.%M:%L) [%T] - %m%!+\n\t!w"/>
</bean>
<bean id="consoleAppender" class="org.smallmind.scribe.pen.ConsoleAppender">
<property name="formatter" ref="patternFormatter"/>
</bean>
<bean id="timestampRollover" class="org.smallmind.scribe.pen.TimestampRollover">
<property name="timestampQuantifier" value="TOP_OF_DAY"/>
<property name="separator" value="-"/>
<property name="timestamp" ref="shortTimestamp"/>
</bean>
<bean id="warnLevelFilter" class="org.smallmind.scribe.pen.LevelFilter">
<property name="level" value="WARN"/>
</bean>
<bean id="consoleErrorHandler" class="org.smallmind.scribe.pen.DefaultErrorHandler">
<property name="backupAppender" ref="consoleAppender"/>
</bean>
<bean id="fileAppender" class="org.smallmind.scribe.pen.FileAppender">
<property name="logFilePath" value="${log.dir}/${PROJECT_APPLICATION}/log.txt"/>
<property name="rollover" ref="timestampRollover"/>
<property name="formatter" ref="patternFormatter"/>
<property name="errorHandler" ref="consoleErrorHandler"/>
</bean>
<bean id="errorFileAppender" class="org.smallmind.scribe.pen.FileAppender">
<property name="logFilePath" value="${log.dir}/${PROJECT_APPLICATION}/error-log.txt"/>
<property name="rollover" ref="timestampRollover"/>
<property name="filter" ref="warnLevelFilter"/>
<property name="formatter" ref="patternFormatter"/>
<property name="errorHandler" ref="consoleErrorHandler"/>
</bean>
<bean id="fileErrorHandler" class="org.smallmind.scribe.pen.DefaultErrorHandler">
<property name="backupAppender" ref="errorFileAppender"/>
</bean>
</beans>This file sets up basic logging. Note the use of the system property variables to determine the log file in use, and the base logging location. The 'environment variable-like' system properties, such as '${PROJECT_APPLICATION}', should be overridden in application.xml, while the more standard dot-notated properties, such as '${log.dir}', may be set or overridden at the global, application, or local level (see Property Files).