Wednesday, January 25, 2012

Spring IOC without xml


Since Java adopted annotations, most of application has started using it to cut down the xml configuration, spring 3 also introduce the annotation driven configuration, let’s explore.
Here is the Martin Fowler’s famous dependency injection example of moviLister and moveFinder

MovieFinder

public interface MovieFinder {
    List findAll();
}

Implementation of MovieFinder
public class ColonMovieFinder implements MovieFinder {
            Resource filename;
           
            public Resource getFilename() {
                        return filename;
            }

           
            public void setFilename(Resource filename) {
                        this.filename = filename;
            }

            @Override
            public List<Movie> findAll() {
                        List<Movie> movies=null;
                        try {
                                    movies = inputStreamAsString(this.filename.getInputStream());
                        } catch (IOException e) {
                                    // TODO Auto-generated catch block
                                    e.printStackTrace();
                        }
                        return movies;
            }
           
}      

MovieLister needs MovieFinder dependency

public class MovieLister {

            private MovieFinder finder;

            public void setFinder(MovieFinder finder) {
                        this.finder = finder;
            }

           
           
            public Movie[] moviesDirectedBy(String arg) {
                        List allMovies = finder.findAll();
                        for (Iterator it = allMovies.iterator(); it.hasNext();) {
                                    Movie movie = (Movie) it.next();
                                    if (!movie.getDirector().equals(arg))
                                                it.remove();
                        }
                        return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);
            }
           
           
}

Setup the dependency
1.       Configuration java class need to be written to define the dependency.
2.       Add @Configuration to tell the spring about your configuration class
3.       @Bean should be define to tell the spring, they are spring bean
4.       initMethod and distroyMethod attribute should be used in @Bean annotation to define the life cycle.
5.       @Scope should be used to define the scope is singleton or prototype or request ect

@Configuration
public class AppConfig {

            public
            @Bean(destroyMethod="distroy",initMethod="init")
             @Scope("prototype")
            MovieLister movieLister() {
                        MovieLister moviLister = new MovieLister();
                        moviLister.setFinder(movieFinder());
                        return moviLister;
            }

            public @Bean
            MovieFinder movieFinder() {
                        ColonMovieFinder colonMovieFinder = new ColonMovieFinder();
                        Resource resource = new ClassPathResource("examples/movies.txt");
                        colonMovieFinder.setFilename(resource);
                        return colonMovieFinder;
            }

}
Construct the application context
1.       Pass the class having @Configuration to AnnotationConfigApplicationContext constructor
2.       More than one configuration can be written and all of them can be passed to constructor as it support java 5 vargar


AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

Test class
public class ApplicationContextAnnotationTest {

            public static void main(String[] args) {
        //Initialize IoC Container
                        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

                        //Retrieve the bean from Container
                        MovieLister myBean = context.getBean(MovieLister.class);

                        for(Movie m : myBean.moviesDirectedBy("Rajnikant")){
                                    System.out.println(m); 
                        }
                        context.destroy();
                        context.close();
            }
           
}

Problems what if you two bean of same type?
1.       Pass the name to @bean attribute
2.       Get the bean from context using been class and name.

Register bean by name
            public @Bean(name="moviFinder")
            MovieFinder movieFinder() {
                        ColonMovieFinder colonMovieFinder = new ColonMovieFinder();
                        Resource resource = new ClassPathResource("examples/movies.txt");
                        colonMovieFinder.setFilename(resource);
                        return colonMovieFinder;
            }

Retrieve bean by name
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
           
MovieFinder myFind = context.getBean("moviFinder",MovieFinder.class);


Problem : this approach doesn’t cut the configuration it just move the configuration from xml file to java file, right way to cut the configuration is autowiring that I will post in next blog


No comments: