Roll-your-own DI
- no 3rd party framework dependency, but...
- leads to code duplication
- you'll end up creating your own framework of factories, etc in the end
- generally a waste of time
z, ? | toggle help (this) |
space, → | next slide |
shift-space, ← | previous slide |
d | toggle debug mode |
## <ret> | go to slide # |
c, t | table of contents (vi) |
f | toggle footer |
r | reload slides |
n | toggle notes |
p | run preshow |
style-*
project sources http://github.com/cbeams/distylesTransferService
public class TransferService {
public void transfer(double amount,
String fromId, String toId) {
Account from = accounts.findById(fromId);
Account to = accounts.findById(fromId);
from.debit(amount);
to.credit(amount);
}
}
public class TransferService {
public void transfer(double amount,
String fromId, String toId) {
// TransferService has a dependency on 'accounts'
Account from = accounts.findById(fromId);
Account to = accounts.findById(fromId);
from.debit(amount);
to.credit(amount);
}
}
public class TransferService {
public void transfer(double amount,
String fromId, String toId) {
// where does the 'accounts' object come from?
Account from = accounts.findById(fromId);
Account to = accounts.findById(fromId);
from.debit(amount);
to.credit(amount);
}
}
public class TransferService {
public void transfer(double amount,
String fromId, String toId) {
AccountRepo accounts = // direct instantiation?
new JdbcAccountRepo(...); // (not a great option)
Account from = accounts.findById(fromId);
Account to = accounts.findById(fromId);
from.debit(amount);
to.credit(amount);
}
}
public class TransferService {
public void transfer(double amount,
String fromId, String toId) {
AccountRepo accounts = // singleton lookup?
AccountRepoFactory.get(); // (not a great option)
Account from = accounts.findById(fromId);
Account to = accounts.findById(fromId);
from.debit(amount);
to.credit(amount);
}
}
public class TransferService {
public void transfer(double amount,
String fromId, String toId) {
AccountRepo accounts = // JNDI lookup?
jndiCtx.lookup("accts"); // (not a great option)
Account from = accounts.findById(fromId);
Account to = accounts.findById(fromId);
from.debit(amount);
to.credit(amount);
}
}
public class TransferService {
public void transfer(double amount,
String fromId, String toId) {
// all of the above are forms of 'dependency lookup';
// transfer() becomes inflexible, can't be unit-tested
Account from = accounts.findById(fromId);
Account to = accounts.findById(fromId);
from.debit(amount);
to.credit(amount);
}
}
public class TransferService {
private final AccountRepo accounts;
public TransferService(AccountRepo accounts) {
this.accounts = accounts; // dependency injection!
} // (a much better option)
public void transfer(double amount,
String fromId, String toId) {
Account from = accounts.findById(fromId);
Account to = accounts.findById(fromId);
from.debit(amount);
to.credit(amount);
}
}
public class TransferService {
private final AccountRepo accounts;
public TransferService(AccountRepo accounts) {
this.accounts = accounts;
}
public void transfer(double amount,
String fromId, String toId) {
// the transfer method remains simple, testable, etc
Account from = accounts.findById(fromId);
Account to = accounts.findById(fromId);
from.debit(amount);
to.credit(amount);
}
}
public TransferService(AccountRepo accounts) {
this.accounts = accounts;
}
public static void main(String... args)
throws InsufficientFundsException, IOException {
DataSource dataSource = ...; // not enough slide space!
Properties props = new Properties();
props.load(TransferScript.class.getClassLoader()
.getResourceAsStream("com/.../app.properties"));
TransferService transferService =
new DefaultTransferService(
new JdbcAccountRepository(dataSource),
new FlatFeePolicy(
Double.valueOf(props.getProperty("flatfee.amt"))));
transferService.setMinimumTransferAmount(
Double.valueOf(props.getProperty("min.xfer.amt")));
transferService.transfer(10.00, "A123", "C456");
}
public static void main(String... args)
ApplicationContext ctx =
new GenericXmlApplicationContext("app-config.xml");
TransferService transferService =
ctx.getBean(TransferService.class);
transferService.transfer(10.00, "A123", "C456");
}
<beans>
XML<beans>
XMLApplicationContext ctx =
new GenericXmlApplicationContext("app-config.xml");
<beans>
XML<beans>
XML<namespace:*>
XML<context:property-placeholder/>
<jdbc:embedded-database/>
<tx:annotation-driven/>
<jee:jndi-lookup/>
<namespace:*>
XML<context:property-placeholder
locations="com/bank/app-config.xml/>
<namespace:*>
XML<namespace:*>
XML<beans:*>
<aop:*>
<beans:*>
<cache:*>
<context:*>
<jdbc:*>
<jee:*>
<jms:*>
<lang:*>
<mvc:*>
<oxm:*>
<task:*>
<tool:*>
<tx:*>
<util:*>
<namespace:*>
XML<bean>
elements@Autowired
@Component
<context:component-scan/>
<context:component-scan
base-package="com.bank"/>
@ContextConfiguration
and friends@Controllers
@Configuration
classes instead of <beans>
XML documents@Bean
methods instead of <bean>
elements
@Configuration
@EnableTransactionManagement
public class AppConfig {
@Bean
public QuoteService quoteService() {
RealTimeQuoteService quoteService = ...;
return quoteService;
}
}
// @Configuration classes ~= <beans/> documents
@Configuration
@EnableTransactionManagement
public class AppConfig {
@Bean
public QuoteService quoteService() {
RealTimeQuoteService quoteService = ...;
return quoteService;
}
}
@Configuration
@EnableTransactionManagement // ~= <tx:annotation-driven>
public class AppConfig {
@Bean
public QuoteService quoteService() {
RealTimeQuoteService quoteService = ...;
return quoteService;
}
}
@Configuration
@EnableTransactionManagement
public class AppConfig {
// @Bean methods ~= <bean/> elements
@Bean
public QuoteService quoteService() {
RealTimeQuoteService quoteService = ...;
return quoteService;
}
}
@Configuration
@EnableTransactionManagement
public class AppConfig {
@Bean
public QuoteService quoteService() {
RealTimeQuoteService quoteService = // instantiate
return quoteService;
}
}
@Configuration
@EnableTransactionManagement
public class AppConfig {
@Bean
public QuoteService quoteService() {
RealTimeQuoteService quoteService = ...;
// configure
return quoteService;
}
}
@Configuration
@EnableTransactionManagement
public class AppConfig {
@Bean
public QuoteService quoteService() {
RealTimeQuoteService quoteService = ...;
return quoteService; // object managed by Spring
}
}
public static void main(String... args) {
ApplicationContext ctx =
new AnnotationConfigApplicationContext(AppConfig.class);
QuoteService quoteService =
ctx.getBean(QuoteService.class);
System.out.println(quoteService.currentValue("AAPL"));
}
public static void main(String... args) {
// bootstrap the Spring container
ApplicationContext ctx =
new AnnotationConfigApplicationContext(AppConfig.class);
QuoteService quoteService =
ctx.getBean(QuoteService.class);
System.out.println(quoteService.currentValue("AAPL"));
}
public static void main(String... args) {
ApplicationContext ctx =
new AnnotationConfigApplicationContext(AppConfig.class);
// retrieve the bean we want to use in type-safe fashion
QuoteService quoteService =
ctx.getBean(QuoteService.class);
System.out.println(quoteService.currentValue("AAPL"));
}
public static void main(String... args) {
ApplicationContext ctx =
new AnnotationConfigApplicationContext(AppConfig.class);
QuoteService quoteService =
ctx.getBean(QuoteService.class);
// use the bean however desired
System.out.println(quoteService.currentValue("AAPL"));
}
@Component
, @Autowired
) vs. central blueprints (XML, @Configuration
classes)@cbeams
@springframework
style-*
project sources: http://github.com/cbeams/distyles