Dependency Injection Styles

72
© 2010 SpringSource, A division of VMware. All rights reserved CONFIDENTIAL © 2010 SpringSource, A division of VMware. All rights reserved CONFIDENTIAL DI Styles: Choosing the Right Tool for the Job Chris Beams, Senior Technical Staff, SpringSource

description

"Dependency Injection Styles" by Chris Beams. Spring User Group France, 2010-06-10.

Transcript of Dependency Injection Styles

Page 1: Dependency Injection Styles

© 2010 SpringSource, A division of VMware. All rights reserved

CONFIDENTIAL

© 2010 SpringSource, A division of VMware. All rights reserved

CONFIDENTIAL

DI Styles: Choosing the Right Tool for the Job

Chris Beams, Senior Technical Staff, SpringSource

Page 2: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 2

Hello!

Chris Beams• Senior Staff Engineer with SpringSource

• Member Core Spring team

• Trained hundreds to use Spring effectively

• Author of the forthcoming Spring in a Nutshell (O'Reilly)

Page 3: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 3

Dependency Injection: Simple, Right?

TransferService AccountRepository

public TransferService(AccountRepository ar) { this.accountRepository = ar;}

Page 4: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 4

Choices

@Inject

@Autowired

<context:component-scan/>

<bean/>

@Component

@Configuration

@Bean

@Configurable

<context:annotation-config/>

...

Page 5: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 5

Agenda

A brief history of Dependency Injection (DI)

Seven characteristics of a DI style

A demo-centric tour of Spring DI styles• Comparative analysis of available styles

• What's new in Spring 3 for DI

• Demo sources available at:• http://github.com/cbeams/distyles

Page 6: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 6

Agenda

A brief history of Dependency Injection (DI)

Seven characteristics of a DI style

A demo-centric tour of Spring DI styles• Comparative analysis of available styles

• What's new in Spring 3 for DI

• Demo sources available at:• https://src.springsource.org/svn/springone2gx/distyles

Page 7: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 7

Agenda

A brief history of Dependency Injection (DI)

Seven characteristics of a DI style

A demo-centric tour of Spring DI styles• Comparative analysis of available styles

• What's new in Spring 3 for DI

• Demo sources available online• http://github.org/cbeams/distyles

Page 8: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 8

A one-slide history of DI

2000: Fowler, et al coin 'POJO'

2002: Johnson, et al: 1:1 J2EE; J2EE w/o EJB

2002-3: Spring and other 'lightweight IoC containers' emerge

2004: Fowler coins 'Dependency Injection as a specialization of the Inversion of Control principle'• Defined three 'types' of DI

• Constructor Injection

• Setter Injection

• Interface Injection

2004-present: Spring evolves; DI is widely adopted

Page 9: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 9

DI: Why?

Dependency Injection enables 'POJO programming'

POJO programming facilitates• Simplicity• Effective separation of concerns• Proper unit testing

Well-factored and well-tested code• Tends to be well-designed code• Evolves well into maintainable systems

Page 10: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 10

DI: Where to Inject?

Three possible 'Injection Points'• Constructor

• Good for mandatory dependencies• Setter

• Good for optional dependencies• Field

• Good for injecting system test fixtures in JUnit tests

Page 11: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 11

DI: How to Configure?

Styles for expressing DI metadata and instructions• External

• Configuration files (XML, properties, ...)• Code (Java)• DSL (Spring XML namespaces, Groovy, ...)

• Internal• Annotations embedded within POJOs• Usually requires at least some external configuration

Page 12: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 12

DI: Evolution

We've come a long way since Fowler coined DI

Today developers are faced with many choices• Annotations changed the game• Rise of non-Java languages on the JVM creates new possibilities

Page 13: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 13

DI: Today's Choices

Open-source projects• Spring• Grails BeanBuilder• Google Guice• Many other projects across languages

Standards efforts• JSR-250 (Common Annotations)• JSR-299 (Java Contexts and Dependency Injection)• JSR-330 (Dependency Injection for Java)• OSGi 4.2 Blueprint Container

Page 14: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 14

Choosing a DI Style

Page 15: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 15

DI Configuration: What matters to you?

Let's begin by defining the characteristics that matter when thinking about DI

Provide a framework for making decisions about your own applications

Page 16: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 16

Seven Characteristics of a DI Style

1.External vs. Internal

2.Explicit vs. Implicit

3.Type-safety

4.Noninvasiveness

5.Portability (of POJOs)

6.Configurability of 3rd party components

7.Tooling support

Page 17: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 17

Characteristic 1: External vs. Internal

Internal

@Componentpublic class TransferServiceImpl implements TransferService { @Autowired public TransferServiceImpl(AccountRepository repo) { this.accountRepository = repo; } …}

<bean id=“transferService” class=“com.bank.TransferServiceImpl”> <constructor-arg ref=“accountRepository” /></bean>

External

Page 18: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 18

Characteristic 1: External vs. Internal

External DI is noninvasive• But causes context-switching during coding• More verbose• Provides a 'blueprint' of your application

Internal DI is necessarily invasive• May or may not be portable• But requires less coding and maintenance• Easier to use during development

Page 19: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 19

Seven Characteristics of a DI Style

1.External vs. Internal

2.Explicit vs. Implicit

3.Type-safety

4.Noninvasiveness

5.Portability (of POJOs)

6.Configurability of 3rd party components

7.Tooling support

Page 20: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 20

Characteristic 2: Explicit vs. Implicit

<bean id=“transferService” class=“com.bank.TransferServiceImpl”> <constructor-arg ref=“accountRepository” /> <constructor-arg ref=“feePolicy” /></bean>

<bean id=“accountRepository” class=“com.bank.JdbcAccountRepository”><bean id=“feePolicy” class=“com.bank.FlatFeePolicy”>

public class TransferServiceImpl implements TransferService { public TransferServiceImpl(AccountRepository accountRepository, FeePolicy feePolicy) { … } … }

Page 21: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 21

Characteristic 2: Explicit vs. Implicit

<context:component-scan base-package=“com.bank">

@Componentpublic class TransferServiceImpl implements TransferService { @Autowired public TransferServiceImpl(AccountRepository accountRepository,

FeePolicy feePolicy) { … } … }

@Componentpublic class JdbcAccountRepository implements AccountRepository{ … }

@Componentpublic class FlatFeePolicy implements FeePolicy{ … }

Page 22: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 22

Characteristic 2: Explicit vs. Implicit

Explicit DI comes with greater verbosity• More tedious in simple cases• Easier and more clear when things get complicated

Implicit DI introduces the possibility of ambiguity• If multiple implementations of a given type are detected / scanned• Disambiguation strategies are required• But ambiguities may arise at any time

Page 23: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 23

Explicit vs. Implicit: Ambiguity

<context:component-scan base-package=“com.bank">

@Componentpublic class TransferServiceImpl implements TransferService { @Autowired public TransferServiceImpl(AccountRepository accountRepository, FeePolicy feePolicy) { … } … }

@Componentpublic class JdbcAccountRepository implements AccountRepository{ … }

@Componentpublic class FlatFeePolicy implements FeePolicy{ … }

@Componentpublic class VariableFeePolicy implements FeePolicy{ … }

Which one should get injected?

Page 24: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 24

Implicit DI: Disambiguation

<context:component-scan base-package=“com.bank">

@Componentpublic class TransferServiceImpl implements TransferService { @Autowired public TransferServiceImpl(AccountRepository repo, @Qualifer(“domestic”) FeePolicy feePolicy) { … } … }

@Componentpublic class JdbcAccountRepository implements AccountRepository{ … }

@Component@Qualifier(“domestic”) public class FlatFeePolicy implements FeePolicy{ … }

@Component(“international”) public class VariableFeePolicy implements FeePolicy{ … }

Page 25: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 25

Seven Characteristics of a DI Style

1.External vs. Internal

2.Explicit vs. Implicit

3.Type-safety

4.Noninvasiveness

5.Portability (of POJOs)

6.Configurability of 3rd party components

7.Tooling support

Page 26: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 26

Characteristic 3: Type-safety

XML is inherently not type-safe• Tooling can mitigate this

• STS/IDEA/NetBeans are Spring XML-aware and can raise warnings and errors at development time

How can one get the compiler to catch errors in DI configuration?• Custom @Qualifier annotations• @Configuration classes

Page 27: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 27

Seven Characteristics of a DI Style

1.External vs. Internal

2.Explicit vs. Implicit

3.Type-safety

4.Noninvasiveness

5.Portability (of POJOs)

6.Configurability of 3rd party components

7.Tooling support

Page 28: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 28

Characteristic 4: (Non)invasiveness

Originally, noninvasiveness was a defining characteristic of DI and POJO programming

Noninvasiveness matters because• An object should be usable independent of its environment and context• Especially important when it comes to testing

But...• Annotations changed this

Page 29: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 29

Annotations and Invasiveness

Annotations, by definition, are invasive• Requires modifying POJOs

But we may say they are minimally invasive• Because annotations have no detrimental effect on the utility of a POJO• Java 6 even allows for annotations to be missing from the classpath at

runtime

Non-standard annotations still impact portability

Page 30: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 30

Seven Characteristics of a DI Style

1.External vs. Internal

2.Explicit vs. Implicit

3.Type-safety

4.Noninvasiveness

5.Portability (of POJOs)

6.Configurability of 3rd party components

7.Tooling support

Page 31: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 31

Characteristic 5: Portability

Ideally, a POJO should be reusable across DI frameworks

Non-standard annotations tie you to a particular framework• Hence the desire for standardization• JSR-330!

Page 32: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 32

Seven Characteristics of a DI Style

1.External vs. Internal

2.Explicit vs. Implicit

3.Type-safety

4.Noninvasiveness

5.Portability (of POJOs)

6.Configurability of 3rd party components

7.Tooling support

Page 33: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 33

Characteristic 6: Configurability of 3rd Party Components

Internal configuration and 3rd party components don't mix• You can't annotate somebody else's code

External configuration is the only way• Hence a complete DI solution must support both

Page 34: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 34

Seven Characteristics of a DI Style

1.External vs. Internal

2.Explicit vs. Implicit

3.Type-safety

4.Noninvasiveness

5.Portability (of POJOs)

6.Configurability of 3rd party components

7.Tooling support

Page 35: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 35

Characteristic 7: Tooling Support

Natural, integrated refactoring• XML-driven DI requires Spring-aware tooling• Code-driven DI takes advantage of built-in IDE Java tooling

Content Assist in configuration files• Generic XML tooling only gets you so far• Need XML tooling built to purpose

Visualization• Seeing the 'blueprint' of your application

Other concerns• Static analysis• Obfuscation

Page 36: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 36

SpringSource Tool Suite (STS)

Page 37: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 37

A Tour of DI Styles

Page 38: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 38

DI Styles

XML• <beans/>• <namespace:*/>

@Autowired

@Configuration

Standards• JSR-250 (Common Annotations)• JSR-299 (Java Contexts and Dependency Injection)• JSR-330 (Dependency Injection for Java)

Page 39: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 39

DI Styles

Remember...• DI styles need not be mutually exclusive!• You'll probably use more than one in a given app

Page 40: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 40

<beans/>

Page 41: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 41

<beans/> XML

The original DI style for Spring

Remains very widely used

General-purpose, thus very powerful

But can get verbose / maintenance-intensive

Page 42: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 42

<beans/> demo

Page 43: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 43

<beans/>: Summary

1.External vs. Internal: External

2.Explicit vs. Implicit: Explicit

3.Type-safe: No

4.Noninvasive: Yes

5.Portable: Yes

6.Can configure 3rd party components: Yes

7.Has tooling support: Yes

Page 44: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 44

<namespace:*/>

Page 45: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 45

<namespace:*/> XML

Introduced in Spring 2.0

Expanded in Spring 2.5 and 3.0

Widely supported by Spring projects• Spring Integration• Spring Batch• Spring Web Flow• Spring Security• ...

Greatly reduces XML verbosity

More expressive at the same time

Page 46: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 46

<namespace:*/> demo

Page 47: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 47

<namespace:*/>: Summary

Same fundamental characteristics as <beans/>

But eliminates much of the verbosity problem with XML• Serves as a 'configuration DSL'

Not just about DI• Helps manage many other aspects of the application

• Scheduling, AOP, security, etc.

Page 48: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 48

@Autowired

Page 49: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 49

@Autowired

AKA "Annotation-driven injection"

Introduced in Spring 2.5

More annotations added in Spring 3.0• @Primary• @Lazy• @DependsOn• extended semantics for @Scope

Widely used today

Works in conjunction with @Component and <context:component-scan/> to streamline development lifecycle

Page 50: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 50

@Autowired demo

Page 51: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 51

@Autowired: Summary

1.External vs. Internal: Internal

2.Explicit vs. Implicit: Implicit

3.Type-safe: Yes

4.Noninvasive: No

5.Portable: No

6.Can configure 3rd party components: No

7.Has tooling support: Yes (as of STS 2.2.0)

Page 52: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 52

JSR-330 (@Inject)

Page 53: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 53

Introducing JSR-330

AKA @Inject

A joint JCP effort by Google and SpringSource

Provides common understanding of injection semantics through portable DI annotations

Packaged under javax.inject.* (Java SE)

JSR went final late 2009• API is available in Maven Central

Spring 3.0 GA passes the TCK

Page 54: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 54

Smallest. JSR. Ever.

Page 55: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 55

JSR-330 demo

Page 56: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 56

JSR-330: Summary

1.External vs. Internal: Internal

2.Explicit vs. Implicit: Undefined! (can be either)

3.Type-safe: Yes

4.Noninvasive: No

5.Portable: Yes

6.Can configure 3rd party components: No

7.Has tooling support: Yes (STS)

Page 57: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 57

@Autowired and @Inject: The Bottom Line

JSR-330 standardizes internal DI annotations• Meaning: portable POJOs

However, @Inject is a subset of the functionality provided by Spring's @Autowired support

Rule of thumb• You can get 80% of what you need with @Inject

• Rely on @Autowired and friends for the rest

Page 58: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 58

From @Autowired to @Inject

Spring javax.inject.*

@Autowired @Inject * @Inject has no 'required' attribute

@Component @Named * Spring supports scanning for @Named

@Scope @Scope * for meta-annotation and injection points only

@Scope("singleton")

@Singleton * jsr-330 default scope is like Spring's 'prototype'

@Qualifier @Qualifier, @Named

@Value no equivalent see SPR-6251 for ideas on how Spring can help bridge this gap

@Primary no equivalent

@Lazy no equivalent

@Required no equivalent

Page 59: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 59

@Configuration

Page 60: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 60

@Configuration

Formely Spring JavaConfig

Now included in core Spring Framework 3.0

Annotation-driven, but is an external DI style• POJOs remain untouched by annotations

Provides full programmatic control over object instantiation and DI

Allows for object-oriented configuration

Integrates well with other Spring DI styles

Page 61: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 61

A @Configuration class

@Configurationpublic class AppConfig {

@Bean public TransferService transferService() { return new TransferService(accountRepository()); }

@Bean public AccountRepository accountRepository() { return new JdbcAccountRepository(dataSource()); }

// ...}

Page 62: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 62

Look familiar?

<bean id=“transferService” class=“com.bank.TransferServiceImpl”> <constructor-arg ref=“accountRepo” /></bean>

<bean id=“accountRepo” class=“com.bank.JdbcAccountRepository”> <constructor-arg ref=“dataSource” /></bean>

Page 63: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 63

Bootstrapping @Configuration

public class CommandLineApplication {

public static void main(String... args) { ApplicationContext ctx =

new AnnotationConfigApplicationContext(AppConfig.class);

TransferService transferService = ctx.getBean(TransferService.class);

transferService.transfer(100.00, “A123”, “C456”); }

}

Page 64: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 64

@Configuration demo

Page 65: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 65

@Configuration: Summary

1.External vs. Internal: External

2.Explicit vs. Implicit: Explicit

3.Type-safe: Yes

4.Noninvasive: Yes

5.Portable: Yes

6.Can configure 3rd party components: Yes

7.Has tooling support: Yes

Page 66: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 66

Spring is about choice

Choice in many areas...

All DI metadata (internal or external) contributes to the core BeanDefinition model• This layer is what makes adding different configurations styles possible!

Spring embraces any relevant deployment environment• Use latest DI/EE6 styles on

• J2EE 1.5 and JEE 5

• OSGi

Page 67: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 67

Q&A

Page 68: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 68

Thank you!

https://github.com/cbeams/distyleshttp://twitter.com/cbeams

Page 69: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 69

Groovy/Grails BeanBuilder

Page 70: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 70

BeanBuilder

DSL for creating Spring BeanDefinitions

Currently part of Grails

Work is underway to include within Spring 3.1

Page 71: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 71

Grails BeanBuilder at a Glance

import org.springframework.context.ApplicationContextimport grails.spring.BeanBuilder...def bb = new BeanBuilder()

bb.beans { transferService(TransferServiceImpl, accountRepository, feePolicy) accountRepository(JdbcAccountRepository, dataSource) dataSource(BasicDataSource) { driverClassName = "org.hsqldb.jdbcDriver" url = "jdbc:hsqldb:mem:grailsDB" username = "sa" password = "" }}

ApplicationContext ctx = bb.createApplicationContext();TransferService transferService = ctx.getBean(TransferService);

Page 72: Dependency Injection Styles

CONFIDENTIALCONFIDENTIAL 72

@Configuration: Summary

1.External vs. Internal: External

2.Explicit vs. Implicit: Explicit

3.Type-safe: No

4.Noninvasive: Yes

5.Portable: Yes

6.Can configure 3rd party components: Yes

7.Has tooling support: No