Dependency Injection Frameworks Technion – Institute of Technology 236700 1 Author: Assaf Israel -...
-
Upload
shon-stone -
Category
Documents
-
view
215 -
download
0
Transcript of Dependency Injection Frameworks Technion – Institute of Technology 236700 1 Author: Assaf Israel -...
![Page 1: Dependency Injection Frameworks Technion – Institute of Technology 236700 1 Author: Assaf Israel - Technion 2013 ©](https://reader036.fdocuments.in/reader036/viewer/2022082613/5697c00d1a28abf838cc9835/html5/thumbnails/1.jpg)
Dependency Injection FrameworksTechnion – Institute of Technology236700
1
Auth
or: A
ssaf
Isra
el -
Tech
nion
201
3 ©
![Page 2: Dependency Injection Frameworks Technion – Institute of Technology 236700 1 Author: Assaf Israel - Technion 2013 ©](https://reader036.fdocuments.in/reader036/viewer/2022082613/5697c00d1a28abf838cc9835/html5/thumbnails/2.jpg)
Dependency Injection – Drawbacks (deep)What happens when we need to perform deep injections with no defaults?• Consider the following simple design:• A is dependent on B, which is dependent on C, which is dependent on D…
• In order to create an instance of A, we need to inject it with an instance of B, which needs to be injected with an instance of C which needs to be injected with an instance of D…• A a = new AImpl(new BImpl(new CImpl(new DImpl())));
• What if each class has two or more dependencies?• What happens if we have parallel dependencies?
• e.g., one for local database, another for cloud management, one for development
• It is hard to wire everything up without mistakes• We could just put everything in a single abstract factory…• …but that breaks encapsulation
Auth
or: G
al L
alou
che
- Tec
hnio
n 20
15 ©
2
![Page 3: Dependency Injection Frameworks Technion – Institute of Technology 236700 1 Author: Assaf Israel - Technion 2013 ©](https://reader036.fdocuments.in/reader036/viewer/2022082613/5697c00d1a28abf838cc9835/html5/thumbnails/3.jpg)
Dependency Injection Frameworks• Completely separate object configuration
from creation, allowing for cleaner code• Can inject recursively• Easy to manage parallel instantiations
Auth
or: G
al L
alou
che
- Tec
hnio
n 20
15 ©
3
![Page 4: Dependency Injection Frameworks Technion – Institute of Technology 236700 1 Author: Assaf Israel - Technion 2013 ©](https://reader036.fdocuments.in/reader036/viewer/2022082613/5697c00d1a28abf838cc9835/html5/thumbnails/4.jpg)
Dependency Injection Libraries – Java World• Guice• https://github.com/google/guice
• Spring• http://www.springsource.org
• Pico• http://www.picocontainer.org
Auth
or: G
al L
alou
che
- Tec
hnio
n 20
15 ©
4
Our focus today
![Page 5: Dependency Injection Frameworks Technion – Institute of Technology 236700 1 Author: Assaf Israel - Technion 2013 ©](https://reader036.fdocuments.in/reader036/viewer/2022082613/5697c00d1a28abf838cc9835/html5/thumbnails/5.jpg)
Guice – Supplier • Supplier code (using annotations):
• @Inject can be applied to:• Constructors• Methods
• All methods annotated with @Inject will be invoked after the object’s instantiation
• Fields (not recommended)
Auth
or: G
al L
alou
che
- Tec
hnio
n 20
15 ©
5
class MyBillingService implements BillingService {private final CreditCardProcessor processor;
@Injectpublic MyBillingService(CreditCardProcessor p) {
processor = p;}…
}
That’s it!
![Page 6: Dependency Injection Frameworks Technion – Institute of Technology 236700 1 Author: Assaf Israel - Technion 2013 ©](https://reader036.fdocuments.in/reader036/viewer/2022082613/5697c00d1a28abf838cc9835/html5/thumbnails/6.jpg)
Guice – Complex Dependencies• Dependencies can also be complex to create:
• BankAccount may have dependencies of its own• TxApprover may be an interface
Auth
or: G
al L
alou
che
- Tec
hnio
n 20
15 ©
6
class VisaCreditCardProcessor implements CreditCardProcessor {private final BankAccount account;private final TxApprover txApprover;
@Injectpublic VisaCreditCardProcessor(BankAccount a, TxApprover t) {
account = a;txApprover = t;
}…
}
![Page 7: Dependency Injection Frameworks Technion – Institute of Technology 236700 1 Author: Assaf Israel - Technion 2013 ©](https://reader036.fdocuments.in/reader036/viewer/2022082613/5697c00d1a28abf838cc9835/html5/thumbnails/7.jpg)
Guice – Module• Dependencies are described in a separate Module class:
• Client code is now:
• Guice will recursively build the requested binding objects• In this case a MyBillingService object will be created with DatabaseTxLog and a VisaProcessor
Auth
or: G
al L
alou
che
- Tec
hnio
n 20
15 ©
7
public class BillingModule extends AbstractModule {@Overrideprotected void configure() {
bind(CreditCardProcessor.class).to(VisaCreditCardProcessor.class);bind(TxApprover.class).to(VisaIsraelTxApprover.class);bind(BillingService.class).to(MyBillingService.class);
}}
Injector injector = Guice.createInjector(new BillingModule());BillingService billingService = injector.getInstance(BillingService.class);
![Page 8: Dependency Injection Frameworks Technion – Institute of Technology 236700 1 Author: Assaf Israel - Technion 2013 ©](https://reader036.fdocuments.in/reader036/viewer/2022082613/5697c00d1a28abf838cc9835/html5/thumbnails/8.jpg)
Guice advanced binding
• Can bind concrete types by:• Type• Name• Annotation
• Can bind to:• A class (new instance every time)• An object (a specific instance)• Generic classes
Auth
or: G
al L
alou
che
- Tec
hnio
n 20
15 ©
8
![Page 9: Dependency Injection Frameworks Technion – Institute of Technology 236700 1 Author: Assaf Israel - Technion 2013 ©](https://reader036.fdocuments.in/reader036/viewer/2022082613/5697c00d1a28abf838cc9835/html5/thumbnails/9.jpg)
Annotation binding – annotationsBinding to annotated class:
• Persistent TransactionLogs should bind to SqlTxLog • Un-persistent TransactionLogs should bind to StringTxLog
Auth
or: G
al L
alou
che
- Tec
hnio
n 20
15 ©
9
public class BillingModule extends AbstractModule {@Overrideprotected void configure() {
bind(TransactionLog.class).to(StringTxLog.class);bind(TransactionLog.class)
.annotatedWith(Persistent.class) .to(SqlTxLog.class);
}}
public class PersistentLogger { public PersistentLogger(@Persistent TransactionLog l) { this.l = l; }}
![Page 10: Dependency Injection Frameworks Technion – Institute of Technology 236700 1 Author: Assaf Israel - Technion 2013 ©](https://reader036.fdocuments.in/reader036/viewer/2022082613/5697c00d1a28abf838cc9835/html5/thumbnails/10.jpg)
Binding constants using @Named• We can use an annotation “shortcut” using @Named
• Bind to specific constant object (instantiated only once)
Auth
or: G
al L
alou
che
- Tec
hnio
n 20
15 ©
10
class SqlTxLog {@Injectpublic SqlTxLog(@Named(″JDBC URL″) String connectionURL,
@Named(″login timeout seconds″) Integer timeout) { … }}
public class SqlTxLogModule extends AbstractModule { @Override protected void configure() { bind(String.class)
.annotatedWith(Names.named("JDBC URL"))
.toInstance("jdbc:mysql://localhost/pizza"); bind(Integer.class)
.annotatedWith(Names.named(″login timeout seconds”))
.toInstance(10); }}
![Page 11: Dependency Injection Frameworks Technion – Institute of Technology 236700 1 Author: Assaf Israel - Technion 2013 ©](https://reader036.fdocuments.in/reader036/viewer/2022082613/5697c00d1a28abf838cc9835/html5/thumbnails/11.jpg)
More on Binding to InstanceThere are two ways to bind an instance:• Using .toInstance passing an instance
• Using .to(SomeClass.class).in(Singleton.class)
• A single instance is created by Guice• Dependencies are injected according to the Module• We can also use @Singleton on the bound class
Auth
or: G
al L
alou
che
- Tec
hnio
n 20
15 ©
11
bind(String.class) .annotatedWith(Names.named("login timeout seconds")) .toInstance("10");
bind(BillingService.class) .to(MyBillingService.class).in(Singleton.class);
![Page 12: Dependency Injection Frameworks Technion – Institute of Technology 236700 1 Author: Assaf Israel - Technion 2013 ©](https://reader036.fdocuments.in/reader036/viewer/2022082613/5697c00d1a28abf838cc9835/html5/thumbnails/12.jpg)
Creational logic with @ProvidesIf we have some non-trivial creational logic we can write it in a @Provides method in the Module• If this method receives any arguments they will be injected• We can also annotate the return type
Auth
or: G
al L
alou
che
- Tec
hnio
n 20
15 ©
12
public class MyPaymentModule extends AbstractModule { @Override protected void configure() { … }
… @Provides @Persistent // will be provided to dependencies annotated with @Persistent TransactionLog provideTxLog(@Named(″JDBC URL″) String conURL) { DatabaseTransactionLog transactionLog = new DatabaseTxLog(); transactionLog.setJdbcUrl(connectionURL); transactionLog.setThreadPoolSize(30); return transactionLog; }}
![Page 13: Dependency Injection Frameworks Technion – Institute of Technology 236700 1 Author: Assaf Israel - Technion 2013 ©](https://reader036.fdocuments.in/reader036/viewer/2022082613/5697c00d1a28abf838cc9835/html5/thumbnails/13.jpg)
Factories with provider<T>sHow do we pass factories?• Naïve solution: simply inject an AbstractFactory
• We have to create a special VisaProcessorFactory class to bind to
• We bind both to VisaProcessor and VisaProcessorFactory; that’s not very DRY…
Auth
or: G
al L
alou
che
- Tec
hnio
n 20
15 ©
13
class MyBillingService implements BillingService {@Injectpublic MyBillingService(CreditCardProcessorFactory pf) {
this.factory = pf;}
}…// module:bind(CreditCardProcessor.class).to(VisaProcessor.class);bind(CreditCardProcessorFactory.class).to(VisaProcessorFactory.class);
![Page 14: Dependency Injection Frameworks Technion – Institute of Technology 236700 1 Author: Assaf Israel - Technion 2013 ©](https://reader036.fdocuments.in/reader036/viewer/2022082613/5697c00d1a28abf838cc9835/html5/thumbnails/14.jpg)
Factories with provider<T>s (cont.)• Using providers achieves just that!
• We don’t have to bind the provider explicitly, since we already bound VisaProcessor
• Food for thought: why don’t we have a problem with type erasure here?
• This makes the Guice injector instance in essence a FactoryFactory, but it is okay in this case because we don’t need any extra code to support it!
Auth
or: G
al L
alou
che
- Tec
hnio
n 20
15 ©
14
class MyBillingService implements BillingService {@Injectpublic MyBillingService(Provider<CreditCardProcessor> pf) {
this.factory = pf;}
}…// module:bind(CreditCardProcessor.class).to(VisaProcessor.class);
![Page 15: Dependency Injection Frameworks Technion – Institute of Technology 236700 1 Author: Assaf Israel - Technion 2013 ©](https://reader036.fdocuments.in/reader036/viewer/2022082613/5697c00d1a28abf838cc9835/html5/thumbnails/15.jpg)
Binding GenericsBinding generics is a bit complicated due to type erasure• Binding classes with generic dependencies:
• Binding generic classes:
Auth
or: G
al L
alou
che
- Tec
hnio
n 20
15 ©
15
class A { @Inject public A(List<String> list) {…}}
…bind(new TypeLiteral<List<String>>(){}).to(new TypeLiteral<ArrayList<String>>(){});
…injector.getInstance(A.class); // A will be injected an ArrayList
class B<T> { @Inject public B(List<T> list) {…}}
…bind(new TypeLiteral<List<Integer>>(){}) .to(new TypeLiteral<ArrayList<Integer>>(){});
…injector.getInstance(new Key<B<Integer>>(){}); // B will be injected an ArrayList
![Page 16: Dependency Injection Frameworks Technion – Institute of Technology 236700 1 Author: Assaf Israel - Technion 2013 ©](https://reader036.fdocuments.in/reader036/viewer/2022082613/5697c00d1a28abf838cc9835/html5/thumbnails/16.jpg)
Outcome• What we’ve achieved?• Both client and supplier are decoupled from implementation
details• All dependency logic is executed at runtime and is contained in
Modules• A module encapsulates all creation logic in our program• Testing & Mocking is easy – since we’re essentially using constructor
injection
• Side-note:• Other DI frameworks (e.g. Spring) use XML files to define
dependencies• This enables changing the code’s behavior without recompiling• But it also has its disadvantages (e.g. it’s not type safe)
Auth
or: G
al L
alou
che
- Tec
hnio
n 20
15 ©
16
![Page 17: Dependency Injection Frameworks Technion – Institute of Technology 236700 1 Author: Assaf Israel - Technion 2013 ©](https://reader036.fdocuments.in/reader036/viewer/2022082613/5697c00d1a28abf838cc9835/html5/thumbnails/17.jpg)
Auth
or: G
al L
alou
che
- Tec
hnio
n 20
15 ©
Dependency Injection – Is it really that important?• If we want to write real units tests, then we have to isolate our
units• If we want to isolate our units, then we have to use mocks• If we want to use mocks, we have to inject them somehow
But we aren’t doing it (just) for the tests!• If we use dependency injection, our code is less coupled, more
modular, robust, and reusable, cohesive, cleaner and DRYer.
Remember, Testable Code => Better Code!17
Unit Tests Mock objects
DependencyInjection