Comments (2)
@rbygrave thanks a lot for your explanation. It makes perfect sense to me.
from avaje-config.
Could we do this - yes, the question is should we do this.
So for example:
@Singleton
public class EngineImpl implements Engine {
@Value("${my.engine.cylinders:6}")
protected int cylinders;
...
}
Could be done today as:
import io.avaje.config.Config;
@Singleton
public class EngineImpl implements Engine {
protected int cylinders = Config.getInt("my.engine.cylinders", 6);
... and in fact we can make that a final field:
protected final int cylinders = Config.getInt("my.engine.cylinders", 6);
There is some background design thinking around this so we need to outline that here.
Background
Both Spring and Micronaut have a @Value
and by implication they have chosen to combine "external configuration" in with "dependency injection". With avaje-inject we could also do that but we (mostly I) have desired to keep these 2 things separate for what I believe are fairly good reasons. So lets look at those reasons.
We could for implement this via source code generation with avaje-inject as:
public class EngineImpl$Proxy extends EngineImpl {
public EngineImpl$Proxy() { // match super constructor,
super();
this.cylinders = Config.getInt("my.engine.cylinders", 6);
}
}
1. Timing of getting the configuration
We can see that cylinders
is only set after the super()
. Any code that tries to use cylinders
before that would get a 0 (or null with Integer etc). This is relatively obvious to experienced devs but it is a source of bugs for less experienced devs. That is, if we don't use @Value
and instead use Config.getInt()
the field is initialised just like any normal field. That is, @Value
fields have delayed initialisation and this can trip people up / be a source of bugs.
2. Dynamic configuration
If we go from needing the configuration read and set ONCE AT STARTUP to being read each time and potentially changing (aka dynamic configuration). Then we either need to change away from using @Value
OR use the "Refreshable scope" concept.
I'd argue that when using Config.getInt()
we can just use it anywhere - field, final field, static final field, in a method (dynamic configuration). There isn't a big shift between static configuration and dynamic configuration.
2.B "Refreshable scope"
As a consequence of "dynamic configuration", both Spring and Micronaut have the concept of "refreshable beans" / "refreshable context". With avaje-inject we explicitly do NOT have that concept as we'd get no value from "re-wiring the graph". Spring and Micronaut somewhat need it to re-read the @Value
configuration - I'd argue that is because they have combined "external configuration" with "dependency injection wiring" ... so any dynamic configuration need with @Value
means the bean needs to be refreshed.
That is, avaje-inject doesn't need "refreshable beans" because we expect "external dynamic configuration" to be done independently (for example, by using avaje-config). Instead, avaje-inject creates effectively immutable BeanScope.
3. avaje-config
I really like avaje-config. It's simple, extendable, and pretty mature. It was originally part of ebean orm and I extracted it into it's own project. If we supported @Value
in avaje-inject then it would have to pick a "configuration implementation" and that would be avaje-config. However, currently avaje-inject users are free to do whatever they like here with external configuration and I know that some of them choose other configuration libraries.
Q: So could we support @Value
?
A: Yes we could, it means that we need a $Proxy
(just like we do to support AOP) and the generated code would pretty much be:
public class EngineImpl$Proxy extends EngineImpl {
public EngineImpl$Proxy() { // match constructor of EngineImpl
super();
this.cylinders = Config.getInt("my.engine.cylinders", 6);
}
}
Q: So should we do this ?
Well, we could ... and then ideally document it in such a way that people think about their choices.
One of the interesting things about the code generation approach is that adding something like this can often result in ZERO added complexity to the runtime part of the library .. and instead just extra complexity is added to the code generator. I suspect that is the case here.
from avaje-config.
Related Issues (20)
- Load configuration from a specific file - is it possible? HOT 14
- Extracting property source. HOT 6
- Inconsistency with builder and initial loader. Default resource loader does not use the System class loader? HOT 19
- Use UncheckedIOException rather than IllegalStateException for consistency HOT 4
- Potential NPE in CoreConfigurationBuilder HOT 1
- ENH: Add Configuration.evalModify() ... to perform evaluation of expressions that modify properties in place
- Use AppLog.getLogger() rather than System.getLogger() to allow customization
- Remove the warning log messages when yml file extension is used rather than yaml
- Change so that properties via command line arguments is ALWAYS read (it wasn't when test resources detected)
- load.properties parameter should load from jar resources HOT 5
- loading from .localdev supports .yaml but not .yml (Add support for .yml with .localdev configuration)
- Maven Plugin Feature (and some other features). HOT 28
- SPI for initialization HOT 46
- Change from System.Logger to use events and control how those events are logged. HOT 2
- Event System does not coalesce changes properly HOT 8
- Document or fix hard dependency on avaje-inject when using module-path HOT 15
- Interpolation doesn't work in the same resource file.
- Multi-Profile support
- Make a Parser interface
- Support TOML? HOT 5
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from avaje-config.