LookupAndSpring

From APIDesign

(Difference between revisions)
Jump to: navigation, search
(Double Injection)
Current revision (05:50, 22 March 2015) (edit) (undo)
(Double Injection)
 
(8 intermediate revisions not shown.)
Line 1: Line 1:
-
An important subset of [[Spring]] is said to be an example of [[Dependency Injection]]. [[Lookup]] library, originally invented by [[NetBeans]] project used to be said to do similar kind of [[injection]]. From a distance they seem to server similar purpose, yet after closer look they are both different. Each of them is optimized for slightly different task. Could they strengthen themselves if they worked together? That it what we'll find soon out.
+
An important subset of [[Spring]] is said to be an example of [[Dependency Injection]]. [[Lookup]] library, originally invented by [[NetBeans]] project seems to do similar kind of [[injection]]. Do these two [[API]]s serve similar purpose or are they both quite different? Each of them is optimized for slightly different task. Could they strengthen themselves if they worked together? That it what we'll find soon out.
Imagine there is a GUI application to play the [[wikipedia::Anagrams|Anagrams Game]]. We have a base UI class called ''Anagrams'' that needs two additional interfaces to be injected. In [[Spring]] world, this can be done with a two arguments constructor:
Imagine there is a GUI application to play the [[wikipedia::Anagrams|Anagrams Game]]. We have a base UI class called ''Anagrams'' that needs two additional interfaces to be injected. In [[Spring]] world, this can be done with a two arguments constructor:
Line 13: Line 13:
=== Java Extension Mechanism ===
=== Java Extension Mechanism ===
-
To open door and allow others to do late bindng [[injection|inject]] various implementations of ''WordLibrary'' and ''Scrambler'' classes and be discovered using [[ServiceLoader|Java Extension Mechanism]] as abstracted by [[Lookup]]. Just compose your own XML context with the [[ServiceLoader|Java Extension]] one in your main method:
+
To open door and allow others to do late [[injection]] to bind various implementations of ''WordLibrary'' and ''Scrambler'' classes, one can use the [[LookupAndSpring]] bridge. Then the actual implementations of needed interfaces are to be discovered using [[ServiceLoader|Java Extension Mechanism]] as abstracted by [[Lookup]]. The steps are simple. Get the [[LookupAndSpring]] and [[Lookup]] libraries and just compose your own XML context with the [[ServiceLoader|Java Extension]] one in your main method:
<source lang="java" snippet="anagramdemo.springlookup.main"/>
<source lang="java" snippet="anagramdemo.springlookup.main"/>
-
This creates an unfinished, open application to be extended by other [[JAR]]s composed together by those who assemble and deploy the final application. Yet, the coding style and testing of individual application's [[JavaBean]]s can be done using the classical [[Spring]] [[Dependency Injection]] style of development (just like the ''Anagrams'' class shows).
+
This creates an unfinished, open application to be extended by other [[JAR]]s orchestrated together by those who assemble and deploy the final application. Yet, the coding style and testing of individual application's [[JavaBean]]s can be done using the classical [[Spring]] [[Dependency Injection]] style of development (just like the ''Anagrams'' class shows).
=== Double [[Injection]] ===
=== Double [[Injection]] ===
-
Yet, if there are extensions written according to the [[ServiceLoader|Java Extension]] mechanism or using the ''@ServiceProvider'' annotation offered by the [[Lookup]] library, one can have [[JAR]] files one with:
+
Yet, if there are extensions written according to the [[ServiceLoader|Java Extension]] mechanism or using the ''@ServiceProvider'' annotation offered by the [[Lookup]] library, one can have a [[JAR]] file containing result of compilation of:
<source lang="java" snippet="anagramdemo.springlookup.scrambler"/>
<source lang="java" snippet="anagramdemo.springlookup.scrambler"/>
Line 37: Line 37:
I am not sure if this kind of ''double'' [[injection]] can be useful in web applications where developer is also acting as assembler putting everything together, but in [[Use Modular Architecture|modular applications]] it has its place. If you are interested, see and use the [[Spring]]/[[Lookup]] bridge:
I am not sure if this kind of ''double'' [[injection]] can be useful in web applications where developer is also acting as assembler putting everything together, but in [[Use Modular Architecture|modular applications]] it has its place. If you are interested, see and use the [[Spring]]/[[Lookup]] bridge:
-
* [http://hudson.apidesign.org/hudson/job/lookup/org.apidesign$spring-lookup/javadoc/ javadoc]
+
* [http://hudson.apidesign.org/hudson/job/lookup/javadoc/ javadoc]
 +
* [http://hudson.apidesign.org/hudson/job/lookup/lastSuccessfulBuild/artifact/spring.lookup/target/ library JAR]
 +
* [http://source.apidesign.org/hg/lookup/file/tip/spring.lookup source] - use ''hg clone http://source.apidesign.org/hg/lookup/'' to get it localy.
Leave here comments about your satisfaction, disappointment and my confusion.
Leave here comments about your satisfaction, disappointment and my confusion.
<comments/>
<comments/>

Current revision

An important subset of Spring is said to be an example of Dependency Injection. Lookup library, originally invented by NetBeans project seems to do similar kind of injection. Do these two APIs serve similar purpose or are they both quite different? Each of them is optimized for slightly different task. Could they strengthen themselves if they worked together? That it what we'll find soon out.

Imagine there is a GUI application to play the Anagrams Game. We have a base UI class called Anagrams that needs two additional interfaces to be injected. In Spring world, this can be done with a two arguments constructor:

Code from Anagrams.java:
See the whole file.

public class Anagrams extends javax.swing.JFrame implements UI {
    private WordLibrary wordLibrary;
    private Scrambler scrambler;
 
    public Anagrams(WordLibrary w, Scrambler s) {
        wordLibrary = w;
        scrambler = s;
        init();
    }
}
 

and an XML configuration file:

Code from Main.xml:
See the whole file.

<bean
    id="ui"
    class="org.apidesign.demo.anagramwithspringandlookup.Anagrams"
    autowire="autodetect"
/>
 

If used in classical Spring sense, the configuration file would have to refer to implementations of both constructor arguments, in order to let the Anagrams class to be properly wired. While this is fine in world of web applications, when one knows all the libraries running on the server, this may be too restricted in world of modular applications which are assembled together by someone else than the developer of the Anagrams implementation.

Java Extension Mechanism

To open door and allow others to do late injection to bind various implementations of WordLibrary and Scrambler classes, one can use the LookupAndSpring bridge. Then the actual implementations of needed interfaces are to be discovered using Java Extension Mechanism as abstracted by Lookup. The steps are simple. Get the LookupAndSpring and Lookup libraries and just compose your own XML context with the Java Extension one in your main method:

Code from Main.java:
See the whole file.

public static void main(String[] args) throws Exception {
    ApplicationContext servicesContext = SpringAndLookup.create(
        Lookup.getDefault(), "java.extensions"
    );
    ClassPathXmlApplicationContext mergedContext;
    mergedContext = new ClassPathXmlApplicationContext(
        new String[] { "Main.xml" },
        Main.class,
        servicesContext
    );
    UI ui = (UI)mergedContext.getBean("ui", UI.class);
    ui.display();
}
 

This creates an unfinished, open application to be extended by other JARs orchestrated together by those who assemble and deploy the final application. Yet, the coding style and testing of individual application's JavaBeans can be done using the classical Spring Dependency Injection style of development (just like the Anagrams class shows).

Double Injection

Yet, if there are extensions written according to the Java Extension mechanism or using the @ServiceProvider annotation offered by the Lookup library, one can have a JAR file containing result of compilation of:

Code from SimpleScrambler.java:
See the whole file.

@ServiceProvider(service=Scrambler.class)
public class SimpleScrambler implements Scrambler {
    private static final Random random = new Random();
 
    public String scramble(String word) {
}
}
 

and another one with another class:

Code from StaticWordLibrary.java:
See the whole file.

@ServiceProvider(service=WordLibrary.class)
public class StaticWordLibrary implements WordLibrary {
}
 

or even more JARs with different implementations of the same interfaces.

The composition of final application then becomes piece of cake. Instead of writing complicated binding XML file or doing inefficient on start scan of all resources in a package, one can just put selected JAR files into classpath and they look each other up effectively and unrestrainably.

In some sense this represent an example of double injection. First of all we instructed the Spring framework to do its Dependency Injection to provide necessary implementations to the Anagrams class constructor. Yet, these implementations are unknown at compile time of the JAR and they are not present in any single configuration file. Instead they are picked up from the runtime classpath by using Java Extension Mechanism as abstracted by Lookup.getDefault(). This is the second level of injection where the assembler injects various JARs into effective application classpath.

I am not sure if this kind of double injection can be useful in web applications where developer is also acting as assembler putting everything together, but in modular applications it has its place. If you are interested, see and use the Spring/Lookup bridge:

Leave here comments about your satisfaction, disappointment and my confusion.

<comments/>

Personal tools
buy