Date post: | 02-Jul-2015 |
Category: |
Technology |
Upload: | montreal-jug |
View: | 943 times |
Download: | 0 times |
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Dependency Injection
Guicewith...
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
About me
Mathieu Carbou Expert Java Developer + 6 years Open-Source projects Code design, Web, Testing, Maven, Spring, WS,
JMS, EDA, OSGI , Security, Hibernate, .... … and Google Guice !
http://code.mycila.com
http://blog.mycila.com
http://www.testatoo.org
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
About the next hour
Pre-DI anti-patterns Evolutions in the Java World DI advantages A little word about Spring... … and a long long time about Guice !
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Pre-DI Anti-Patterns
Manual instanciation
public final class SignupService { public void signup(User user) { EmailService emailService = new EmailService(); emailService.setHost("smtp.company.com"); emailService.setPort(25); emailService.send( "[email protected]", user.getEmail(), "Welcome to Killer App !"); }}
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Pre-DI Anti-Patterns
Factory pattern
public final class SignupService { public void signup(User user) { EmailService emailService =
EmailServiceFactory.getEmailService(); emailService.send( "[email protected]", user.getEmail(), "Welcome to Killer App !"); }}
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Pre-DI Anti-Patterns
Service locator
public void signup(User user) { // retreived from JNDI for example ServiceLocator serviceLocator = getServiceLocator(); EmailService emailService = (EmailService)
serviceLocator.getService("emailService"); emailService.send( "[email protected]", user.getEmail(), "Welcome to Killer App !");}
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Pre-DI Anti-Patterns
Bean factory
public void signup(User user) { // retreived Spring's bean factory BeanFactory beanFactory = getBeanFactory(); EmailService emailService =
(EmailService) beanFactory.getBean("emailService"); emailService.send( "[email protected]", user.getEmail(), "Welcome to Killer App !");}
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Pre-DI Anti-Patterns
Design issues Strong coupling (locator, factory, identifier) No isolation Difficult to test, refactor and maintain
SignupService MailService
ServiceLocator
UserService UserRepository UserRepository
depends
depends
depends
depends
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Pre-DI Anti-Patterns
Potential issues Bad responsibility for client and user classes Static references never garbadged-collected Static shared access issues (concurrency) Static lazy initialization often badly coded
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Pre-DI Anti-Patterns
public final class MyFactory {
private static EmailService EMAIL_SERVICE;
public static EmailService getEmailService() { if(EMAIL_SERVICE == null) { EMAIL_SERVICE = new EmailService(); //object initalization } return EMAIL_SERVICE; }
}
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Pre-DI Anti-Patterns
public final class MyFactory {
private static EmailService EMAIL_SERVICE;
public static synchronized EmailService getEmailService() { if(EMAIL_SERVICE == null) { EMAIL_SERVICE = new EmailService(); //object initalization } return EMAIL_SERVICE; }
}
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Pre-DI Anti-Patterns
public final class MyFactory {
private MyFactory() {}
public static EmailService getEmailService() { return LazyInit.EMAIL_SERVICE; }
private static final class LazyInit { private static final EmailService EMAIL_SERVICE
= new EmailService(); }}
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Evolutions
Metadata representations XML Annotations
Misconception about annotations
Annotations are metadata within classes introducing no dependencies at runtime. A class can be resolved even if its annotations are not in the classpath !
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Evolutions
ByteCode manipulation (ASM, proxy, ...) JSR250 (already in JDK6, commes from J2EE)
@Resource
@PostConstruct
@PreDestroy
JSR330 (next JDK, jar available) @Inject
@Provider
@Named
@Singleton
@Scope
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Evolutions
Generics (type literals) List<Employee> != List<User>
Some DI frameworks till rely on Class (Spring) May crash at runtime (type erasure) !
New DI frameworks use TypeLiteral (Guice) Errors caugth at compile time !
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Evolutions
Example:
public final class FireService {
final List<Employee> employees;
@Inject FireService(List<Employee> employees) { this.employees = employees; }
public void fireAll() { for (Employee employee : employees) employee.fire(); }}
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Evolutions
Guice: Compile error !
Spring (xml): compiles, but fails at runtime !
final class FireModule extends AbstractModule { protected void configure() { bind(new TypeLiteral<List<Employee>>(){})
.toInstance(Arrays.asList(new User())); }}
<bean name="fireService"class="com.mycompany.killerapp.FireService">
<constructor-arg> <list> <bean class="com.mycompany.killerapp.User"/> </list> </constructor-arg></bean>
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
DI Definition
A dependant is contacted by its dependencies
Hollywood principle: Don't call me, I'll call you
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
DI Definition
Example:
public final class FireService {
final List<Employee> employees;
@Inject FireService(List<Employee> employees) { this.employees = employees; }
public void fireAll() { for (Employee employee : employees) employee.fire(); }}
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
DI Advantages
Easier testing & refactoring Easier maintenance Loose coupling Manage object lifetime Better design and use (interfaces) Hide implementation details Write less code (and less bugs)
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
About Spring Framework
Everyone knows it You can compare
Guice != Spring Guice = Advanced DI framework Spring = Integration Framework (JMX, JMS, JDBC,
TX, Hibernate, ...) built upon a DI stack
You can use Spring classes with Guice
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Google Guice !
Open-Sourced by Google First public release in 2007 http://code.google.com/p/google-guice/
Project's lead: Bob Lee Cofounder of AOP Alliance Creator of JAdvise and Dynaop Strong AOP background
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Google Guice !
Version 3 to be released soon
Standardized DI annotations (JSR330)
Focus on: Easy to use Best DI capabilities
Not an integration framework
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Google Guice Ecosystem
Guice Servlets (DSL, DI and lifetime management for servlets and filters)
<listener> <listener-class> com.company.web.guice.GuiceConfig </listener-class></listener><filter> <filter-name>Guice Filter</filter-name> <filter-class> com.google.inject.servlet.GuiceFilter </filter-class></filter><filter-mapping> <filter-name>Guice Filter</filter-name> <url-pattern>/*</url-pattern></filter-mapping>
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Google Guice Ecosystem
Guice Servlets (DSL, DI and lifetime management for servlets and filters)
protected void configureServlets() { Map<String, String> params = new HashMap<String, String>();
/* Shirio Security */ bind(IniShiroFilter.class).in(Scopes.SINGLETON); filter("/*").through(IniShiroFilter.class);
/* Wicket */ params.put(WicketFilter.FILTER_MAPPING_PARAM, "/*"); filter("/page/*").through(WicketGuiceFilter.class, params); bind(WebApplication.class).to(MyApplication.class);
/* Jersey */ serve("/rest/*").with(GuiceContainer.class, params);}
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Google Guice Ecosystem
Guice Persistence (Hibernate, JPA, DB4O, ...)
protected void configurePersistence() { workAcross(UnitOfWork.TRANSACTION).usingJpa("c4sJpaUnit"); bind(DataSource.class) .toProvider(fromJndi(DataSource.class, "jdbc/c4sDS")) .in(Singleton.class); bind(PlayerRepository.class) .to(JpaPlayerRepository.class) .in(Singleton.class); bind(TeamRepository.class) .to(JpaTeamRepository.class) .in(Singleton.class);}
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Google Guice Ecosystem
Guice Persistence (Dynamic finders)
public interface TeamFinder { @Finder(query="from Team") List<Team> allTeams();}
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Google Guice Ecosystem
Guice Jndi
class SqlModule extends AbstractModule { protected void configure() { bind(UserRepository.class).to(SQLUserRepository.class);bind(DataSource.class)
.toProvider(fromJndi(DataSource.class, "jdbc/h2DB"))
.in(Singleton.class);
}}
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Google Guice Ecosystem
Spring Integration Assisted inject (contextual DI)
interface PaymentFactory {Payment create(Date startDate, Money amount);
}
// DI configurationbind(Payment.class).to(PaymentImpl.class);bind(PaymentFactory.class)
.toProvider(newFactory(PaymentFactory.class, RealPayment.class));
// user codePayement pay = factory.create(today, amount);
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Google Guice Ecosystem
Projects extending Guice capabilities: Peaberry (OSGI) Mycila-testing Guiceyfruit (JSR250, JNDI, ...)
Mycila-guice (JSR250, scopes, module discovery, …)
GuiceBerry [...]
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Google Guice Advantages
Easier to use, test, maintain, refactor, learn Better power to complexity ratio than Spring Advanced DI concepts Favor good design
Immutability, valid objects Thread-safe object
No more java beans constraints Injectable DSL is possible
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Google Guice Advantages
No string identifier No more conflicts No more responsability issue
No more XML ! Static and compile-time verification Plus many things we'll see in details now !
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Dive into Guice
DI configuration (Java-based, DSL & Fluent API)
public final class SqlModule extends AbstractModule { @Override protected void configure() { bind(UserRepository.class).to(SQLUserRepository.class); bind(DataSource.class) .toProvider(fromJndi(DataSource.class,"jdbc/myDB")) .in(Singleton.class); } @Provides Connection connection(DataSource dataSource) throws SQLException { return dataSource.getConnection(); }}
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Dive into Guice
Dependency identification: Key class Supports type literals and raw types Bindings annotations Static type checking Errors caught at compile time, not at runtime
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Dive into Guice
Dependency identification
bind(Properties.class) .annotatedWith(named("app-settings")) .toProvider(fromJndi(Properties.class, "settings/app"));
bind(new TypeLiteral<GenericRepository<Employee>>(){}).to(EmployeeRepository.class);
--------------------------------------------------------------
Key key = Key.get(new TypeLiteral<GenericRepository<Employee>>(){});
GenericRepository<Employee> repo = injector.getInstance(key)
Properties props = injector.getInstance( Key.get(Properties, named("app-settings")))
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Dive into Guice
Bootstrapping
Injector injector = Guice.createInjector(Stage.PRODUCTION, new MyModule(), new JSR250Module(), new SqlModule());
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Dive into Guice
Injection points: Constructors, Fields, Methods
public class BasicTemplateService {
@Inject UserRepository repository private final Settings settings; @Inject public BasicTemplateService(Settings settings) { this.settings = settings; } @Inject @Named("/app/messages/user") void withMessageBundle(ResourceBundle rb) {
[...] }}
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Dive into Guice
AOP support Easy All casual cases
Intercept: Methods Injections
Matchers Classes Methods
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Dive into Guice
AOP support - InterceptorsbindInterceptor(
Matchers.inPackage(getPackage("com.company.repository")), Matchers.annotatedWith(Test.class), new MyAopAllianceInterceptor());
package com.company.repository;class MyRepository { @Test void intercepted() {}}
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Dive into Guice
AOP support – Injection listeners
bindListener(Matchers.any(), new TypeListener() {
public <I> void hear(final TypeLiteral<I> type, final TypeEncounter<I> encounter) {
System.out.println("Meeting type: " + type);
encounter.register(new InjectionListener<I>() {
public void afterInjection(I injectee) { System.out.println("Type has been injected"); } }); }});
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Dive into Guice
Providers Scope widening Delay construction
class CurrentLocale {
@Inject Provider<HttpServletRequest> request;
public Locale get() { [...] }}
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Dive into Guice
Scopes Object lifetime management By default: no scope Allows objects to be garbadged-collected shortly
Misconception about singletons @Singleton IS a scope ! Should only considered when really needed Constructing new objects has no cost in Java
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Dive into Guice
Scopes
bind(JamesBondMessage.class) .in(new ExpiringSingleton(10, SECONDS));
bindScope(Concurrent.class, new ConcurrentSingleton());bind(EnglishDataLoader.class).in(Concurrent.class);bind(FrenchDataLoader.class).in(Concurrent.class);
@Concurrentclass SpanishDataLoader {}
Copyright © 2010 – Mathieu Carbou – Mycila.com - [email protected]
Dive into Guice
And also Module overriding
Modules.override(...).by()... Introspection API
Elements.getElements() binding.acceptVisitor() […]
Parent / Child injectors Private / Public bindings