Showing posts with label Guice. Show all posts
Showing posts with label Guice. Show all posts

Philosophy of Guice

Dependencies injection + interfaces

Classes are glued together by interfaces, and implemented classes are injected in run-time.
---Compile time: interface calls interface, run time: implementation calls implementation. In between taken care by Guice.
  • we don't need implemented classes to get compiled.
  • we could change to different implemented classes on the fly.
  • No need to rewrite test client.
Guice
  • What to inject: map interface to real implementation, this is the place we'll make the change. Keep mind, bind interface to implementation is the best practice, but you could also bind any class to its sub class, as long as they are the same type or implements the same interface.
public class BillingModule extends AbstractModule
{
  @Override 
  protected void configure()
  {
    bind(TransactionLog.class).to(DatabaseTransactionLog.class);
    bind(CreditCardProcessor.class).to(PaypalCreditCardProcessor.class);
    bind(BillingService.class).to(RealBillingService.class);
  }
}
  • Where to inject: mark the location to tell Guice where to replace interface with implementation
public class RealBillingService implements BillingService 
{
  private final CreditCardProcessor processor;
  private final TransactionLog transactionLog;

  @Inject
  public RealBillingService(CreditCardProcessor processor, TransactionLog transactionLog) 
  {
    this.processor = processor;
    this.transactionLog = transactionLog;
  }
....
}
  • How to inject: Usage of Guice, create injector based on module, injector is like a map.
public static void main(String[] args) 
{
    Injector injector = Guice.createInjector(new BillingModule());
    BillingService billingService = injector.getInstance(BillingService.class);
    ...
}

AspectJ, Spring, and Guice

Recently, I have some time to take a look at these 3 things, mainly on AOP part.

Spring has a very good support for AOP, but the main problem is, all the beans need to be managed by Spring's container, otherwise, AOP won't work. This is ideal if you have a completely Spring-powered project. But it won't do you any good if you are not.

[Not exactly: Spring could inject values into non-Spring bean]

1. define bean in config as abstract plus the configurations, the id, let's see, is "testBean1"
2. add @configurable("testBean1") before the class in .java file.
3. add in config file.

It seems behind the scene, it's still AspectJ is doing all the work.

Guice has the same problem, the Java classes have to be binded by Guice's injector to have AOP work.

That leaves only one choice, AspectJ.
With AspectJ, we could have a very powerful tool to work on big project.

Imagine your boss gives you this task: log the result whenever a method named getMyMoneyBack() gets called. Sound easy? Not so fast, the problem is getMyMoneyBack() exists in thousands of classes, and they are called by millions of times. You really don't want to go to millions of places to put your log code there, do you?

With AspectJ, life is much easier.

You define a point cut like:

pointcut logGetMyMoneyBack() : call (* *.getMyMoneyBack(..))

String around() : logGetMyMoneyBack
{
String result = proceed();
System.out.println(result );
return result;
}
return proceed();

Guice


Here is the idea:

You have a class A, which depends on class B and class C.
First step, you want to create interface iB for class B and interface iC for class C, why? won't you rather depend on an interface than an concrete class? This will give a flexibility to use whatever classes you like to use, as long as they implement the interface. For example, B is concrete class for credit card processing, when you do the test, you don't want to call B to do a real credit card processing, right? Ok, so are we good to depend on interface?

Second step, in the run time, which concrete class to use? Guice provides a simple way, called Module, what Module does is binding interface with concrete class. So you could have many Modules, for example, in Module1, you bind iB to class B1, and iC to C1, while in Module2, you could bind iB to class B2, and iC to C2. In runtime, you could decide to use which Module as you like.

Ok, all these are just theories, now let's dive into the bolts and nolts.

Class A have 2 dependencies in iB and iC, in its constructor, you need add an annotation, @Inject, this signal Guice that we want to do Dependency Injection.

In the codes where you want to use class A, you don't need call A's constructor, instead, you use Guice injector

Injector injector = Guice.createInjector(new Module1());
Class A = injector.getInstance(A.class);

That's it.
Let's calm down to understand what's we have just done, it's a lot.

1. We create a Class A instance without calling its constructor.
2. We have binded its 2 dependencies into class A. not just interfaces, but real concrete classes: B1 and C1.

Now you see, A doesn't even know anything about B1 and C1, they are completely decoupled. Their only glue is interface iB and iC. And Guice injector makes it super easy to bind them together in run time. aHa....

Also, you Module1 is also decoupled from Class A, if A doesn't have the annotation, Module1 will just leave it alone.