-
Notifications
You must be signed in to change notification settings - Fork 567
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
4.x: Introduction of Helidon Service Inject. #9249
base: main
Are you sure you want to change the base?
Conversation
I have done a small update to include inject as a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LVGTM
Dmitry asked me to review. I mostly just had some questions and things to think about. I see there's an (enthusiastic) approval already so feel free to merge whenever you like; I don't want to get in the way.
Clearly a lot of work went into all this; hope this is useful. |
I will create follow up PRs that support |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simple comments, aside from the offline review.
doTestExitOnStarted(); | ||
} | ||
|
||
// @Test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test is commented-out here but not in other variants.
<groupId>io.helidon.build-tools</groupId> | ||
<artifactId>helidon-maven-plugin</artifactId> | ||
<configuration> | ||
<defaultJvmOptions>-Dapp.static.path=../../web</defaultJvmOptions> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not used.
Signed-off-by: Tomas Langer <[email protected]>
Signed-off-by: Tomas Langer <[email protected]>
Signed-off-by: Tomas Langer <[email protected]>
Signed-off-by: Tomas Langer <[email protected]>
Signed-off-by: Tomas Langer <[email protected]>
Proper qualifier for config beans even when `OrDefault` is used Added test for `OrDefault` Signed-off-by: Tomas Langer <[email protected]>
…annotations. Added feature processor and metadata codegen to Helidon Service Registry and Inject. Signed-off-by: Tomas Langer <[email protected]>
Add support for injection of InterceptionMetadata. Rework delegate interception to be usable by users.
…f possible. Changed default of Injection.Described to be singleton, as that feels more natural.
…ltiple constructor injection A few bugfixes for problems discovered by tests
5d8775c
to
47ae6f4
Compare
Related to #9158 (Step 1)
Follow up steps:
javax
andjakarta
packages)Inject Service Registry
An extension to the core service registry, Helidon Service Inject adds a few concepts:
Singleton
scope, optionalRequestScope
The main entry point to get service registry is
io.helidon.service.inject.InjectRegistryManager
(part of implementation, not API), which can be used to obtainio.helidon.service.inject.api.InjectRegistry
.The registry can then be used to lookup services (it extends the existing
ServiceRegistry
).Injection and scopes
Annotation type:
io.helidon.service.inject.api.Injection
Annotations:
Inject
Qualifier
Named
NamedByClass
Named
, that uses the fully qualified class name of the configured class as nameScope
Instance
Singleton
RequestScope
RunLevel
CreateFor
CreateForName
CreateFor
)Main
Describe
Interfaces:
ServicesProvider
ConfigBean
InjectionPointProvider
QualifiedProvider
QualifiedInstance
ScopeHandler
Injection into services
A service can have injection points, usually through constructor.
Example:
A dependency (such as
Contract1
above) may have the following forms (Contract
stands for a contract interface, or class):Instance based:
Contract
- injects an instance of the contract with the highest weight from the registryOptional<Contract>
- same as previous, the contract may not have an implementation available in registryList<Contract>
- a list of all available instances in the registrySupplier based (to break cyclic dependency, and to create instances as late as possible):
Supplier<Contract>
Supplier<Optional<Contract>>
Supplier<List<Contract>>
Service instance based (to obtain registry metadata in addition to the instance):
ServiceInstance<Contract>
Optional<ServiceInstance<Contract>>
List<ServiceInstance<Contract>>
As can be seen above, we can have more than one producer of a single contract type within the registry. The ordering is always by qualifiers first, weight second (unqualified instances are first).
Interceptors
Interception provides capability to intercept call to a constructor or a method (even to fields when used as injection points).
Interception is (by default) only enabled for elements annotated with an annotation that is a
Trigger
. Annotation processorconfiguration allows for creating interception "plumbing" for any annotation, or to disable it altogether.
Interception works "around" the invocation, so it can:
Annotation type:
io.helidon.service.inject.api.Interception
Annotations:
Trigger
Interfaces:
Interceptor
NamedByClass
) will be used as interceptor of methods annotated with that annotation. Interceptor must callproceed
method to handle the interception chainFactory
ConfigBean
methodsConfig beans
Config beans are types that are driven by a configuration key. They must use root configuration key (such as server, security).
Config beans may be repeatable, or single instance (see details below in Annotations section).
Annotation type:
io.helidon.service.inject.api.ConfigDriven
Annotations:
ConfigBean
@Prototype.Blueprint
typesAtLeastOne
Repeatable
AddDefault
@default
(or unnamed) instance is not in configuration, create it using defaultsOrDefault
ConfigBean
In case
OrDefault
is used, the config bean is a singleton.In all other cases, each config bean created is a named instance, where the name is either
@default
, orname
key providedin its configuration.
Config beans work in two steps (this is only true for
@Prototype.Blueprint
beans):Prototype.Builder
instance is created, which can be updated by other servicesPrototype
instance is created that injects thePrototype.Builder
Startup
Helidon Service Inject adds a new startup provider - so if you use
io.helidon.Main
as your main class, service registrywould be automatically started as long as it is on your classpath, and services in all run levels that are present will be
looked up (triggering
@PostConstruct
calls, which can be used to start the "container").