Guice multiple implementations, parameterized constructor with dependencies - dependency-injection

I'm struggling with a particular dependency injection problem and I just can't seem to figure it out. FYI: I'm new to guice, but I have experience with other DI frameworks - that's why I believe this shouldn't be to complicated to achieve.
What am I doing:
I'm working on Lagom multi module project and using Guice as DI.
What I would like to achieve:
Inject multiple named instances of some interface implementation (lets' call it publisher, since it will publishing messages to kafka topic) to my service.
This 'publisher' has injected some Lagom and Akka related services (ServiceLocator, ActorSystem, Materializer, etc..).
Now I would like to have two instances of such publisher and each will publish messages to different topic (So one publisher instance per topic).
How would I achieve that?
I have no problem with one instance or multiple instances for the same topic, but if I want to inject different topic name for each instance I have a problem.
So my publisher implementation constructor looks like that:
#Inject
public PublisherImpl(
#Named("topicName") String topic,
ServiceLocator serviceLocator,
ActorSystem actorSystem,
Materializer materializer,
ApplicationLifecycle applicationLifecycle) {
...
}
If I want to create one instance I would do it like this in my ServiceModule:
public class FeedListenerServiceModule extends AbstractModule implements ServiceGuiceSupport {
#Override
protected void configure() {
bindService(MyService.class, MyServiceImpl.class);
bindConstant().annotatedWith(Names.named("topicName")).to("topicOne");
bind(Publisher.class).annotatedWith(Names.named("publisherOne")).to(PublisherImpl.class);
}
}
How would I bind multiple publishers each for it's own topic?
I was playing around with implementing another private module:
public class PublisherModule extends PrivateModule {
private String publisherName;
private String topicName;
public PublisherModule(String publisherName, String topicName) {
this.publisherName = publisherName;
this.topicName = topicName;
}
#Override
protected void configure() {
bindConstant().annotatedWith(Names.named("topicName")).to(topicName);
bind(Publisher.class).annotatedWith(Names.named(publisherName)).to(PublisherImpl.class);
}
}
but this led me nowhere since you can't get injector in you module configuration method:
Injector injector = Guice.createInjector(this); // This will throw IllegalStateException : Re-entry is not allowed
injector.createChildInjector(
new PublisherModule("publisherOne", "topicOne"),
new PublisherModule("publisherTwo", "topicTwo"));
The only solution which is easy and it works is that I change my PublisherImpl to abstract, add him abstract 'getTopic()' method and add two more implementations with topic override.
But this solution is lame. Adding additional inheritance for code reuse is not exactly the best practice. Also I believe that Guice for sure must support such feature.
Any advises are welcome.
KR, Nejc

Don't create a new Injector within a configure method. Instead, install the new modules you create. No child injectors needed—as in the PrivateModule documentation, "Private modules are implemented using parent injectors", so there's a child injector involved anyway.
install(new PublisherModule("publisherOne", "topicOne"));
install(new PublisherModule("publisherTwo", "topicTwo"));
Your technique of using PrivateModule is the one I'd go with in this situation, particularly given the desire to make the bindings available through binding annotations as you have it, and particularly if the full set of topics is known at runtime. You could even put the call to install in a loop.
However, if you need an arbitrary number of implementations, you may want to create an injectable factory or provider to which you can pass a String set at runtime.
public class PublisherProvider {
// You can inject Provider<T> for all T bindings in Guice, automatically, which
// lets you configure in your Module whether or not instances are shared.
#Inject private final Provider<ServiceLocator> serviceLocatorProvider;
// ...
private final Map<String, Publisher> publisherMap = new HashMap<>();
public Publisher publisherFor(String topicName) {
if (publisherMap.containsKey(topicName)) {
return publisherMap.get(topicName);
} else {
PublisherImpl publisherImpl = new PublisherImpl(
topicName, serviceLocatorProvider.get(), actorSystemProvider.get(),
materializerProvider.get(), applicationLifecycleProvider.get());
publisherMap.put(topicName, publisherImpl);
return publisherImpl;
}
}
}
You'd probably want to make the above thread-safe; in addition, you can avoid the explicit constructor call by using assisted injection (FactoryModuleBuilder) or AutoFactory, which will automatically pass through explicit parameters like topicName while injecting DI providers like ServiceLocator (which hopefully has a specific purpose, because you may not need much service-locating within a DI framework anyway!).
(Side note: Don't forget to expose your annotated binding for your PrivateModule. If you don't find yourself injecting your topicName anywhere else, you might also consider using individual #Provides methods with the assisted injection or AutoFactory approach above, but if you expect each Publisher to need a differing object graph you might choose the PrivateModule approach anyway.)

Guice's approach to dependency injection is that the DI framework complements your instantiation logic, it doesn't replace it. Where it can, it will instantiate things for you, but it doesn't try to be too clever about it. It also doesn't confuse configuration (topic names) with dependency injection - it does one thing, DI, and does that one thing well. So you can't use it to configure things, the way you can with Spring for example.
So if you want to instantiate an object with two different parameters, then you instantiate that object with two different parameters - ie, you invoke new twice. This can be done by using provider methods, which are documented here:
https://github.com/google/guice/wiki/ProvidesMethods
In your case, it might look something like adding the following method to your module:
#Provides
#Named("publisherOne")
#Singleton
Publisher providePublisherOne(ServiceLocator serviceLocator,
ActorSystem actorSystem,
Materializer materializer,
ApplicationLifecycle applicationLifecycle) {
return new PublisherImpl("topicOne", serviceLocator,
actorSystem, materializer, applicationLifecycle);
}
Also, you probably want it to be a singleton if you're adding a lifecycle hook, otherwise you could run into memory leaks each time you add a new hook every time it's instantiated.

Related

Inject vs Injectable vs Custom Providers

I’m having difficulty trying to figure out when to use what. I understand DI and have done this for years, but within NestJS it seems like there are things missing from the docs that would help me understand why some assigned properties go missing from an injected item.
We have a logger that gets injected via a custom provider.
From looking at the docs, they'll add #Inject during the constructor area, but if I'm injecting via a custom provider, why use #Inject?
Equally, why use #Injectable if we have custom providers handling all the injection setup for the module?
Where the question comes up is that filename is getting lost among other injected services where sometimes when the logger gets executed in one service, the filename is the same, while other times the service being different, it will retain the filename from the ctor name of a different service.
Anyway, I don't understand why to use one set up over another.
Update: I found we follow the LifeCycle on some Services, but I find the logger doesn't retain at the time of execution.
//custom-provider
export ClientProvider = {
provide: Client,
userFactory: (logger: Logger): Client => {
return new Client(logger);
},
inject: [Logger.getToken()]
};
//client
export class Client{
private readonly logger;
constructor(logger:Logger){
this.logger = logger;
if (this.logger) this.logger.fileName = this.constructor.name;
}
}
//logger
export class Logger {
static getToken(): string { return 'the-token-key'; }
private filename: string;
constructor(filename: string){
this.filename = filename;
}
}
//cat-service
export class CatService implements OnModuleInit {
private readonly logger;
constructor(#Inject(Logger.getToken()) private logger:Logger){
this.logger = logger;
}
onModuleInit() {
if (this.logger) this.logger.fileName = this.constructor.name;
}
}
So, high level, Nest naturally uses metadata reflected from Typescript to know what to bind and where. Normally, this metadata is things like Class Names that exist at runtime, which is why you cannot use interfaces.
#Injectable() tells Nest that it should look for the metadata provided in this class's constructor and find the correct providers. This is how Nest does most of the DI, as mentioned before.
#Inject() tells Nest, "Hey, I know this says it is a Logger class, but really inject the provider with the injection token I tell you", which is useful for things like using specific instances of, say, a Logger class.
With a custom provider, #Injectable() is not necessary if you use a factory, as you have shown, but it would be if you were to use a class instead, because factories return the instance of the value to be provided, whereas with useClass you are returning a class definition that Nest will need to instantiate.
The only reason I could see your filename being overwritten is that providers are singleton scope between modules, but if the same provider is in the providers array then it should be a new instance each time, so maybe something with that is acting a little wonky

Dependency injection in `ActionFiliter` vs. calling `Activator.CreateInstance()`

Requiring to sometimes use dependency injection in ActioFilter or other attributes running before or after an action API or result is inevitable. However, it is carried out through passing the type to be injected to the attribute using the typeof keyword. In order to simplify the case, when having various implementations for an interface, I have found it much simpler to manually instantiate the type than using the built-in dependency injection framework. For example:
public TestAttribute: Attribute, IActionFilter {
private Type injectionType;
public TestAttribute(Type injectionType){
...
}
...
public void OnActionExecuting(ActionExecutingContext context) {
InjectedTypeInterface injectedTypInterface = (InjectedTypeInterface) Activator.CreateInstance(injectedType, arg1, arg2, ...);
...
}
}
I want to know, from the point of view of other people here, that would this approach cause problems that using the built-in dependency injection framework would not? (Injected implementation will be always Transient in this case and not Scoped or Singleton)
I don't recommend doing the route of Activator.CreateInstance, here are some reasons why to avoid it and stick with the official way:
You'd need to pass in all instances of the parameters (i.e. of the type you want to instantiate has other dependencies) to it
The instance created this way isn't tracked by the scoped container. This also means, it won't automatically get disposed (Updated note this of course will only happen if the service implements IDisposable interface) at the end of the request and instead be disposed at some indeterminable time in future, when the GC kicks in and will keep resources open for longer then intended (i.e. holding connection or file handle open for longer then intended) unless you dispose it explicitly
Like you already recognized, you can't do so with scoped and singleton instances
For your concrete examples, there are easier ways to get a specific instance from DI - aside from the official supported ways (Filters - Dependency Injection) - you can also resolve from HttpContext, assuming you have access to it in the type of filter you are using.
For ActionFilter/IActionFilter
public void OnActionExecuting(ActionExecutingContext context) {
InjectedTypeInterface injectedTypInterface = context.HttpContext
.RequestServices.GetService<InjectedTypeInterface>();
...
}

Is it "bad practice" to pass argument to guice module

Checking out Guice and I love it. I currently have problem where guice solved it by injecting all the required dependencies I need. But I wonder if I am using Guice in the wrong way. What I require though is define bindings depending on specific instance. And to achieve this I passed the instance in the module.
For instance, consider the following (somewhat similar to my problem):
public class CustomerModule extends AbstractModule {
private Customer customer;
public CustomerModule(Customer customer){
this.customer = customer;
}
#Override
public void configure() {
bind(ReportGenerator.class).to(HtmlReportGenerator.class);
}
#Provides
Account providePurchasingAccount() {
return customer.getPurchasingAccount();
}
}
I use this module to get Account dependency injected to the report generator class that needs the account of a specific customer. For example, a user chooses a specific customer and say, wants to show a generated report. I have method like
public void printReport (Customer customer){
Injector injector = Guice.createInjector(new CustomerModule(customer));
ReportGenerator reportGenerator = injector.getInstance(ReportGenerator.class);
showReport(reportGenerator.generate())
}
Once the work is done, I am done with this module.
Is this a ok use of guice?
It is appropriate and useful to accept a constructor argument for a Module. This is an especially common pattern when making bindings for similar objects. Example:
// Installs #Named("accounts") Db to the given impl, backed with the given cache.
install(new DbModule("accounts", AccountDb.class, InMemoryCache.class));
// Same as above.
install(new DbModule("users", UserDb.class, DiskCache.class));
install(new DbModule("products", ProductDb.class, CustomProductCache.class));
That said, it is not common to create a new root Injector per action (such as printReport). Injector creation can take a long time as Guice reflectively queries classes and their dependencies. Instead, it is much more common to create the root Injector at application startup, and then create a child injector when you need to bind specific objects the way you have them.
Though it may make sense for you to temporarily create a brand new root Injector for each action, the way you have it, bear in mind that future development may make warrant singleton or application-level scope that persists beyond a single action, or your object graph may grow such that mid-action root Injector creation is no longer performant enough for your uses. If/when that happens, you may want to shift most of your Injector creation and configuration to a predictable startup flow, and only bind your Customer (and nothing else) into a child injector.

Ninject.Extensions.Logging.nlog2 - How to?

Browsing the nuget library, i came across Ninject.Extensions.Logging.nlog2. Some googling and trying to figure things out, I can't seem to find how or why you would use this extension.
Is it advisable to use with MVC 3?
What exactly is the point?
How do you use it?
It's really very simple; both NLog and log4net expect you to use singleton/static references to obtain logger instances:
private static Logger logger = LogManager.GetCurrentClassLogger();
This is widely considered to be an anti-pattern, but even if you have no problem with it, it's still going against the grain if you're trying to implement dependency injection. In the case of NLog it's not even an ILog or ILogger interface like log4net, it's an actual class. That carries certain disadvantages such as the inability to create proxies, deferred loading, caching, etc.
What the Ninject.Extensions.Logging project does is first provide an abstract ILogger class with simple methods like Info, Error, etc., so you can inject it as a dependency and switch the logging framework if you want:
public class WidgetProvider
{
private readonly ILogger log;
public WidgetProvider(ILogger log)
{
this.log = log;
}
}
This is how DI is supposed to work - a class never goes out to grab its own dependencies, instead they're supplied by the constructor or caller as above. Assuming you've already integrated Ninject itself into your project, that's really all you have to do, there is no additional work.
As for what Ninject.Extensions.Logging.NLog2 does specifically - it just provides an implementation for Ninject.Extensions.Logging based on NLog2. The base Logging library doesn't actually contain any implementations of ILogger, you have to plug in one of the specific libraries (NLog, NLog2, or log4net) in order to get it to work.
If you switch your DI library more often than you switch loggers then don't bother with it. But if you're like me and use Ninject in almost every project, then it's a nice way to decouple your code from any specific logging library.
If you want to use dependency injection via the constructor you can pass the ILoggerFactory interface.
This is how I did it.
using Ninject.Extensions.Logging;
public class MyClass
{
private readonly ILogger _log;
public MyClass(ILoggerFactory logFactory)
{
_log = logFactory.GetCurrentClassLogger();
}
public void DoWork()
{
_log.Info("Doing work!");
}
}
Problem solved!
Hope this helps someone.

How do I use Dependency Injection with wicket?

How do I convert the following example to use one of the wicket/IOC integration packages?
I want to learn and understand the DI/IOC pattern. I have read a lot about it, but I've found it a little hard to grasp without digging into a code example. I have an example of a complete, working Wicket panel, which I think I want to convert to using DI.
The panel is basically a web UI editor for a list. It takes an IPanelFactory as a constructor argument. The constructor creates a list (DefaultRefreshingView), and the panel factory knows how to create a ViewPanel for each row. The panelFactory also knows how to create an add form, for introducing a new item into the list.
I will cut out a lot of code to get to the heart of what I think is relevant:
public interface IPanelFactory<T extends DomainEntity, U extends DomainEntity>
extends IDetachable {
IAddItemPanel<T, U> newAddItemPanel(String id);
Component newEditPanel(ViewPanel.ViewPanelParameters<T> parms);
Component newListPanel(String id, IModel<Collection<T>> listModel);
}
public class ListEditorPanel2<T extends DomainEntity, U extends DomainEntity>
extends Panel implements IHeaderContributor {
private static final long serialVersionUID = 1L;
private final IPanelFactory<T, U> panelFactory;
public ListEditorPanel2(String id, IModel<Collection<T>> listModel,
final IPanelFactory<T, U> panelFactory) {
super(id, listModel);
this.panelFactory = panelFactory;
final AjaxCell listCell = new AjaxCell("listCell");
DefaultRefreshingView<T> itemList = new DefaultRefreshingView<T>(
"itemList", listModel) {
#Override
protected void populateItem(final Item<T> item) {
Component editPanel = ListEditorPanel2.this.panelFactory
.newEditPanel(new ViewPanelParameters<T>("viewPanel",
item.getModel(), new EditPanelCallback(item)));
item.add(editPanel);
}
};
listCell.add(itemList);
add(listCell);
final IAddItemPanel<T, U> addItemPanel = panelFactory
.newAddItemPanel("addItemForm");
add((Component) addItemPanel);
Form<T> form = addItemPanel.getForm();
}
}
Each implementation of IPanelFactory provides different components for the View and Add sections. There can be multiple instances of ListEditorPanel2 that use different factory implementations in the same page hierarchy.
My thinking is that I want IPanelFactory to be an injected dependency. So...
Is this a good use case for DI/IOC, or does it not make sense to use it here?
How would I do this "by hand" without using an IOC container? (Am I doing it already?)
Which wicket-IOC integration should I use? I am using wicket 1.4.8 at present. I was going to try wicket-spring-annot, but it looks like that project is out of date.
How do I set up the IOC container to do this for my wicket components?
I dont quite understand your use case but i will try to answer your question anyway.
Wicket has great support for the 2 most popular DI containers namely Spring and Guice. Personally i prefer using guice since it i find it less bloated and easier to use. You need to understand how guice works and how guice modules are created. To intergrate you wicket application with guice, you do something like below on your wicket application init method:
Injector injector = Guice.createInjector(new AppModule(),PersistenceService.usingJpa().across(UnitOfWork.REQUEST).buildModule());
addComponentInstantiationListener(new GuiceComponentInjector(this, injector));
Here am instantiating a guice injector with 2 modules, namely appModule and Persistence module (ignore the persistenceModule details . am using warp persist for transactions)
In a guice module, you bind all the components that you would like to be injecting. I mostly bind my Daos and my services. I can then inject the same to my panels, pages and any other wicket component. I can also bind panels and other custom components so that i can inject them to other components as neccessary. I have however not found a situation where i will need to bind and inject a user interface component.

Resources