Modern Akka DI with Guice - java

Java 8, Guice 4.0 and Akka 2.3.9 here. I am trying to figure out how to annotate my actor classes with JSR330-style #Inject annotations, and then wire them all up via Guice.
But literally every single article I have read (some examples below) either uses Scala code examples, a criminally-old version of Guice, or a criminally-old version of Akka:
Let It Crash
Scala-Guice
So, given the following Guice module:
public interface MyService {
void doSomething();
}
public class MyServiceImpl implements MyService {
#Override
public void doSomething() {
System.out.println("Something has been done!");
}
}
public class MyActorSystemModule extends AbstractModule {
#Override
public void configure() {
bind(MyService.class).to(MyServiceImpl.class);
}
}
And given the FizzActor that gets injected with a MyService:
public class FizzActor extends UntypedActor {
private final MyService myService;
#Inject
public FizzActor(MyService myService) {
super();
this.myService = myService;
}
#Override
public void onReceive(Object message) {
// .. Do fizz stuff inside here.
}
}
Then I ask: How do I rig up MyActorSystemModule to create instances of FizzActor and properly inject them with Java (not Scala!)?
Please note: FizzActor is not the only actor in my actor system!

Use Creator to create ActorRefs in provider methods of your guice module. To distinguish between the different ActorRefs, which are untyped, use annotations on your provider methods and injection points as you would any guice system. For example,
In your guice module:
#Override
protected void configure() {
bind(ActorSystem.class).toInstance(ActorSystem.apply());
bind(FizzService.class).toInstance(new FizzServiceImpl());
}
#Provides #Singleton #Named("fizzActor")
ActorRef serviceActorRef(final ActorSystem system, final FizzService fizzService) {
return system.actorOf(Props.create(new Creator<Actor>() {
#Override
public Actor create() throws Exception {
return new FizzActor(fizzService);
}
}));
}
Then to use the actor service, inject a specific ActorRef:
class ClientOfFizzActor {
#Inject
ClientOfFizzActor(#Named("fizzActor") ActorRef fizzActorRef) {..}
}
It looks cleaner if the Props.create(..) clause is a static factory method in your actor class.

Unless you are trying to bind UntypedActor to FizzActor, then you can just inject it into other classes as is:
class SomeOtherClass {
#Inject
public SomeOtherClass(FizzActor fizzActor) {
//do stuff
}
}
If you're trying to bind it to the interface, you'll need to specifically do that in the module:
public class MyActorSystemModule extends AbstractModule {
#Override
public void configure() {
bind(MyService.class).to(MyServiceImpl.class);
bind(UntypedActor.class).to(FizzActor.class);
}
}
Edit:
What about using #Named to distinguish the UntypedActor, e.g.:
class SomeOtherClass {
#Inject
public SomeOtherClass(#Named("fizzActor")UntypedActor fizzActor, #Named("fooActor") UntypedActor fooActor) {
//do stuff
}
}
Then in your module you could do the akka lookups:
public class MyActorSystemModule extends AbstractModule {
ActorSystem system = ActorSystem.create("MySystem");
#Override
public void configure() {
bind(MyService.class).to(MyServiceImpl.class);
}
#Provides
#Named("fizzActor")
public UntypedActor getFizzActor() {
return system.actorOf(Props.create(FizzActor.class), "fizzActor");
}
#Provides
#Named("fooActor")
public UntypedActor getFooActor() {
return system.actorOf(Props.create(FooActor.class), "fooActor");
}
}

Use an akka Creator:
public class GuiceCreator<T> implements Creator<T> {
Class<T> clz;
Module module;
/*Constructor*/
public T create() {
Injector injector = Guice.createInjector(this.module);
return injector.getInstance(this.clz);
}
}
Then use Props.create with your shiny new guice-based creator.
Disclaimer: I don't actually know Akka, the mentioned information comes from browsing the documentation and JavaDoc.

In case anyone found this question, you need to use IndirectActorProducer, I referred to the Spring example and changed it to use Guice instead.
/**
* An actor producer that lets Guice create the Actor instances.
*/
public class GuiceActorProducer implements IndirectActorProducer {
final String actorBeanName;
final Injector injector;
final Class<? extends Actor> actorClass;
public GuiceActorProducer(Injector injector, String actorBeanName, Class<? extends Actor> actorClass) {
this.actorBeanName = actorBeanName;
this.injector = injector;
this.actorClass = actorClass;
}
#Override
public Actor produce() {
return injector.getInstance(Key.get(Actor.class, Names.named(actorBeanName)));
}
#Override
public Class<? extends Actor> actorClass() {
return actorClass;
}
}
In the module
public class BookingModule extends AbstractModule {
#Override
protected void configure() {
// Raw actor class, meant to be used by GuiceActorProducer.
// Do not use this directly
bind(Actor.class).annotatedWith(
Names.named(BookingActor.ACTOR_BEAN_NAME)).to(
BookingActor.class);
}
#Singleton
#Provides
#Named(BookingActor.ACTOR_ROUTER_BEAN_NAME)
ActorRef systemActorRouter(Injector injector, ActorSystem actorSystem) {
Props props = Props.create(GuiceActorProducer.class, injector, BookingActor.ACTOR_BEAN_NAME, actorClass);
actorSystem.actorOf(props.withRouter(new RoundRobinPool(DEFAULT_ROUTER_SIZE)), BookingActor.ACTOR_ROUTER_BEAN_NAME);
}
}

So I have been playing around with Akka and Guice recently alot and I feel that those two don't play too well together.
What I suggest is you take a similar approach what Play is doing.
Kutschkem's answer comes closest to that.
use the ActorCreator interface
make sure you have an argumentless Creator. Don't try to do #AssisstedInject in your Creator as this will imply that you will need a new creator for every Actor that you want to create. Personally I believe that initializing this in the actor is better done through messaging.
let the ActorCreator consume an injector such that you can easily create the Actor Object within the Creator.
Here is a code example using current Akka 2.5. This is the preferred setup we chose for our Akka 2.5 deployment. For brevity I did not provide the Module, but it should be clear from the way the Members are injected, what you want to provide.
Code:
class ActorCreator implements Creator<MyActor>
#Inject
Injector injector;
public MyActor create() {
return injector.getInstance(MyActor.class);
}
}
class MyActor extends AbstractActor {
#Inject
SomeController object;
#Nullable
MyDataObject data;
public ReceiveBuilder createReceiveBuilder() {
return receiveBuilder()
.match(MyDataObject.class, m -> { /* doInitialize() */ })
.build();
}
}
class MyParentActor extends AbstractActor {
#Inject
ActorCreator creator;
void createChild() {
getContext().actorOf(new Props(creator));
}
void initializeChild(ActorRef child, MyDataObject obj) {
child.tell(obj);
}
}

Generic Akka Guice integration without dependency on Play,
keeping in mind, not the only actor should be created in the actor system.
import akka.actor.Actor;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import com.google.inject.AbstractModule;
import com.google.inject.Provider;
import com.google.inject.name.Names;
public abstract class AkkaGuiceModule extends AbstractModule {
protected <T extends Actor> void bindActor(Class<T> actorClass, String name) {
bind(actorClass);
Provider<ActorSystem> actorSystemProvider = getProvider(ActorSystem.class);
Provider<T> actorProvider = getProvider(actorClass);
bind(ActorRef.class)
.annotatedWith(Names.named(name))
.toProvider(ActorRefProvider.of(actorSystemProvider, actorProvider, name))
.asEagerSingleton();
}
}
Generic ActorRefProvider to create ActorRef for each Actor
import akka.actor.Actor;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.japi.Creator;
import com.google.inject.Provider;
import lombok.Value;
#Value(staticConstructor = "of")
public class ActorRefProvider<T extends Actor> implements Provider<ActorRef> {
private Provider<ActorSystem> actorSystemProvider;
private Provider<T> actorProvider;
private String name;
public final class ActorCreator implements Creator<Actor> {
#Override
public Actor create() {
return actorProvider.get();
}
}
#Override
public ActorRef get() {
return actorSystemProvider.get().actorOf(Props.create(new ActorCreator()), name);
}
}
Usage example
import akka.actor.ActorSystem;
import com.google.inject.Provides;
import com.typesafe.config.Config; // optional
public class MyAkkaModule extends AkkaGuiceModule {
#Provides
#Singleton
ActorSystem actorSystem(Config config) {
return ActorSystem.create("actor-system-name", config);
}
#Override
protected void configure() {
bindActor(SomeActor1.class, "actorName1");
bindActor(SomeActor2.class, "actorName2");
}
}

Related

Java Guice Named Bindings with Objects provided from other modules

Heres my current setup
Class file
public class ToyAdapter {
private final ToyClient toyClient;
private final Retryer retryer;
#Inject
public APIAdapter(final ToyClient toyClient,
#Named("toyRetryer") final Retryer retryer) {
this.toyClient = toyClient;
this.retryer = retryer;
}
Guice file
I have several guice modules, but this one pertains to the above class
public class ToyModule extends AbstractModule {
#Override
protected void configure() {
bind(ToyAdapter.class).in(Singleton.class);
bind(Retryer.class).annotatedWith(Names.named("toyRetryer")).toInstance(getToyRetryer());
}
#Provides
#Singleton
public ToyClient getToyClient(...){
...
}
private Retryer getToyRetryer() {#Takes no arguments
return RetryerBuilder...build();
}
}
So far this works great! However, now my retryer requires a LogPublisher object provided in another module.
I'm trying
public class ToyModule extends AbstractModule {
LogPublisher logPublisher;
#Override
protected void configure() {
requestInjection(logPublisher);
bind(ToyAdapter.class).in(Singleton.class);
bind(Retryer.class).annotatedWith(Names.named("toyRetryer")).toInstance(getToyRetryer());
}
private Retryer getToyRetryer() {
return RetryerBuilder.withLogPublisher(logPublisher).build();
}
}
LogPublisher is provided in another guice module which has alot of other objects that depend on LogPublisher so I'd rather not just merge everything into one giant guice module.
#Provides
#Singleton
public LogPublisher getLogPublisher() {...}
Is this the proper way to do this? I'm getting Java findBugs errors saying unwritten field so I'm thinking I'm doing it wrong.
Declare your Retryer with help of #Provides/#Named annotations.
#Provides
#Singleton
#Named("toyRetryer")
public Retryer getToyRetryer(LogPublisher logPublisher) {
return RetryerBuilder.withLogPublisher(logPublisher).build();
}

google guice injecting null

I am trying to inject a vertx instance
public ServiceBinder(Vertx vertx) {
this.vertx = vertx;
}
I am binding like this
#Override
protected void configure() {
bind(Vertx.class).toInstance(this.vertx);
}
And I am invoking injection like this
public class BaseVerticle extends AbstractVerticle{
#Override
public void start(Future<Void> startFuture) {
Guice.createInjector(new ServiceBinder(vertx)).injectMembers(this);
}
}
Now I try to inject this in another class
public class DelegateFactory {
#Inject
private Vertx vertx;
}
However here the value of vertx is null. Do I need inject DelegateFactory too?
I tried annotating DelegateFactory with #Singleton, but it did not help
Make sure that :
Your ServiceBinder class extends com.google.inject.AbstractModule
Your DelegateFactory is binded in your ServiceBinder or another guice's AbstractModule subclass like that :
bind(DelegateFactory.class).in(Singleton.class)
or
bind(DelegateFactory.class).toInstance(...)
P.S : it's better to be fail-fast in your ServiceBinder constructor :
import static java.util.Objects.requireNonNull;
public ServiceBinder(Vertx vertx) {
this.vertx = requireNonNull(vertx, "vertx must not be null");
}

Creating Singleton in java using guice

import com.google.inject.Injector;
import static com.google.inject.Guice.createInjector;
public final class BatchFactory {
private static class Holder {
private static final Injector INJECTOR = createInjector(new BatchModule());
private static final batchProvider PROVIDER_INSTANCE = INJECTOR
.getInstance(BatchProvider.class);
}
public static BatchProvider getProviderInstance() {
return Holder.PROVIDER_INSTANCE;
}
}
public class BatchModule extends AbstractModule {
#Override
protected void configure() {
bind(BatchProvider.class).to(
BatchProviderImpl.class);
}
}
BatchProvider is the Interface and BatchProviderImpl is the class implementation.
Here I am using a class BatchFactory to create the #Singleton instance of BatchProviderImpl class.
Can I use #Singleton annotation of google guice to make BatchFactory class #Singleton
See the duplicate question, you can do
bind(Service.class).to(ServiceImpl.class).in(Singleton.class);
Or:
#Provides #Singleton
public ServiceImpl providesService() {
return new ServiceImpl();
}

Spring proxy to choose implementation based on annotation and runtime value

I would like to inject a proxy implementation of an interface to a component and then let spring choose the right implementation based on a runtime property (and the value of an annotation at the implementation class). So my component does not have to care about choosing the right one.
It is kind of like a scope. But i think scopes are only for handling different instances of the same implementation class. Am i wrong with this?
I would like this to run for arbitrary interfaces without creating a service locator or some other construct for every new service.
Here is an example.
Suppose I have an interface defining a service
package test;
public interface IService {
void doSomething();
}
and two implementations:
package test;
import javax.inject.Named;
#Named
#MyAnnotation("service1")
public class Service1 implements IService {
#Override
public void doSomething() {
System.out.println("this");
}
}
...
package test;
import javax.inject.Named;
#Named
#MyAnnotation("service2")
public class Service2 implements IService {
#Override
public void doSomething() {
System.out.println("that");
}
}
Now I would like to inject an IService to another component and let spring choose the correct implementation based on some queryable run time property and the value of MyAnnotation.
Is there a way to do this in a general way in spring?
EDIT:
I have a Context that holds some value. It is a thread local in this case.
package test;
public class MyValueHolder {
private static final ThreadLocal<String> value = new ThreadLocal<>();
public static void set(String newValue) {
value.set(newValue);
}
public static String get() {
return value.get();
}
public static void reset() {
value.remove();
}
}
And I have an component which uses IService
package test;
import javax.inject.Inject;
import javax.inject.Named;
#Named
public class MyComponent {
#Inject
private IService service;
public void myImportantWorkflow(){
MyValueHolder.set("service1");
service.doSomething();
MyValueHolder.set("service2");
service.doSomething();
}
}
The injected service should only be a proxy. Depending on the value set in MyValueHolder the call to doSomething should delegate to service1 or service2. So in this example it should delegate to doSomething on service1 in the first call and to service2 in the second call.
I could write such a delegator implementing the IService interface and use it for this one service. But then i have to repeat this for every other service . I hoped spring could do something like this with proxies almost by itself. Of course i have to provide some method to look beans up based on the value hold in the thread local and register it to spring. But i have no idea if that is even possible without modifying the spring framework. And if it is possible how to accomplish this.
You could use a ProxyFactoryBean to create the proxies and a TargetSource to do the lookup.
For example (not tested)
public class AnnotatedBeanTargetSource implements TargetSource, BeanFactoryAware {
private ConfigurableListableBeanFactory beanFactory;
private Class<? extends Annotation> annotationType;
private Class<?> implementedIterface;
private Map<String, Object> beans;
#Override
public Class<?> getTargetClass() {
return this.implementedIterface;
}
#Override
public boolean isStatic() {
return false;
}
#Override
public Object getTarget() throws Exception {
if (this.beans == null) {
this.beans = lookupTargets();
}
return this.beans.get(MyValueHolder.get());
}
protected Map<String, Object> lookupTargets() {
Map<String, Object> resolvedBeans = new HashMap<String, Object>();
String[] candidates = beanFactory.getBeanNamesForAnnotation(annotationType);
for (String beanName : candidates) {
Class<?> type = beanFactory.getType(beanName);
if (this.implementedIterface.isAssignableFrom(type)) {
Annotation ann = AnnotationUtils.getAnnotation(type, annotationType);
resolvedBeans.put((String) AnnotationUtils.getValue(ann), beanFactory.getBean(beanName));
}
}
return resolvedBeans;
}
#Override
public void releaseTarget(Object target) throws Exception {
// nothing to do
}
#Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
public Class<? extends Annotation> getAnnotationType() {
return annotationType;
}
public void setAnnotationType(Class<? extends Annotation> annotationType) {
this.annotationType = annotationType;
}
public Class<?> getImplementedIterface() {
return implementedIterface;
}
public void setImplementedIterface(Class<?> implementedIterface) {
this.implementedIterface = implementedIterface;
}
}
This is what I would do:
#Named
public class MyComponent {
// introduce a marker interface for Injecting proxies
#InjectDynamic
IService service
...
public void useIService() {
service.doSomething();
...
service.doSomethingElse();
...
service.doFinally();
}
}
Define a BeanPostProcessor that scans for bean with fields annotated with #InjectDynamic, then creates and inject a Proxy implementing the type required by the field.
The Proxy implementation will look in the applicationContext for beans implementing Supplier<T> (Java 8 or guava versions) where <T> is the type of the field annotated with #InjectDynamic.
Then you can define
#Name
public IServiceSupplier implements Supplier<IService> {
#Override
public IService get() {
// here you implement the look-up logic for IService
}
}
In this way the look-up of active the current implementation is decoupled from the Proxy and can be change by target type.

How to inject with Guice `Module` where constructor accepts Class?

The title describes my problem.
E.g.
public class EntryDAOModule extends AbstractModule {
#Override
protected void configure() {
bind(EntryDAO.class).to(EntryDTOMongoImpl.class); // what should this be?
}
}
As shown, what should be the parameter to .to, given the below:
public class GenericDAOMongoImpl<T, K extends Serializable> extends BasicDAO<T, K> {
public GenericDAOMongoImpl(Class<T> entityClass) throws UnknownHostException {
super(entityClass, ConnectionManager.getDataStore());
}
}
public class EntryDAOMongoImpl extends GenericDAOMongoImpl<EntryDTOMongoImpl, ObjectId> implements EntryDAO<EntryDTOMongoImpl> {
private static final Logger logger = Logger.getLogger(EntryDAOMongoImpl.class);
#Inject
public EntryDAOMongoImpl(Class<EntryDTOMongoImpl> entityClass) throws UnknownHostException {
super(entityClass);
}
...
}
How can I instantiate the EntryDAOMongoImpl class like so:
Injector injector = Guice.createInjector(new EntryDAOModule());
this.entryDAO = injector.getInstance(EntryDAO.class); // what should this be?
What you are going to need here is to create a factory. Using assisted injection can help you here.
You can see my previous post regarding assisted injection
but here's the exact solution for your case:
EntryDAOMongoImpl:
public class EntryDAOMongoImpl extends GenericDAOMongoImpl<EntryDTOMongoImpl, ObjectId> implements EntryDAO<EntryDTOMongoImpl> {
private static final Logger logger = Logger.getLogger(EntryDAOMongoImpl.class);
#Inject
public EntryDAOMongoImpl(#Assisted Class<EntryDTOMongoImpl> entityClass) throws UnknownHostException {
super(entityClass);
}
...
}
Factory:
public interface EntryDAOFactory {
public EntryDAOMongoImpl buildEntryDAO(Class<EntryDTOMongoImpl> entityClass);
}
Module:
public class EntryDAOModule extends AbstractModule {
#Override
protected void configure() {
//bind(EntryDAO.class).to(EntryDAOMongoImpl.class); // what should this be?
FactoryModuleBuilder factoryModuleBuilder = new FactoryModuleBuilder();
install(factoryModuleBuilder.build(EntryDAOFactory.class));
}
}
Usage:
Injector injector = Guice.createInjector(new EntryDAOModule());
EntryDAOFactory factory = injector.getInstance(EntryDAOFactory.class);
this.entryDAO = factory.buildEntryDAO(entityClass);
If you are going to be using the EntryDAOMongoImpl as a singelton (natural usage of a singleton imo) then you can do the following without assisted injection within your module:
public class EntryDAOModule extends AbstractModule {
#Override
protected void configure() {
EtnryDTOMongoImpl dto = new EntryDTOMongoImpl(TargetEntry.class); //guessing here
bind(EntryDAO.class).toInstance(new EntryDAOMongoImpl(dto)); // singleton
}
}
Let me know if that helps

Categories

Resources