Blueprint Developer Manual / Version 2512.0
Table Of ContentsCoreMedia applications are based on Spring Boot and as such support Spring Java configuration, Spring Boot auto-configuration, and Spring Boot configuration properties.
The recommended way to develop, extend, and configure CoreMedia applications is to follow the Spring Boot conventions. However, for backward-compatibility reasons, the CoreMedia component loader may still be used to activate component XML bean definitions and to load component properties files.
Spring Bean Customizer
A customizer is a mechanism which enables you to change an existing bean definition without
touching the actual configuration file of the bean. Technically speaking, a customizer is a
BeanPostProcessor
bean which adjusts the bean during startup of the
ApplicationContext.
The recommended way is to use Spring Java configuration and to annotate beans acting as customization sources
using the annotation class
com.coremedia.springframework.customizer.Customize.
However, a customizer can also be declared in a Spring XML file.
Examples
@Configuration(proxyBeanMethods = false)
static class AddEntriesToSomeMap {
@Bean(autowireCandidate = false)
@Customize("someMap")
Map<String, String> append() {
return Map.of("key1", "value1", "key2", "value2");
}
}
Here, two more entries key1 and key2 are added to a bean of type Map.
Although the recommended way to replace a predefined bean is to use Spring Primary annotation
(or XML attribute), there is also a customizer to replace the target bean:
@Configuration(proxyBeanMethods = false)
static class ReplaceLoginInterceptor {
@Bean(autowireCandidate = false)
@Customize(value = "loginInterceptor", mode = Customize.Mode.REPLACE)
MyLoginInterceptor myLoginInterceptor() {
return new MyLoginInterceptor();
}
}
Here, a predefined bean loginInterceptor is replaced with the bean myLoginInterceptor.
XML Syntax
Note
Important: The recommended way to customize beans provided by CoreMedia applications is to use the first mechanism of the following list that can be applied to the target bean.
Use external configuration (for example, system properties) to configure the bean.
Override injection of the target bean by using Spring's
Primaryannotation (or XML attribute).Define a source bean in Spring Java configuration style (for example, using
Component/ComponentScanorConfiguration/Bean) and add theCustomizeannotation.- Only use the XML customizers if none of the above can be used in your project.
The syntax to define a customizer is as follows (id attribute omitted):
<customize:operation
bean="beanname" [property="propertyname"]
custom-value="value"/>or
<customize:operation
bean="beanname" [property="propertyname"]
custom-ref="custom-beanname"/>or
<customize:operation bean="beanname" [property="propertyname"]>
<bean, map, set, list or properties>
</customize:operation>
Basically, an operation (<customize:operation>) is performed on a bean
(bean="...") or on a property of a bean (bean="..." property="...").
As a parameter of an operation, you can use a value (custom-value="...") or a
reference to a bean (custom-ref="..."). Instead of a bean reference, you can also
use an element <map>, <list>, <set>,
<properties>or <bean> as a parameter. The customizer can
be disabled by an attribute enabled="false".
The following operations are supported:
Replace - Depending on the context, a bean will be replaced by another bean or a bean property will be set to another value. If a bean is replaced, it is removed from the context and its name will be added as alias to the replacing bean. This way, wiring logic using the original name will work as expected, except for autowiring Maps where the name of the replacing bean will be used as key.
Append/Prepend - This operation works on beans or properties which are comprised of multiple elements, thus are of type List, Set, Map, String array and the like. The elements you add must be wrapped with the type of the property or bean that you modify (such as list, map or set). As you can see in the listing below you cannot add an element directly but instead, even if it is only one element that you wish to add, you have to wrap it. You can add elements to the start ("prepend") or end ("append").
<customize:append id="registerMyService" bean="myServices"
property="serviceList">
<list>
<ref bean="myServiceBeanId">
</list>
</customize:append>Wrap - This operation wraps a bean by another bean: it replaces a bean and injects the original bean into the new bean. The following example replaces the bean "service" by an instance of
WrapperServiceand injects the original "service" bean as a property "delegate" intoWrapperService:
<customize:wrap id="wrapService" bean="service"
wrapper-property="delegate">
<bean class="com.mycompany.WrapperService"/>
</customize:wrap>
If different customizers work on the same bean or property, conflicts may arise. Therefore, you
can use the attribute order to define the order of execution of the customizers.
<customize:replace id="registerMyService-1" bean="myService"
property="name"
custom-value="myService-1"
order="10"/>
<customize:replace id="registerMyService-2" bean="myService"
property="name"
custom-value="myService-2"
order="20"/>
The example shows two customizers, both working on the property name of the bean
myService. Due to the lower order value (10), the first customizer has a higher
priority and is executed first. Afterward, the second customizer overwrites this setting again.
Note
The rest of this chapter describes the component loader and related topics. This is mostly relevant for projects migrating from an old CoreMedia version to a recent one.
Component Loader
To activate the component loader, add the following dependency to your component or web application
module pom.xml file:
<dependency> <groupId>com.coremedia.cms</groupId> <artifactId>base-component</artifactId> <scope>runtime</scope> </dependency>
Example 4.2. Adding the Base Component
CoreMedia applications are hierarchically assembled from artifacts:
Library artifacts are used by
Component artifacts which are used by
Application artifacts.
Library Artifacts
Library artifacts contain JAR artifacts with Java classes, resources and Spring bean declarations.
An example is the artifact cae-base-lib.jar that contains CAE code as well
as the XML files which provide Spring beans.
Component Artifacts
Component artifacts provide a piece of business (or other high level) functionality by bundling
a set of services that are defined in library artifacts. Components follow the naming scheme
<componentKey>-component.jar. The component artifact
cae-component.jar for example, bundles all services that are typically
required by a CAE web application based project.
Component artifacts are automatically activated on application startup, in contrast to library artifacts. That is, Spring beans and properties are loaded into the application context and servlets and so on will be instantiated. Therefore, you can add a component by simply adding a Maven dependency. No additional steps (such as adding an import to a Spring file) are necessary.
The following files allow you to declare services for a component which are automatically activated:
/META-INF/coremedia/component-<componentname>.xml:An entry point for all component Spring beans. Either declared directly or imported from library artifacts.
/META-INF/coremedia/component-<componentname>.properties:All configuration options of the component as key/value pairs. These properties might be overridden by the concrete application.
Redundant Spring Imports
Note
This section is about Spring XML configuration files. The recommended way to configure Spring bean definitions is to use Spring Java configuration.
Due to the design of the Spring Framework and the CoreMedia component loader, it may often be necessary to declare many
<import/> elements in Spring XML configuration files, often pointing to the
same resource. This slows down the startup of the ApplicationContext.
Unfortunately,
org.springframework.beans.factory.xml.XmlBeanDefinitionReader does not
track imported XML files, so redundant <import/> elements will lead to
Spring parsing the same XML files over and over again (in most cases, those XML files will
contain more <import/> elements leading to even more parsing, ...) After
moving to Servlet 3.0 resources, for each <import/>, the JAR file
containing the XML file has to be unpacked. Also, every time that an XML file is completely
parsed, Spring reads all Bean declarations, creates new
org.springframework.beans.factory.config.BeanDefinition instances,
overwriting any existing bean definitions for the same bean ID.
The optional
Spring Environment property skip.redundant.spring.imports controls handling of
redundant imports. If set to true, the first
<import/> element will be used and all following, duplicate
<import/> elements pointing to the same resource will be ignored.
The property is true by default.
The time saved depends on the number of duplicated <import/> elements.
Caution
Even though this setting is recommended, it may change which bean definitions are loaded. (As
explained above, normally, bean definitions may be overwritten by subsequent imports,
depending on how <import/> elements are used in a web application).


