Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Mark Struberg on JSR299 and Java Context And Dependency Injection

Mark Struberg on JSR299 and Java Context And Dependency Injection

More Decks by Enterprise Java User Group Austria

Other Decks in Technology

Transcript

  1. What is Dependency Injection? • Inversion Of Control pattern used

    for object creation – Hollywood Principle: don't call us, we call you • No more hardcoded dependencies • Ease Object Oriented coding – Most times, the user only uses Interfaces, not real classes MyDbService dbS = new DbServiceForVerySpecialDatabase(specParam); MyDbService dbS = new DbServiceForVerySpecialDatabase(specParam);
  2. Why using Dependendy Injection • Easy to change implementations •

    Encourage Separation of Concerns • Minimise dependencies • Dynamic Object retrieval • Makes Modularisation easy • Simplifies Reusability
  3. How Dependency Injection works • Contextual Instance factory pattern –

    Someone has to trigger the instance creation - even in a DI environment – But the trigger has no control over the Implementation class nor Instance • 'Singletons', Scopes, Contexts, – Each created Contextual Instance is a 'Singleton' in a well specified Context – Session Singleton, ApplicationSingleton, ConversationSingleton, RequestSingleton, ...
  4. XML based DI • Old DI frameworks only had XML

    based dependency configuration mechanisms • Newer frameworks allow to override dependencies in the code with XML configuration
  5. Annotation based DI • Default dependencies via Java Annotations •

    @Resource • @Statefull • @Autowired • @Inject
  6. JSR-299 • Current Name “Contexts and Dependency Injection” (CDI) •

    The spec formerly known as “WebBeans” • Started ~ 2007 • Originally designed for J2EE but also usable for standalone applications • Typesafe Dependency Injection
  7. Injectable Objects • Legal Bean types – Almost all classes

    (nonfinal, nonabstract , default ct or annotated ct) – EJB classes – Objects returned by producer methods – JPA and JMS Resources – Web Service References • META-INF/beans.xml marker file
  8. Lifecycle • Each Context has it's own lifecycle • Everyone

    may code his own Scopes and Context lifecycle • E.g. Builtin @RequestScoped – Created by the doFilter() – Destroyed after the request returns
  9. Special Scopes • @Dependent – Pseudo scope – If injected,

    the Contextual Instance will get/use the Context of it's parent • Qualifier @New (no scope!) – Annotation only valid at injection points! – For each injection, a new instance will be created
  10. Managed Beans • The term Managed Bean means a Java

    Class and all it's rules to create contextual instances of that bean. • Interface Bean<T> • Managed Beans in the spec don't mean Java Beans!
  11. Contextual Instances • The term 'Contextual Instance' means a Java

    instance created with the rules to of the Bean<T> • Contextual Instances usually don't get injected directly!
  12. Contextual References • The term 'Contextual Reference' means a proxy

    for a Contextual Instance. • Proxies will automatically be created for injecting all @NormalScope beans.
  13. Qualifiers • A Qualifier enables the application to lookup a

    specific Implementation at runtime • A class may define multiple Qualifiers • Qualifier connects 'creation info' with InjectionPoints.
  14. Builtin Qualifiers • @Default – Assumed, if no other Qualifier

    (beside @Named) is specified • @New – For each managed bean (and session bean), a second Managed Bean with @New exists. • @Any – Always exists but not for @New beans
  15. Own Qualifiers • Defining the Qualifier annotation @Qualifier @Retention(RUNTIME) @Target({TYPE,

    METHOD, FIELD, PARAMETER}) public @interface Favorit {} @Qualifier @Retention(RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER}) public @interface Favorit {}
  16. A small CDI example • Define a bean @ConversationScoped public

    class Playlist { private @Inject Country ctry; @Inject public setUser(@LoggedIn User usr) {..} public void addTrack(Track track) {..} public List<Track> getTracks() {..} } @ConversationScoped public class Playlist { private @Inject Country ctry; @Inject public setUser(@LoggedIn User usr) {..} public void addTrack(Track track) {..} public List<Track> getTracks() {..} }
  17. A small CDI example • Inject the scoped object @SessionScoped

    public class PlaylistController { @Inject private Playlist pl; public void resortPlaylist() {..} } @SessionScoped public class PlaylistController { @Inject private Playlist pl; public void resortPlaylist() {..} }
  18. Producers • Producer methods or fields if more logic is

    needed to create a Contextual Instance @ConversationScoped public class Playlist { public void addTrack(Track track) {..} public List<Track> getTracks() {..} @Produces @Favorit @RequestScoped public Track getFavTrack() { return new Track(favTitle);} public void dropFavT(@Disposes @Favorit Track t) { dosomecleanup();} } @ConversationScoped public class Playlist { public void addTrack(Track track) {..} public List<Track> getTracks() {..} @Produces @Favorit @RequestScoped public Track getFavTrack() { return new Track(favTitle);} public void dropFavT(@Disposes @Favorit Track t) { dosomecleanup();} }
  19. Defining an InterceptorBindingType • InterceptorBindingTypes are used to uniquely identify

    which Interceptors should be applied to a bean @InterceptorBinding @Retention(RetentionPolicy.RUNTIME) @Target( { ElementType.TYPE, ElementType.METHOD }) public @interface Transactional { @Nonbinding boolean requiresNew() default false; } @InterceptorBinding @Retention(RetentionPolicy.RUNTIME) @Target( { ElementType.TYPE, ElementType.METHOD }) public @interface Transactional { @Nonbinding boolean requiresNew() default false; }
  20. Implementing an Interceptor class @Interceptor @Transactional public class TransactionalInterceptor {

    private @Inject EntityManager em; @AroundInvoke public Object invoke(InvocationContext context) throws Exception { EntityTransaction t =em.getTransaction(); try { if(!t.isActive()) t.begin(); return context.proceed(); } catch(Exception e) { .. rollback and stuff } finally { if(t != null && t.isActive()) t.commit(); } } } @Interceptor @Transactional public class TransactionalInterceptor { private @Inject EntityManager em; @AroundInvoke public Object invoke(InvocationContext context) throws Exception { EntityTransaction t =em.getTransaction(); try { if(!t.isActive()) t.begin(); return context.proceed(); } catch(Exception e) { .. rollback and stuff } finally { if(t != null && t.isActive()) t.commit(); } } }
  21. Using an Interceptor • Class level interceptor • Method level

    interceptor @RequestScoped @Named public class LoginController { private @Current EntityManager em; @Transactional public User checkLogin(String name, String pw) { Query qry = em.createQuery("select..); return qry.getSingleResult(); } @RequestScoped @Named public class LoginController { private @Current EntityManager em; @Transactional public User checkLogin(String name, String pw) { Query qry = em.createQuery("select..); return qry.getSingleResult(); }
  22. Stacking of Interceptors • It's possible to assign more than

    1 Interceptor to the same method • Interceptors have to be enabled in beans.xml or ejb.jar <beans> <interceptors> <class>org.mypkg.TransactionalInterceptor</class> <class>org.mypkg.OtherInterceptor</class> </interceptors> </beans> <beans> <interceptors> <class>org.mypkg.TransactionalInterceptor</class> <class>org.mypkg.OtherInterceptor</class> </interceptors> </beans>
  23. Reusing InterceptorBindings • InterceptorBindings may be used as base for

    other InterceptorBindings public @Secure @Transactional @InterceptorBinding @Retention(RUNTIME) @Target(TYPE) @interface Action {} public @Secure @Transactional @InterceptorBinding @Retention(RUNTIME) @Target(TYPE) @interface Action {}
  24. Decorators • Decorators uses the delegation pattern by proxying complete

    functions • A Decorator may implement business logic @Decorator class TimestampLogger implements Logger { @Inject @Delegate Logger logger; public TimestampLogger(@Decorates Logger logger) { this.logger=logger; } ... } @Decorator class TimestampLogger implements Logger { @Inject @Delegate Logger logger; public TimestampLogger(@Decorates Logger logger) { this.logger=logger; } ... }
  25. Decorator enabling • Decorators have to be enabled in beans.xml

    <beans> <decorators> <class>org.mycompany.myfwk.TimestampLogger</class> <class>org.mycompany.myfwk.IdentityLogger</class> </decorators> </beans> <beans> <decorators> <class>org.mycompany.myfwk.TimestampLogger</class> <class>org.mycompany.myfwk.IdentityLogger</class> </decorators> </beans>
  26. Events • Oberserver/Observable pattern • Event producer • Event consumer

    bitte keine private methods! private @Inject Event<UserLoggedIn> loggedInEvent; loggedInEvent.fire( new UserLoggedIn(user) ); private @Inject Event<UserLoggedIn> loggedInEvent; loggedInEvent.fire( new UserLoggedIn(user) ); public void onLogin(@Observes UserLoggedIn loggedIn) { // do something with loggedIn.getUser() } public void onLogin(@Observes UserLoggedIn loggedIn) { // do something with loggedIn.getUser() }
  27. Stereotypes • Stereotypes are used to combine various attributes and

    roles – A default scope – A default naming scheme – Set of InterceptorBindings – May restrict allowed scopes – May restrict allowed Java Types
  28. Named Beans • Names are mainly used for EL •

    @Named(”myName”) • @Named default name – unqualified class name in camelCase – camelCase producerMethod name (without 'get' or 'is') – camelCase producerField name
  29. XML • JSR-299 currently only defines a few criterias for

    beans.xml • Bean configuration via XML can easily be applied via a portable extension.
  30. Annotation howto • JSR-299 is heavily based on Annotations •

    Defining your own Annotations is daily business • Use of meta-annotations
  31. Technical Concepts • A few internal mechanisms explained a bit

    more detailed • Good point to start looking at OWB: – WebApplicationLifeCycle – WebBeansConfigurationListener
  32. How Dependency Injection works, the big picture • Creating the

    meta information at startup – Classparth Scanning and creating Managed Beans metainformation • Contextual Instance creation at runtime – Based on the Managed Beans, the Context will maintain the instances – ServletContextListener, ServletRequestListener, HttpSessionListener, HttpSessionActivationListener
  33. Proxying • Passivation of non-serializable contextual instances (via it's contextual

    reference) • scope-differences This happens e.g. if a @RequestScoped class gets injected into a @SessionScoped one. • Interceptors, Decorators
  34. Java ServiceLoader • OWB uses dynamic plugin loading via a

    java.util.ServiceLoader • No hardcoded dependencies to 'fat' libraries in the core • Simply drop in a plugin.jar into the classpath
  35. Deployment and Runtime • OWB can run in e.g. the

    following constellations – J2EE container – ServletEngine + EJB microcontainer – ServletEngine + JPA + JSF – ServletEngine + Wicket – Standalone + SWT or Swing – ...
  36. Portable Extensions (JSR-299 SPI) • JSR-299 defines a set of

    SPI APIs to easily extend it's core in a portable fashion • Enables 3rd party libraries to run on any JSR-299 container • Integration via java.util.ServiceLoader and JSR-299 'Container Lifecycle Events'.
  37. Documentation • JSR-330 @Inject • JSR-299 Contexts and Dependency Injection

    • JSR-318 EJB-3.1 (pt2: Interceptor spec) • JSR-250 Common Annotations • Apache OpenWebBeans