-
Notifications
You must be signed in to change notification settings - Fork 924
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
Add DependencyInjector to inject dependencies in annotations #4202
Conversation
Motivation: Users cannot inject an instance, which has constructor parameters, through `@Decorator` and other anntations. It would be nice if we provide a way to inject dependencies. Modifications: - Add `DependencyInjector` to inject the instances that are specified in an annotated service. - Spring integration module automatically adds `SpringDependencyInjector` to inject the depdendencies defined via bean definition. Result: - Close line#4006 - You can now inject dependencies that have constructor parameters to an annotated service.
Codecov Report
@@ Coverage Diff @@
## master #4202 +/- ##
==========================================
Coverage 73.44% 73.44%
- Complexity 17395 17443 +48
==========================================
Files 1482 1488 +6
Lines 65296 65448 +152
Branches 8207 8221 +14
==========================================
+ Hits 47954 48067 +113
- Misses 13169 13201 +32
- Partials 4173 4180 +7
Continue to review full report at Codecov.
|
@Override | ||
public <T> T getInstance(Class<T> type) { | ||
try { | ||
return beanFactory.getBean(type); |
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.
Would be useful to inject a decorator with a name?
@Decorator(FooDecorator.class, "foo1Decorator")
public String foo();
// Will be chosen
@Bean(name = "foo1Decorator")
FooDecorator foo1() {
...
}
@Bean(name = "foo2Decorator")
FooDecorator foo2() {
...
}
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.
Thanks, that's a good suggestion. 👍
However, can I just leave it as a TODO and implement it later because:
- We haven't had such demands so far
- It increases the complexity of the implementation
- Users can easily apply the different instances using
@DecoratorFactory
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.
Makes sense. We can add the feature later without hurting the original API.
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.
Would naming a bean work for other DI frameworks by the way? (Guice, Dagger, etc)
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.
Guice and Dagger supports @Named
bean injection as well.
https://github.com/google/guice/wiki/BindingAnnotations#named
core/src/main/java/com/linecorp/armeria/server/DependencyInjector.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/DependencyInjector.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/DefaultDependencyInjector.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/OrElseDependencyInjector.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/OrElseDependencyInjector.java
Outdated
Show resolved
Hide resolved
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.
Overall, looking good. Left minor comments.
core/src/main/java/com/linecorp/armeria/server/DependencyInjectorBuilder.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/FallbackDependencyInjector.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/FallbackDependencyInjector.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/DefaultDependencyInjector.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/ServerBuilder.java
Outdated
Show resolved
Hide resolved
@Override | ||
public <T> T getInstance(Class<T> type) { | ||
try { | ||
return beanFactory.getBean(type); |
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.
Makes sense. We can add the feature later without hurting the original API.
core/src/main/java/com/linecorp/armeria/server/DefaultDependencyInjector.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/DefaultDependencyInjector.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/DefaultDependencyInjector.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/FallbackDependencyInjector.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/ServerBuilder.java
Outdated
Show resolved
Hide resolved
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.
...toconfigure/src/main/java/com/linecorp/armeria/internal/spring/SpringDependencyInjector.java
Outdated
Show resolved
Hide resolved
Motivation Currently, depedencies for decorators are injected when the class is set to the `GrpcServiceBuilder`. However, we need to use the `DependencyInjector` that will be introduced in line#4202. The `DependencyInjector` is set to the `Server` so we need to delay to inject dependencies until the `serviceAdded` method is called which means we can get the injector. Modifications: - Refactor `GrpcServiceBuilder` for adding decorators - Use `lookupMethodFromAttribute` where applicable - Fix a bug that decorator is not applied when `grpcBuilder.addService(path, service, method)` is called. - Inject dependencies in `GrpcDecoratingService.serviceAdded()` Result: - Ready to apply line#4202 - Decorator is correctly applied when a method is added via `GrpcServiceBuilder.addService(String,BindableService,MethodDescriptor)`.
Motivation Currently, depedencies for decorators are injected when the class is set to the `GrpcServiceBuilder`. However, we need to use the `DependencyInjector` that will be introduced in line#4202. The `DependencyInjector` is set to the `Server` so we need to delay to inject dependencies until the `serviceAdded` method is called which means we can get the injector. Modifications: - Refactor `GrpcServiceBuilder` for adding decorators - Use `lookupMethodFromAttribute` where applicable - Fix a bug that decorator is not applied when `grpcBuilder.addService(path, service, method)` is called. - Inject dependencies in `GrpcDecoratingService.serviceAdded()` Result: - Ready to apply line#4202 - Decorator is correctly applied when a method is added via `GrpcServiceBuilder.addService(String,BindableService,MethodDescriptor)`.
…ratingService (#4228) Motivation Currently, dependencies for decorators are injected when the class is set to the `GrpcServiceBuilder`. However, we need to use the `DependencyInjector` that will be introduced in #4202. The `DependencyInjector` is set to the `Server` so we need to delay injecting dependencies until the `serviceAdded` method is called which means we can get the injector. Modifications: - Refactor `GrpcServiceBuilder` for adding decorators - Fix a bug that decorator is not applied when `grpcBuilder.addService(path, service, method)` is called. - The path, which is used to set a service, is now correctly normalized. - Inject dependencies in `GrpcDecoratingService.serviceAdded()` Result: - Ready to apply #4202 - Decorator is correctly applied when a method is added via `GrpcServiceBuilder.addService(String,BindableService,MethodDescriptor)`.
core/src/main/java/com/linecorp/armeria/server/DependencyInjector.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/DependencyInjectorEntry.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/DependencyInjectorEntry.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/internal/server/annotation/AnnotatedObjectFactory.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/DependencyInjectorEntry.java
Outdated
Show resolved
Hide resolved
Updated, PTAL. 🙇♂️ |
core/src/main/java/com/linecorp/armeria/server/BuiltInDependencyInjector.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/BuiltInDependencyInjector.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/DefaultDependencyInjector.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/ReflectiveDependencyInjector.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/ShutdownSupport.java
Outdated
Show resolved
Hide resolved
...toconfigure/src/main/java/com/linecorp/armeria/internal/spring/ArmeriaConfigurationUtil.java
Show resolved
Hide resolved
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.
Looks good! Only left nits and a question 🙇
core/src/main/java/com/linecorp/armeria/server/ServerBuilder.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/ServerBuilder.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/ServerBuilder.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/DefaultDependencyInjector.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/BuiltInDependencyInjector.java
Outdated
Show resolved
Hide resolved
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.
Awesome!! 🍃🎉
Spring users will love this feature.
core/src/main/java/com/linecorp/armeria/server/DependencyInjector.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/DependencyInjector.java
Outdated
Show resolved
Hide resolved
@@ -289,4 +289,9 @@ default boolean shutdownBlockingTaskExecutorOnStop() { | |||
* supports case sensitive HTTP/1 headers. | |||
*/ | |||
Http1HeaderNaming http1HeaderNaming(); | |||
|
|||
/** | |||
* Returns the {@link DependencyInjector} that injects dependencies in annotated services. |
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.
Should the DependencyInjector
be used in a gRPC service?
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.
That's a good point. 😉 We might support adding annotations to a Thrift
service later so let me change the sentence to injects dependencies in annotations
* constructor, which does not have a parameter, of the classes. | ||
*/ | ||
@UnstableApi | ||
public interface DependencyInjector extends SafeCloseable { |
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.
Would it make sense to move this interface to common
so we can use this for both client and server side? For example, in the future, we could introduce a client-side (or common) @Decorator
annotation and let our users use it with Retrofit or our future Retrofit alternative.
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.
That's a good suggestion. 👍 Moved the package. 😉
core/src/main/java/com/linecorp/armeria/server/OrElseDependencyInjector.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/ServerBuilder.java
Outdated
Show resolved
Hide resolved
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.
Should be a really useful feature! Thanks @minwoox 🙇 👍 🙇
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.
Still LGTM with new changes.
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.
Thanks for this awesome feature, @minwoox! 👍
Thanks, reviewers! 😉 |
Motivation:
Users cannot inject an instance, which has constructor parameters, through
@Decorator
and other annotations.It would be nice if we provide a way to inject dependencies.
Modifications:
DependencyInjector
to inject the instances that are specified in an annotated service.DependencyInjector
is not set,ReflectiveDependencyInjector
is used to keep the backward-compatibilityDependencyInjector
is set,BuiltInDependencyInjector
is applied at first to support built-in classes.SpringDependencyInjector
that injects usingBeanFactory
.armeria.enable-auto-injection
totrue
to applySpringDependencyInjector
.DependencyInjector
.Result:
@Decorator
#4006DependencyInjector
to annotated services.