Jump to the example if you're quite advanced in Spring already
What do we have
Working in Spring Boot stack one of the first features that every developer is taking the advantage of is Configuration Properties
Which could be configured as:
- class level beans
- method based beans
Basically method level beans are the same as class level but you can create N properties beans from a single class.
The properties itself can be propagated in different ways but the most common is through application properties / yaml files.
What's important about the properties that they can be:
- null
- defaulted
Naming
Spring follows the next conventions as for the configuration (class with beans) and configuration properties classes:
-
@Configuration
-*Configuration.kt
-
@ConfigurationProperties
-*Properties.kt
It's good to follow the standards from the ecosystem you use to prevent confusions as:
Properties class is not a configuration
Anti-patterns
Difference between configuration and properties
- Configuration - is a class that defines beans
- Properties - is a class that defines data structure to describe the application properties, e.g. to map the properties to an object
The next example is anti-pattern because spring works differently with these concepts:
@Configuration
@ConfigurationProperties
class MyProperties {
String value;
}
Configuration properties bean must be initialised by Spring not manually
The next example is anti-pattern because configuration properties is a bean can be initialised much more naturally when it's loosely coupled with it's configuration, for instance it's a problem if you use @ConstructorBinding
:
@Component
@ConfigurationProperties
class MyProperties {
String value;
}
Standards, code consistency
The goal of the best practices is to find the golden mean. Where we expect that the data-structure represents in a neat way the mapping between the properties and the class.
- default value should be located as close as possible to the field so developer can immediately see it
- nullability should represent the actual necessity of the property
- it should be simple
- composite children fields are designed in the same way
Having all the requirements we have the next example:
Demo
Let's say we have this set of properties defined:
io.github.artemptushkin.example:
defaultOverriddenProperty: overridden
requiredStringProperty: required-value
notNullListProperty: ["foo", "baz"]
it will give us the next runtime properties:
io.github.artemptushkin.example.defaultedStringProperty=default
io.github.artemptushkin.example.defaultOverriddenProperty=overridden
io.github.artemptushkin.example.requiredStringProperty=required-value
io.github.artemptushkin.example.optionalStringProperty=null
io.github.artemptushkin.example.notNullListProperty[0]=foo
io.github.artemptushkin.example.notNullListProperty[1]=baz
Key points are:
-
@ConstructorBinding
let's us use create immutable objects - Kotlin default constructor values let us use to have default values right in place in one single line
- Always initialise collections as empty by default to prevent nullable field
Summary
It's possible to write clean classes and keep them concise from one project to another and within your company.
I hope this noted helped you.
Top comments (0)