Archive

Posts Tagged ‘dependency injection’

Spring vs Dagger

Spring contains configurable factory classes called contexts. These contexts can read description (specified in XML, for example) about
creating objects and satisfying dependecies. Finally, your app can obtain instances of objects from context and start using
them.

Dagger requires you to describe if class requires depdendency to be injected via @Inject annotation (right, that’s intruzive).
If dependency is concrete class, then it may be created in default way, and no more work required for it. Otherwise, if you
have to inject an instance of interface, or you need to create injected class in some specific way, then you use special
factory class and annotate it with @Module annotation and annotate each factory method with @Provides annotation. Finally, you
can generate a factory class for any classes which need injected dependency. This class will have factory methods identified
by return types, and they need all necessary @Modules to be supplied.

Compare:

Spring Dagger
Classes which don’t have dependencies, but on which other classes depend Describe them in XML, init them via values If they require some specific way to create them, then you need a @Provides factory method in some @Module class. Otherwize they will be created automatically
Classes which have dependencies, and on which other classes depend Describe them in XML, inject them with references to other beans If they require some specific way to create them, then you need a @Provides factory method in some @Module class. Otherwize they will be created automatically. In both cases their dependencies will be satisfied
Classes which have dependencies, but which are not needed to be injected See previous These classes will be needed externally, so you need to generate factory methods for them
A way to make it work Load description, call refresh(), obtain objects which you need. All beans will be created and injected in each other in a way which you describe Invoke generated factory methods for objects which you need and supply specific @Module factories to customize the result
Advertisements

Container approach in Java. Part 2: instances (version 2.0)

June 2, 2008 Leave a comment

In a previous article I’ve defined a component/container architecture and explained the reasons why such architecture is used. This article will cover real examples of containers which are known to me. in historical perspective.

Servlet containers

Earliest containers known to me are servlet containers. These are typical IoC containers, used on servers communicating asymmetric request/response protocols, like HTTP. This allows applying IoC approach to handling of protocol logic: servlets must implement “Servlet” interface containing method “service()”. This method is invoked by container for each incoming request. For HTTP, IoC principle also applies to creation and sending of responses. 

Interface “Servlet” also contains methods “init()” and “destroy()”, which are used for lifecycle management. Method “init()” also used for “context” injection. From this “context” a servlet can extract references to all components it depends on. 

Servlets are developed according to special convention, so they are collections of classes and XML descriptor.

Well-known examples of servlet containers are Apache Tomcat, Jetty, Resin.

EJB containers

EJB spec is also quite old. It is a “generic” component/container architecture for complex data-processing logic used inn enterprize IT systems. Curioulsy enough, it was developed as distributed architecture, meaning that each component will be located on dedicated machine, and container will provide inter-component communication. IoC principle is applied to lifecycle and persistence. Dependencies are resolved using lookup (in JNDI facility), however binding in JNDI is done automatically.

Later EJB spec changed to support “local” access between components. Anyway, it was and still criticised for being complex and slow, and many other frameworks emerged to fix its flaws.

Well-known examples of EJB containers are: Glassfish, Apache OpenEJB, JBoss, JOnAs, Bea WebLogic, IBM websphere, and lots of others.

Microcontainers

Microcontainers are “generic” component containers focusing only on local access and providing just lifecycle and late binding. All other features could be realized “on top” of container, by implementing them as a components. 

Apache Avalon was first known to me attempt to build “lightweight” container. Later its developers divided, but they have tried to support common framework for containers. This framework follows “interface injection” approach, which means that dependency on something is declared by implementing certain interface, and the same interface is used for injecting this dependency. Thus, Avalon framework contains lots of interfaces, for example for lifecycle, logging, configuration. However, injection is used only for dependencies which are part of framework. For resolving other dependencies there is also lookup facility.

Apache Hivemind is another minimalistic container, with IoC principles applied to lifecycle, configuration and automatic dependency injection, although lookup is also supported. This container is best classified as “declarative de-centralized”. It uses a special format for its components (code + XML-based descriptor). Dependency injection is supported through components following a naming convention.

Other examples of microcontainers are: Picocontainer, Butterfly, Guice.

Spring

Spring framework is a set of components aimed to be simple, lightweight and cheap alternatives to  all parts of JEE. As a a replacement of EJB it provides a much simpler IoC container. However, this container is often used not just for binding user components together, but also for binding them with system components. This was new at the time, because JEE application servers didn’t allow to customize the “system” part. Spring container is not just “business logic integration point”, but whole “application integration point”.

IoC principle in Spring could be applied to lots of concerns, including lifecycle, dependency resolving via injection, configuration. However, usage of IoC is not mandatory and could be avoided, but it will make whole arcitecture less consistent.

One interesting application of IoC principle used Spring is “aspect-oriented programming”: a container “wraps” modules with its own “proxy”, and injects this proxy into dependent modules. This “proxy” allows inserting some functionality before invocation and after invocation, so some component can affect interaction between two other modules without modifying them.

Spring is very popular, because it provides a large base for building custom server-side software, either complex or simple.

 JEE application servers

After success of Spring vendors of many JEE application servers understood that their products should be more customizable, so those servers were re-designed as microcontainers. Apache Geronimo is a microcontainer allows deployment of components called “GBeans”. JBoss also implements microcontainer architecture. Glassfish and JOnAs stated that they will move to OSGi.

Apache Geronimo is an example of “embedded container” architecture: EJB container (OpenEJB) is itself a component in another container (Geronimo microcontainer).

OSGi

The distinguishing feature of OSGi framework is a complex classloading. This allows “hot upgrade” through dynamic loading and unloading of classes, and other interesting capabilities. IoC principle is applied only to lifecycle. As a separate component there is a “service facility” which could be used for basic dependency lookup, and also allows subscription to notifications about lifecycle events in other services. There is also component for dependency injection called “Service Binder” based on XML descriptors.

There are several implementations of OSGi framework, including Eclipse Equinox and Apache Felix.

JSLEE

JSLEE is another non-generic component architecture for Java. It is similar to EJB in a way in which IoC principle is applied to persistence and lifecycle. JSLEE includes scalable event-delivery facility, and IoC principle is appled to some aspects of interfaction between components and event-delivery facility. could be viewed as a combination of Servlet Container and EJB container. Dependencies are resolved using lookup (in JNDI).

Container approach in Java (version 2.3)

May 28, 2008 Leave a comment

This article discusses reasons for existence of software flavor called “container” with emphasis on Java. For a long time I was wandering if technologies like Spring, Apache HiveMind, Apache Fortress, OSGi are really useful. And here is the story what I’ve learned. Please be warned that I never used any of those technologies myself! I’m not an expert in any sense, and all this stuff I write based only on reading documentation. This first part is theoretical, and second part contains real-life examples.

Software modularity.

Software modularity is known for a long time. It was invented as approach to software analysis and design. Whole software is decomposed into pieces, and each piece implements certain functionality. The reason for modularity is to simplify analysis by controlling levels of detail. There are basically two means of expressing modularization: referring to something compound through a name (e.g. modules, packages, classes, procedures, functions), and preventing something from getting outside of context (e.g. local variables). Another term for levels of detail is called “levels of abstraction”, since detail is complementary term to abstraction. The main point I want to emphasize is that modularization is logical because it is meant to bring logical order by keeping many things local and dependencies explicit.

Next level of modularity is called “source modularity”, which means that source code is divided into parts representing logical modules. Java is remarkable in expressing logical modularization strictly through source. An accidental benefit of source modularity is a possibility of division of work, if analysis precedes implementation.

Another accidental side effect of modularity was the ability to re-use modules in several programs. Whole program is unlikely suitable for more than one purpose. However, a set of logical “blocks” which human’s mind uses is limited, so program analysts often use same concepts while designing different programs, leading to re-use of code which implements those concepts. Programmers started tearing programs apart. Some programming languages are proud of not just expressing modularization, but enforcing it. Some people started to write incomplete programs called “libraries” with idea that others will use them. Analysis of a program now includes a research of which parts could be re-used from other programs.

For me, most straightforward way to re-use existing module is by including its source code into program’s source code. However, if program is compiled, then source code of the module is compiled too. Because main program is changed much more frequently then module, and compilation takes time, so separate compilation was invented and new “linking” stage assembles modules together. An additional benefit of linking is that it very well expresses dependencies between coarse-grained modules.

It doesn’t matter if modules are assembled at source level or at linking level, the result will be a solid program. Compilation and linking are one-way processes, so it is not possible to remove a module from a program. In other words, module itself is a prototype which is “cloned” with no cost, and each clone is “fused” into a program instance forever. Java is slightly different in this way, because it doesn’t have linking stage, JAR files just look solid.

Software modularity as a development practice nowadays is used in any non-trivial software. Yes, it could be misused, but amount of experience in this area today allows developers to quickly learn how to use it in right way.

Struggle for de-coupling and implementation lookup.

Next thing which software developers have noticed is that modules could be replaceable. Several modules can have same interface and differ in implementation, performance, price and license, so module user has a choice. Module users were so excited about “flexibility” their programs suddenly achieved, that they agreed to abandon more straightforward interfaces in favor of “standard” ones. Biggest selling point of most Java technologies is that customer will not depend on single vendor.

Programmers started inventing interfaces and using modules only through interfaces. So, dependencies have not gone, they have just changed. First, instead of depending on particular module, program now depends on interface. And second, a complete program consists not of interfaces, but of particular modules. So dependency on implementation is still introduced, it just happens later. With languages like C a dependency on real module is introduced at linking stage. Unfortunatelly for Java, dependency is specified in the source code, at place where instance of implementation is created. So, for Java “late binding” always means “run-time binding”.

I had this in my Java programs. Whole program used module through interface, and the single place where my program depended on particular implementation was a place where I called “new InterfaceImpl();”. I had extracted this expression into factory method, and replaced “new” with creation through reflection, taking class name from system property. I was very proud of myself, because from this time this code was “flexible”. I have pulled out this dependency into script which launched the program. Such approach for resolving the dependency is called “implementation lookup”, because class name was obtained by searching in some single-instance location using specified key.

Obvious advantage of “late binding” is “deployment flexibility”, which means that you don’t need to re-compile your user module when you want to use another implementation. This could be useful, because some people just afraid of programming, other people don’t want to download source code. However, other people prefer pure programming solution. So, this concern is purely human one. Another advantage, which is more important to developers, is that there is no dependency on particular implementation at compile time, so compiler enforces de-coupling. There are also disadvantages: code became more complex and much less straightforward. If I have specified an incorrect implementation, I would get a runtime error. And instead of single direct dependency it now has two dependencies: on interface and on binding policy.

Implementation injection and Inversion of control

Programmers who value compiler-enforced interface-based programming and don’t value a flexibility of deployment have invented another programming technique called “implementation injection”. Factory method is moved in separate module (“factory module”), and user module receives an instance of interface from this factory module through setter method. Thus, by multiplying amount of modules and complicating a compilation process a programmer will have compiler-enforced flexibility and still pure programming solution.

Implementation injection is a particular case of more general programming practice called “inversion of control”. Inversion of control is a process of changing your module in the way so it is no longer executes some precise action to obtain a result (e.g. creating instance) , but instead it just exposes some means of obtaining a result (like setter method). In other words, Inversion of control is a process of turning an active component into passive one. Another colorful name for this approach is called “Hollywood principle (don’t call us, we’ll call you)”.

Inversion of control is quite general principle. Another particular implementation of it is called “event-driven programming”, which means that instead of having event-polling loop in each component there is a one global event-polling and dispatching loop. Applying inversion of control makes some code more flexible, but less capable (because now it does less), so it should be done only when extracting common behaviour from several places for sharing and unification.

Speaking of complexity, injection and lookup are similar. The only difference is that lookup is more imperative and injection is more structural.

Management containers

Sometimes you need to execute several totally independent programs in the same runtime environment, for example, in the same JVM. This could be useful on equipment with limited memory, so common class files will be shared. Most straightforward way would be to write simple Launcher, which will create and start all co-programs. Programmers which prefer to stick with single language will write Launcher in the same language as co-programs (Java). But if a set of co-programs to be run changes, then updating such class means full circle of editing, compiling, deploying. There are approaches with better “deployment flexibility”, such as:

  • launcher with shell for interactive specifications of co-programs
  • launcher which reads configuration or script in some special language
  • launcher which automatically discovers co-programs. For this case, modules should follow some common convention, so launcher could discover and use them. This is called “plug-in” concept: “if something exists, then it works, if you don’t want it working – remove it”.

Launcher is a simplest form of “management container”, because the only thing it controls is if a co-program will be started or not. Being able to manage co-programs from single point seems good to lots of people, so number of concerns to be managed have grown far beyond lifecycle.

Each co-program could be managed differently. To unify and automate management tasks most containers introduce “policies” which co-programs must follow. For example, they must implement certain interface used by container for lifecycle. So, making a co-program “manageable” often means inversion of control.

For example of lifecycle-management container, you can imagine window which shows several applets, with controls allowing to start/stop them independently.

Two benefits of container architecture (single management point for users, and having common code in single place for developers) really matter only if number of co-program is significant (for me, more then 10). For just a couple of co-programs, it is not worth to bother.

Component containers

We are coming to most important point in whole story. Somehow developers decided that modules of which co-programs consist should be separate co-programs in container. Main reason for that is an ability of runtime sharing of code and associated resources (for example, one window frame, one HTTP stack, one event-polling thread). As a result, co-programs are no longer complete, they use other co-programs. Let’s call such co-programs a “components”, since they are parts from which a complete solution is assembled.

To implement sharing, a used component should be created by container (that’s why it is a separate component), and user modules should obtain a shared instance.

One approach for user modules to obtain shared instance is a “lookup”: a reference to shared instance is bound to some “name” (or “key”) in lookup facility, and user modules can obtain an instance using this “name” as a parameter. Since lookup could be done at any moment after user module creation, it is important to create and bind used module before creating user module.

Binding of shared module to name in lookup facility could be realized in different ways:

  • “Imperative” way. Binding is done in the code of used module.
  • “Declarative” way. Used module declares that it provides some service, and binding is done automatically by container after creation of used module, using service name as key.
  • “Container-managed” way. Binding is done by container, either interactively, or through configuration.

Second and third approaches are cases of inversion of control, because common binding code is being moved from components into container. Applying inversion of control to user module turns “instance lookup” into “instance injection”: user module provides a setter method though which it will obtain a reference to used module. Like binding, injection could be realized in “declarative” per-component way and in “container-managed” way.

Thus we got a “component container”, which is a special flavor of management container capable of performing “wiring up” or “linking” components into complete application.

Dependency management in containers

You probably already noticed that the same “lookup” and “injection” approaches are used for two different purposes: for de-coupling of user code from implementation and for discovery of shared instance. Both tasks are cases of general task called “runtime dependency resolving” or “late binding”. Accordingly, “lookup” and “injection” are general solutions to this task. For component containers this means that existing linking facility could be also used for removing “hard” dependencies between components and replacing them with “managed” dependencies.

For simplicity, and because some components simultaneously play roles both of user of one interface and of implementation of another interface (so called “layers”), containers usually have uniform approach for dependency management. Here are typical cases.

“Imperative” container is not far beyond lifecycle manager plus bind/lookup facility. Both binding and lookup is hidden in code, so dependencies are not known to container. If “dependency could not be found” error occurs during startup, then container admin must check documentation and find out if he has missed some component or he should change startup order. In other words, management is simple yet not flexible, and troubleshooting is hard. However, this approach appeals to developers who prefer use single language for everything and do stuff programmatically. Components depend on container (lifecycle and bind/lookup facility) and on interface naming policy.

“Declarative de-centralized” container with dependency injection is a most widespread approach. Separate declaration is explicit, which requires special language for it (e.g. XML, annotations). This is a plug-in approach with container resolving dependencies automatically and printing helpful messages in case  of errors. Start order is determined automatically by reversing dependency order. Components depend on container (lifecycle), interface naming policy (because interface must have same name declared in implementations and users) and dependency-declaration language. In other words, components are complex, container management is simple yet not flexible.

“Flexible centralized” container. Components are “plain old java objects” (“POJOs”), which themselves have no dependencies on container and on interface name. Container has an interpreter of some language (declarative, like XML or imperative, like BeanShell) for lifecycle management and wiring up components. This is a centralized and very flexible, but more complex management.

Container wars

Flexible containers are transparent for components. However, they require some manual work for wiring up components, and in this sense they are just another way of programming.

Other approaches imply that components are designed for particular container. There were attempts to de-couple components from particular containers by designing a common standard for containers (“container framework”). Examples of such efforts are: EJB, Apache Avalon, OSGi. Neither framework prevailed, so developers have following options:

  • Stick with single container
  • Support several containers (usually not many) directly in cost of harder maintenance
  • Use “wrapper” component for each container

There are still “container wars”. Some containers (like OSGi or JSLEE) have some distinguishing features which they use as selling points. Other containers try to be “generic” and attempting to attract users by supporting many dependency-management approaches and having more ready-to-use components packaged. More about that will be explained in second part.

Criticism

We already mentioned that containers provide some benefits, like uniform management, runtime module sharing and implementation replaceability. However, it comes with cost of harder development and maintenance: architecture is more complex, code is less straightforward, “second” language and possibility of runtime errors.

My main criticism to containers comes from the fact that drawbacks are never mentioned by container vendors. They promote their products and push users to create over-engineered systems.

I believe that runtime errors are bad and should be avoided where possible. By “avoided” I mean “checked at compile stage instead”. In this sense, a claim that “containers help by enforcing modularity” is absolutely false.

To promote containers, their vendors claim that it will become possible to do “rapid application assembly from known components” (taken from azuki site). However, an amount of ready components is very small (in my opinion, only Spring has some). I believe that containers are appealing to non-programmers who think that they can avoid programming. But if your application is just an assembly of “known” components, what gives you advantage over competitors? I never believed in just “assembly”, something always should be written in code.

Then why containers are used ?

In my opinion, container approach is used mostly in server software. There are several reasons for that. Servers often host several independent “services” (co-programs). Server software clearly distinguishes between “service users” and “administrators” who manage from single point. Services often share common modules which consume system resources (threads, memory pools, database connections). For server-side software there is a market for “system-level” components (message queues, network stacks, object-relational mapping, tracing/logging) providing one of standard JEE APIs.  So, you can see that all requirements which led to creation of containers are often applicable for server software.

Conclusion

To sum up all said, here are short advices.

  • Avoid containers where possible.
  • Don’t listen to their propaganda. They want to complicate your life, because they need to justify their worthless efforts to buil something from nothing.
  • If forced by circumstances, evaluate something existing
  • Be prepared to harder maintenance

Coming soon

A second part, which will try to map theory on real life by checking which of existing containers use which approach.

Useful links:

  • Apache container 2.0 paper is a good overall presentation. However, I don’t agree with author about definition of “Inversion of control”.
  • Great article of Martin Fowler supposes that you already believe in importance of using de-coupled components and discusses in depth topics of dependency injection and dependency lookup without investigating reasons of emergence of containers