PicoContainerPicoContainer
Presented by:Presented by:
Jim O’HaraJim O’Hara
Ed KausmeyerEd Kausmeyer
Jingming ZhangJingming Zhang
Lightweight ContainersLightweight Containers Attempts to build alternatives to the Attempts to build alternatives to the
mainstream J2EE technologiesmainstream J2EE technologies A common obstacle:A common obstacle:
• How to wire together different elementsHow to wire together different elements• How do you fit together this web controller How do you fit together this web controller
architecture with that database interface backing architecture with that database interface backing when they were built by different teams with little when they were built by different teams with little knowledge of each other?knowledge of each other?
Lightweight ContainersLightweight Containers• Frameworks that have taken a stab at this problem Frameworks that have taken a stab at this problem
and are branching out to provide a general and are branching out to provide a general capability to assemble components from different capability to assemble components from different layerslayers
• PicoContainer, SpringPicoContainer, Spring
Overview of Overview of PicoContainerPicoContainer
Lightweight and highly embeddable Lightweight and highly embeddable container for components that honor container for components that honor Dependency InjectionDependency Injection
Small, simple container for arbitrary Small, simple container for arbitrary components/servicescomponents/services
Originally implemented in JavaOriginally implemented in Java• Now available for other platforms and Now available for other platforms and
languages also (including C# and Ruby)languages also (including C# and Ruby)• http://http://
opensource.thoughtworks.com/projects/picopensource.thoughtworks.com/projects/picocontainer.jspocontainer.jsp
Overview of Overview of PicoContainerPicoContainer
Not a replacement for a J2EE Not a replacement for a J2EE containercontainer• Does not offer any infrastructure Does not offer any infrastructure
services out of the boxservices out of the box Can use the monitor support of Can use the monitor support of
PicoContainer to react on internal PicoContainer to react on internal events e.g. by loggingevents e.g. by logging
Benefits of PicoContainerBenefits of PicoContainer
Embeddable inside other applicationsEmbeddable inside other applications• 50k jar that has no external dependencies 50k jar that has no external dependencies
except JDK 1.3except JDK 1.3 Compact in sizeCompact in size Non-intrusiveNon-intrusive
• Components don't have to implement any Components don't have to implement any funny APIs and can be POJOsfunny APIs and can be POJOs
Very extensible design: Enables Very extensible design: Enables virtually any form of extensions to the virtually any form of extensions to the corecore
Benefits of PicoContainerBenefits of PicoContainer
Modularize how dependencies Modularize how dependencies between parts of an application between parts of an application are laced upare laced up• Common to have dependencies Common to have dependencies
scattered all overscattered all over• Can be valuable for large projectsCan be valuable for large projects
Improve how components are Improve how components are configured in an applicationconfigured in an application
Improve the testability of codeImprove the testability of code
Dependency InjectionDependency Injection A way of instantiating components and lacing A way of instantiating components and lacing
them together with other dependent them together with other dependent componentscomponents
Main idea: Have a separate object, an Main idea: Have a separate object, an assembler, that populates a field in a class to assembler, that populates a field in a class to be created with an appropriate be created with an appropriate implementation for an interface that class implementation for an interface that class needs, resulting in a dependencyneeds, resulting in a dependency• That is, a component user specifies the interfaces That is, a component user specifies the interfaces
it needs, and the implementations of the required it needs, and the implementations of the required components are provided at creation timecomponents are provided at creation time
• Decouple the caller of the component from the Decouple the caller of the component from the implementationimplementation
Types of Dependency Types of Dependency InjectionInjection
Constructor Dependency Injection Constructor Dependency Injection (CDI): an object gets all its (CDI): an object gets all its dependencies via the constructordependencies via the constructor
Setter Dependency Injection (SDI): Setter Dependency Injection (SDI): the container or embedder hands the container or embedder hands dependencies to a component via dependencies to a component via setter methods after instantiationsetter methods after instantiation
Dependency Injection In Dependency Injection In PicoContainerPicoContainer
PicoContainer supports CDI and SDIPicoContainer supports CDI and SDI PicoContainer identifies dependencies by PicoContainer identifies dependencies by
looking at the constructors of registered looking at the constructors of registered classes (CDI)classes (CDI)
PicoContainer can be thought of as a generic PicoContainer can be thought of as a generic factory that can be configured dynamicallyfactory that can be configured dynamically
PicoContainer is able to instantiate a PicoContainer is able to instantiate a complex graph of several interdependent complex graph of several interdependent objectsobjects
Components In Components In PicoContainerPicoContainer
Components are implemented as ordinary Components are implemented as ordinary Java classes and do not typically have to Java classes and do not typically have to rely on any PicoContainer APIsrely on any PicoContainer APIs
The components are assembled in a The components are assembled in a container using a simple Java API that is container using a simple Java API that is similar to an intelligent hash map utilizing similar to an intelligent hash map utilizing the type of its valuesthe type of its values
This allows PicoContainer to instantiate This allows PicoContainer to instantiate arbitrary objectsarbitrary objects• You can put java.lang.Class objects in and get You can put java.lang.Class objects in and get
object instances backobject instances back
Components In Components In PicoContainerPicoContainer
A component user specifies the interfaces A component user specifies the interfaces it needs, and PicoContainer provides the it needs, and PicoContainer provides the implementations of the required implementations of the required components at creation timecomponents at creation time• This is what Dependency Injection is all aboutThis is what Dependency Injection is all about
A component can be used in the A component can be used in the PicoContainer without importing or PicoContainer without importing or extending any interfaces or defined in the extending any interfaces or defined in the PicoContainer assemblyPicoContainer assembly
Demonstration: Juicer Demonstration: Juicer ExampleExample
Example taken from Example taken from http://www.picocontainer.org/Five+minute+introductionhttp://www.picocontainer.org/Five+minute+introduction
Container HierarchiesContainer Hierarchies
Containers provide a powerful Containers provide a powerful alternative to the singleton antipatternalternative to the singleton antipattern• The singleton pattern is static and global; The singleton pattern is static and global;
it won't allow more than one instance and it won't allow more than one instance and is visible from anywhereis visible from anywhere
Containers serve as singleton-like Containers serve as singleton-like objects that provide fine-grained objects that provide fine-grained control over the visibility scope of the control over the visibility scope of the instanceinstance
Container HierarchiesContainer Hierarchies
A container (and its A container (and its registered components) registered components) can get access to can get access to components registered in a components registered in a parent container, but not parent container, but not vice-versavice-versa
//Container Hierarchy Example//Container Hierarchy Example// Create x hierarchy of containers// Create x hierarchy of containersMutablePicoContainer x = new MutablePicoContainer x = new DefaultPicoContainer();DefaultPicoContainer();
MutablePicoContainer y = new MutablePicoContainer y = new DefaultPicoContainer(x);DefaultPicoContainer(x);
MutablePicoContainer z = new MutablePicoContainer z = new DefaultPicoContainer(x);DefaultPicoContainer(x);
// Assemble components// Assemble componentsx.registerComponentImplementation(Apple.class);x.registerComponentImplementation(Apple.class);y.registerComponentImplementation(Juicer.class);y.registerComponentImplementation(Juicer.class);z.registerComponentImplementation(Peeler.class);z.registerComponentImplementation(Peeler.class);
//Container Hierarchy Example Continued//Container Hierarchy Example Continued// Instantiate components// Instantiate componentsPeeler peeler = Peeler peeler = (Peeler)z.getComponentInstance(Peeler.class);(Peeler)z.getComponentInstance(Peeler.class);
// WON'T WORK! peeler will be null// WON'T WORK! peeler will be nullpeeler = (Peeler) peeler = (Peeler) x.getComponentInstance(Peeler.class);x.getComponentInstance(Peeler.class);
// WON'T WORK! This will throw an exception// WON'T WORK! This will throw an exceptionJuicer juicer = Juicer juicer = (Juicer)y.getComponentInstance(Juicer.class);(Juicer)y.getComponentInstance(Juicer.class);
First line will work fine; First line will work fine; zz will be able to will be able to resolve the dependencies for resolve the dependencies for PeelerPeeler (which is (which is AppleApple) from the parent ) from the parent containercontainer
Second line will return null, as Second line will return null, as xx can't can't see see PeelerPeeler
Third line will throw an exception, since Third line will throw an exception, since JuicerJuicer's dependency to 's dependency to PeelerPeeler can't be can't be satisfied (satisfied (zz can't be seen by can't be seen by yy))
LifecycleLifecycle
One third of Inversion of ControlOne third of Inversion of Control• Inversion of Control = dependency Inversion of Control = dependency
resolution + configuration + lifecycleresolution + configuration + lifecycle Concerns the post composition life of Concerns the post composition life of
a componenta component Most commonly encountered Most commonly encountered
lifecycle concepts: start, stop, lifecycle concepts: start, stop, disposedispose
LifecycleLifecycle
The lifecycle of components are The lifecycle of components are easy to manage in PicoContainereasy to manage in PicoContainer
Lifecycle callbacks are supported Lifecycle callbacks are supported by implementing the lifecycle by implementing the lifecycle interfacesinterfaces
PicoContainer provides two simple PicoContainer provides two simple interfaces for lifecycle: interfaces for lifecycle: StartableStartable and and DisposableDisposable
A lifecycle can be extended or A lifecycle can be extended or totally customizedtotally customized
LifecycleLifecycle
If a set of classes implement If a set of classes implement StartableStartable, the lifecycle of all the , the lifecycle of all the objects can be controlled with objects can be controlled with method calls on the containermethod calls on the container
The container will figure out the The container will figure out the correct order of invocation of correct order of invocation of start()start() or or stop()stop() for all the objects for all the objects it managesit manages
LifecycleLifecycle
Calling Calling start()start() on the container will call on the container will call stop()stop() on all container-managed objects in on all container-managed objects in the order of their instantiationthe order of their instantiation
This means starting with the ones that have This means starting with the ones that have no dependencies, and ending with the ones no dependencies, and ending with the ones that have dependencies on othersthat have dependencies on others
LifecycleLifecycle
Calling Calling start()start() on a container with child on a container with child containers will start all the containers in a containers will start all the containers in a breadth-first order, starting with itselfbreadth-first order, starting with itself
Likewise, calling Likewise, calling stop()stop() will call will call stop()stop() on all on all containers in the hierarchy in a depth-first ordercontainers in the hierarchy in a depth-first order
LifecycleLifecycle
In order for a hierarchy-aware lifecycle In order for a hierarchy-aware lifecycle to work, child containers must be to work, child containers must be registered as components in their registered as components in their parent containerparent container• Just creating a container with another one Just creating a container with another one
as a parent will as a parent will notnot cause the parent cause the parent container to know about the child container to know about the child containercontainer
Calling lifecycle methods on a child Calling lifecycle methods on a child container will container will notnot propagate the propagate the lifecycle to its parent containerlifecycle to its parent container
Lifecycle Example: A Direct Lifecycle Example: A Direct ApproachApproach
MutablePicoContainer parent = new MutablePicoContainer parent = new DefaultPicoContainer();DefaultPicoContainer();
MutablePicoContainer child = new MutablePicoContainer child = new DefaultPicoContainer(parent);DefaultPicoContainer(parent);
// We must let the parent container know// We must let the parent container know
// about the child container.// about the child container.
parent.registerComponentInstance(child);parent.registerComponentInstance(child);
// This will start the parent, which// This will start the parent, which
// will start the child.// will start the child.
parent.start();parent.start();
Lifecycle Example: An Lifecycle Example: An Indirect ApproachIndirect Approach
MutablePicoContainer parent = new MutablePicoContainer parent = new DefaultPicoContainer();DefaultPicoContainer();
parent.registerComponentImplementation("child", parent.registerComponentImplementation("child", DefaultPicoContainer);DefaultPicoContainer);
// This will instantiate the child container// This will instantiate the child container// passing the parent (itself) as parent// passing the parent (itself) as parent// container.// container.// No need to register the child in the parent// No need to register the child in the parent// here.// here.MutablePicoContainer child = MutablePicoContainer child = (MutablePicoContainer) (MutablePicoContainer) parent.getComponentInstance("child"); parent.getComponentInstance("child");
// This will start the parent, which will start// This will start the parent, which will start// the child.// the child.parent.start();parent.start();
NanoContainer, for expanding NanoContainer, for expanding capabilitiescapabilities
Builds on top of PicoContainer the Builds on top of PicoContainer the support for several scripting support for several scripting metalanguages (XML, Groovy, Bsh, metalanguages (XML, Groovy, Bsh, Javascript and Jython), AOP, Web Javascript and Jython), AOP, Web frameworks (Struts and WebWork), frameworks (Struts and WebWork), SOAP, JMX, and much moreSOAP, JMX, and much more
ExampleExample
import org.picocontainer.*;import org.picocontainer.*; import org.picocontainer.defaults.*;import org.picocontainer.defaults.*;
public class DITest{public class DITest{ public static void main(String[] args){public static void main(String[] args){
//Two ways to test Inversion of Control in pico container//Two ways to test Inversion of Control in pico container //Both use Dependency Injection Patten.//Both use Dependency Injection Patten.
//Constructor Injection with PicoContainer indirectly//Constructor Injection with PicoContainer indirectly System.out.println("Constructor Injection indirectly:");System.out.println("Constructor Injection indirectly:"); MyMovieFinder mmf = new MyMovieFinder();MyMovieFinder mmf = new MyMovieFinder(); mmf.testWithPico();mmf.testWithPico();
//Constructor Injection with PicoContainer directly//Constructor Injection with PicoContainer directly System.out.println("constructor Injection directly:");System.out.println("constructor Injection directly:"); MutablePicoContainer pico = new DefaultPicoContainer();MutablePicoContainer pico = new DefaultPicoContainer(); pico.registerComponentImplementation(MovieFinderImpl.class);pico.registerComponentImplementation(MovieFinderImpl.class); pico.registerComponentImplementation(MovieLister.class);pico.registerComponentImplementation(MovieLister.class); MovieLister lister = (MovieLister) MovieLister lister = (MovieLister)
pico.getComponentInstance(MovieLister.class);pico.getComponentInstance(MovieLister.class); lister.listFinder();lister.listFinder();
//Constructing Object without using PicoContainer//Constructing Object without using PicoContainer System.out.println("Construct Object without PicoContainer:");System.out.println("Construct Object without PicoContainer:"); //String title = "Once Upon a Time in the West";//String title = "Once Upon a Time in the West"; MovieFinder finder = new MovieFinderImpl();MovieFinder finder = new MovieFinderImpl(); lister = new MovieLister(finder);lister = new MovieLister(finder); lister.listFinder();lister.listFinder();
System.exit(0);System.exit(0); }} }}
Output of Executing DITest Output of Executing DITest ClassClass
F:\SE510>java DITestF:\SE510>java DITest
Constructor Injection indirectly:Constructor Injection indirectly:
MovieFinder was listed by MovieFinder was listed by MovieLister@1cfb549MovieLister@1cfb549
constructor Injection directly:constructor Injection directly:
MovieFinder was listed by MovieFinder was listed by MovieLister@186d4c1MovieLister@186d4c1
Construct Object without PicoContainer:Construct Object without PicoContainer:
MovieFinder was listed by MovieFinder was listed by MovieLister@f9f9d8MovieLister@f9f9d8
ReferencesReferences Page with several links for information about PicoContainerPage with several links for information about PicoContainer
http://http://www.picocontainer.orgwww.picocontainer.org// One-minute description: provides an overview of PicoContainer One-minute description: provides an overview of PicoContainer
and lists some of its benefitsand lists some of its benefitshttp://http://www.picocontainer.org/One+minute+descriptionwww.picocontainer.org/One+minute+description
Two minute tutorial: provides code snippets that serve as a Two minute tutorial: provides code snippets that serve as a introduction to PicoContainerintroduction to PicoContainerhttp://http://www.picocontainer.org/Two+minute+tutorialwww.picocontainer.org/Two+minute+tutorial
Five minute introduction: provides code snippets that serve as Five minute introduction: provides code snippets that serve as a introduction to PicoContainer and explains the concepts of a introduction to PicoContainer and explains the concepts of container hierarchies and lifecyclecontainer hierarchies and lifecyclehttp://http://www.picocontainer.org/Five+minute+introductionwww.picocontainer.org/Five+minute+introduction
Paper: Inversion of Control Containers and the Dependency Paper: Inversion of Control Containers and the Dependency Injection patternInjection patternhttp://www.martinfowler.com/articles/injection.htmlhttp://www.martinfowler.com/articles/injection.html
Constructor Dependency Injection with PicoContainer, a post-Constructor Dependency Injection with PicoContainer, a post-J2EE Nirvana: Explains Inversion of Control (IoC) and J2EE Nirvana: Explains Inversion of Control (IoC) and Constructor Dependency Injection (CDI) in PicoContainer and Constructor Dependency Injection (CDI) in PicoContainer and NanoContainerNanoContainerhttp://conferences.oreillynet.com/cs/os2004/view/e_sess/5294http://conferences.oreillynet.com/cs/os2004/view/e_sess/5294