
Note
|
The Broadleaf Manifest and Initializr are compatible with Broadleaf Release Train 1.8.2 and above. |
A standard Initializr project can be set up with Broadleaf Release Train 1.8.2 and above. However, some of the features discussed in this article have been added in later versions. Therefore, if your Initializr composition ends up significantly different from a standard one, you may find it necessary to upgrade your Release Train version. You can find more information on new Initializr features in each Release Train’s upgrade notes, where such changes are typically highlighted. Alternatively, seek advice on your specific composition with our team through the appropriate support channels.
General familiarity with Broadleaf Initializr concepts to the extent described in the overview article.
Here is a high-level overview of the steps to migrate from a MicroservicesDemo-style project to an Initializr project:
Generate an Initializr project following the Project Generation guide. This standard project will serve as the basis of all steps to follow in this guide.
Tip
|
If you are planning to use two or more flexpackage compositions to run your project (i.e. Mono for local development and Balanced for nonlocal deployment), select the more granular of the compositions in this step. |
Important
|
This migration guide assumes your project will be leveraging a Spring Cloud Config Server implementation for property management. This is strongly recommended by Broadleaf. It is possible to adopt Initializr without using Config Server (you can disable the |
If your current MicroservicesDemo project uses only a subset of Broadleaf Microservices, and you want your Initializr project to reflect that as well, services can be disabled within the manifest.yml
file.
Simply remove the services from the list of flexUnits
of your flexpackages and set their routed
properties to false
(See screenshot below for an example).
Now, the directories for those services can be safely removed. You may also need to delete dependencies on those services from various places around the project, such as the Data Ingestion and Manifest modules, as well as the flexpackages.
Alternatively, the manifest can take care of that removal for you by re-generating the project (i.e. run mvn flex:generate -DforceClean=true
).
Fair warning - any customization you’ve made to the code or files except the manifest.yml
file will be lost if this command is run.
The standard Initializr project structure includes separate directories for each flexpackage of your composition as well as a directory for each component you are customizing. There are additional components like the Data Ingestion module that will have their own directories.
The Initializr project will become the new structure to store customizations and launch the applications. Therefore, it should be checked into your version control system (VCS). We recommend maintaining a repository for each top-level directory of the project. You should be able to reuse many of your repositories from a MicroserviceDemo-style project.
Important
|
Contents of the security directory should NOT be stored in source control, but instead should be uploaded and managed in a secure location such as an encrypted vault.
|
Note
|
If you are running Granular as your flexpackage composition, the number of repositories needed can get out of hand. See the repository footprint reduction workaround section for a potential recommendation. |
Important
|
This workaround causes deviation from the standard project structure that the Broadleaf starter module is aware of. This can have side effects that prevent operations such as As a result, in most cases, we do not advise following this workaround. We only provide it here as guidance for advanced clients who may be comfortable proceeding with this approach. Future versions of the Broadleaf starter may come with built-in support for generating and interpreting a more reduced directory structure, and this documentation will be updated at the time such a feature is made available. Until then, do note that there are advantages to the 'flat' directory structure that is currently used by default, despite its higher repository footprint. The primary advantage is that it facilitates easy recombination. A component module itself does not need to know how it will be combined or used in different flexpackages, and the separation of directory structure encourages this. |
Depending on your flexpackage composition, a transition to Initializr may actually increase the number of repositories you need to maintain. This is especially true for Granular compositions, where the number of repositories nearly doubles as services with customizations each end up with one more repository. We have found that it is possible to avoid this, and the following example describes the steps to make that happen:
As an example, let’s say your current project runs a Granular composition and contains code customizations in the AdminUser service.
The skeleton Initializr project you generated should contain two folders for AdminUser: adminuser
and adminuserComponent
.
The adminuser
folder is the flexpackage - it contains the runnable Application and pulls in the adminuserComponent
as a Maven dependency.
The adminuserComponent
is the component - only client code customizations are stored there, and it does not have a runnable Application, instead serving as a mere dependency for any flexpackage pulling it in.
Additionally, it pulls in the Broadleaf AdminUserServices as its dependency to build on top of.
To avoid creating another VCS repository to accommodate the component, you should create two sub-folders in your current repository directory (e.g. AdminUserServices/
): flexpackage
and component
.
In the following sections, we will discuss steps of integrating Initializr concepts into your current project.
The flexpackage
directory should be used for files from the adminuser
folder, meanwhile the component
directory should contain files from adminuserComponent
.
As would be the case with entirely separate directories, both sub-folders are still separate Maven modules (as proven by their pom.xml
files) and thus continue to participate in the project as if they were separate.
The top-level service directory now contains an orchestration pom that simply declares the sub-folders (flexpackage
and optionally component
) as modules.
Each sub-folder contains a pom.xml
file designed to handle the sub-folder’s intended responsibilities.
pom.xml
filesThe pom.xml
files are responsible for defining properties, dependencies, and plugins for each of your services.
They are also getting a face-lift with the Initializr.
While each service used to have a single pom to handle all responsibilities, we have divided them according to responsibilities.
The following example poms of Release Train 2.1.0-GA ContentServices (in a Granular configuration) will help us walk through all the updates:
The largest change comes from adopting a new parent pom - com.broadleafcommerce.microservices:broadleaf-microservices-flex-parent
.
This parent pom sets versions and pulls in the necessary dependencies to run a Broadleaf microservice.
The skip…
properties (e.g. skip-schema
) enable a developer to control the execution of the various Initializr-related Maven plugins.
The generated project has the correct values set for each of the properties (default value is true
) to run a standard Initializr configuration.
However, if your team has decided to diverge from the standard, the HELP.md
file provided in the manifest folder details the purpose of each property.
For example, removing the skip-schema
entry would disable automatic liquibase generation if your team decides to manually write liquibase additions.
The client name property - broadleaf-client-prefix
- should be set to the name you expect to appear in changelog file names and other locations around the project.
It would most likely contain the same value for all services.
Broadleaf also introduced a new path of generating and booting up docker images.
There is a number of properties in your pom.xml
files that control the deployment of the images (see example screenshot below).
They can be removed if your team has decided not to adopt the new process.
The following new dependencies can be found in Initializr pom.xml
files:
The manifest is a new Initializr-only Broadleaf concept. Services should have it as a dependency to receive the benefit of dynamic configuration properties.
The manifest/
directory in your project corresponds to the Maven module that produces this artifact.
Here is an example of what the dependency can look like:
<dependency>
<groupId>com.example.microservices</groupId>
<artifactId>microservice-flexpackage-manifest</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
Client implementation of Broadleaf services depend on Broadleaf’s service (e.g. AdminUserServices
) as a base.
With Initializr, this dependency becomes a bit more nuanced:
When a service contains code customizations, it will require for a component to be created in the Initializr project structure.
The flexpackage will then depend on the component:
<dependency>
<groupId>com.example.microservices</groupId>
<artifactId>microservice-component-inventory</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
And the component will contain a dependency on the Broadleaf base service:
<dependency>
<groupId>com.broadleafcommerce.microservices</groupId>
<artifactId>broadleaf-inventory-services</artifactId>
</dependency>
Note
|
The Broadleaf base service’s version is set by the flex-parent according to the Release Train at its specified version. |
To leverage Broadleaf’s Config Server feature set, each flexpackage should reference your Config Server maven coordinates as a dependency:
<dependency>
<groupId>com.broadleafcommerce.microservices</groupId>
<artifactId>broadleaf-config-server-client</artifactId>
</dependency>
One of the recent versions of Spring Cloud Stream has removed support for annotation-based configuration. Broadleaf has re-introduced the removed annotations and provided backward compatibility as an option for clients. More on this here
Dependencies that support this compatibility both in code and in tests should be included in each flexpackage and component to facilitate normal operations:
<dependency>
<groupId>com.broadleafcommerce.microservices</groupId>
<artifactId>broadleaf-common-extension-compatibility</artifactId>
</dependency>
<dependency>
<groupId>com.broadleafcommerce.microservices</groupId>
<artifactId>broadleaf-common-extension-compatibility-test</artifactId>
<scope>test</scope>
</dependency>
We recommend transitioning custom dependencies to the component along with your customizations in Migrating code customizations.
With Initializr, both Liquibase change-sets and configuration properties need to be split up between the Flexpackage and the Component modules for each service. The exact distinction between the two modules can seem fuzzy, so here is a good summary to begin with:
In short, Flexpackages are responsible for determining environment-specific configurations and contain files specific to the deployment.
Components are responsible for contributing your customizations. They contain properties and changesets that go with the service, regardless of the environment or flexpackage composition.
This matrix table can be used to guide you through nuanced best practices of placing change-sets and properties on either side of the Component vs Flexpackage split.
Entity | Type | Environment-specific | Example | Service has component | Destination |
---|---|---|---|---|---|
Liquibase changeset |
Seed Data |
No |
|
Yes or No |
Flexpackage |
Liquibase changeset |
Seed Data |
Yes |
|
Yes or No |
Flexpackage |
Liquibase changeset |
Broadleaf Override |
No |
|
Yes or No |
Flexpackage |
Liquibase changeset |
Broadleaf Override |
Yes |
|
Yes or No |
Flexpackage |
Liquibase changeset |
Generated Customization |
No |
|
Yes |
Component |
Liquibase changeset |
Data Migration to run before required starter data |
No |
|
Yes |
Component |
Configuration Parameter |
Broadleaf Override |
No |
|
Yes |
Component |
Configuration Parameter |
Broadleaf Override |
No |
|
No |
Flexpackage |
Configuration Parameter |
Broadleaf Override |
Yes |
|
Yes or No |
Flexpackage |
Configuration Parameter |
Spring or other non-Broadleaf override for customizations |
No |
|
Yes |
Component |
Configuration Parameter |
Spring or other non-Broadleaf override for customizations |
No |
|
No |
Flexpackage |
Configuration Parameter |
Spring or other non-Broadleaf override, specific to deployments |
No |
|
Yes or No |
Flexpackage |
Configuration Parameter |
Spring or other non-Broadleaf override |
Yes |
|
Yes or No |
Flexpackage |
Configuration Parameter |
Custom client properties |
No |
|
Yes |
Component |
Configuration Parameter |
Client properties for external connections |
Yes |
|
Yes or No |
Flexpackage |
Configuration Parameter |
Custom Cloud Stream Binding destinations |
No |
|
Yes |
Component |
A number of environment post-processors driven by your manifest have been introduced with Initializr. In practice, they dynamically determine which properties are needed by the project, significantly reducing boilerplate configuration.
To remove the redundant properties from your project, first get the Environment Report for each flexpackage from the standard Initializr project you generated in the first step of this guide.
For that, you need to define the following property in each configuration file config/insecure/[flexpackageName].yml
and run the respective applications:
broadleaf:
environment:
report:
disabled: false
The Environment Report will be one of the first things printed in the logs.
Tip
|
You can find its start by searching for "Broadleaf Environment Report" |
Then, after moving over your custom configuration files, remove all property definitions that have the same values in the standard environment report. Those are default values for your manifest, and your project will inherit them automatically.
All code customizations should be moved into the Component side of each service. The Flexpackages should not contain any custom Java files. Configuration property files and liquibase changelogs can be placed in the Flexpackage. Consult the Split Matrix for further details
When starting up your Application, you may find that some of your custom functionality is not picked up and is missing from the running Application. This same issue may manifest itself with exceptions claiming missing autowired (injected) dependencies as well.
The most likely cause of this is your AutoConfiguration files are not declared in Spring’s new autoconfigurations file.
With SpringBoot 3, Spring introduced the META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
file to replace the historic spring.factories
in declaring Autoconfigurations.
While this change made its way into the Broadleaf codebase with the 2.0.0-GA Release Train, client customizations and a running @SpringBootApplication
being present in the classpath could have made the shift unnoticeable for some clients.
With Initializr, your code customizations live in the component and away from the @SpringBootApplication
, so any AutoConfiguration files should be declared in the aforementioned file to be consumed at runtime.
Find an example of such a file from our NotificationServices below:
[service].starter.required.data.changelog.xml
With Initializr, there is a change in changelog file execution order when some of your changelog files are placed on the flexpackage side of the split.
Prior to Initializr, the client had the flexibility to execute any (and all) changelogs in their folder prior to the required data changelogs ([service].starter.required.data.changelog.xml
) by changing the ordering within their changelog-master yml files.
Now, the master changelog file from the component ([service].component.[database].changelog-master.xml
) is the only file executing ahead of the required data changelogs.
All liquibase changelogs in the component should be referenced within the aforementioned file, and they will run prior to required data changelogs.
With files on the flexpackage side running after required data changelogs, it creates a potential liquibase data conflict if any of client’s custom liquibase or sql files run without conflict resolution clauses. There are two potential resolution paths: changing how your liquibase or sql files react to conflicts, or executing them prior to the required data changelogs.
It is a simple effort to have a given changelog file run in front of the required starter data.
It should be simply moved to the component side of the split and added as an entry to the [service].component.[database].changelog-master.xml
in the component.