Simple IOC Container Implementation-XML-based approach

Source: Internet
Author: User
Tags abstract reflection tostring xmlns
Overview

IOC (inversion of control) "controlled inversion", but the more popular term is "dependency injection" (di-dependency injection).

What is "inversion of control"? The fact is that control (the right to create a dependency between objects and objects) is given to the spring container. We used to use new Xxximpl () when we were writing code that needed an object, and with the spring IOC container, it was responsible for object creation and dependency injection, which was just as good as the spring IOC container when we needed an object.

The IOC sounds very tall, but it's not complicated to realize. This article focuses on the implementation of an IOC container based on an XML configuration, followed by a separate chapter on how to implement an IOC container through annotations. usage

The specific usage is similar to the spring IOC, as follows:

1. Beans.xml configuration file

<?xml version= "1.0" encoding= "UTF-8"?> <beans
xmlns= "Http://www.springframework.org/schema/beans"  
    xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"     
    xsi:schemalocation= "http// Www.springframework.org/schema/beans  
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd ">  

    <bean id= "Userdao" class= "Com.ricky.ioc.sample.dao.UserDaoImpl" scope= "singleton" init-method= "Init" > </bean>

    <bean id= "UserService" class= "Com.ricky.ioc.sample.service.UserServiceImpl" >  
        < Property Name= "Userdao" ref= "Userdao" ></property>  
    </bean>

    <bean id= "Usercontroller" class= "Com.ricky.ioc.sample.controller.UserController" >  
        <property name= "UserService" ref= "UserService" ></property>  
    </bean>
</beans>  

2. Add Maven Dependency

<dependency>
    <groupId>com.ricky.framework</groupId>
    <artifactid>ioc</ artifactid>
    <version>1.0.0</version>
</dependency>

3. Load Bean configuration file

ApplicationContext CTX = new Classpathxmlapplicationcontext ("Beans.xml");

Get bean Usercontroller by id
usercontroller = (usercontroller) ctx.getbean ("Usercontroller");
Usercontroller.login ("Ricky", "123");

Get Bean
UserService userservice = Ctx.getbean (Userservice.class) through class;
System.out.println (userservice);
Userservice.login ("Ricky", "abc");

Ctx.close ();

The results of the operation are as follows:

Usercontroller Login name->ricky,password->123
Userserviceimpl Login name->ricky,password->123
Userdaoimpl Find Name->ricky
com.ricky.ioc.sample.service.userserviceimpl@214c265e
Userserviceimpl Login Name->ricky,password->abc
Userdaoimpl Find Name->ricky
Container close ... Specific Implementation

Ideas:
Parsing Beans.xml Gets the list of beans and the dependencies between them, and then constructs the bean instance through reflection technology and makes the Bean assembly based on the dependency between the beans.

First, look at the ApplicationContext class with the following code:

Package COM.RICKY.FRAMEWORK.IOC;
Import java.beans.IntrospectionException;
Import Java.beans.Introspector;
Import Java.beans.PropertyDescriptor;
Import java.lang.reflect.InvocationTargetException;

Import Java.lang.reflect.Method;

Import Org.apache.commons.lang3.StringUtils;
Import com.ricky.framework.ioc.model.BeanDefinition;
Import com.ricky.framework.ioc.model.PropertyDefinition;

Import Com.ricky.framework.ioc.util.ReflectionUtils;

    Public abstract class ApplicationContext {public abstract Object Getbean (String ID);

    Public abstract <T> T Getbean (class<t> clazz);

    public abstract void Close ();

    Protected abstract beandefinition getbeandefinition (String ID); Protected Object Createbean (beandefinition BD) {try {Object bean = reflectionutils.newinstance (bd.g
            Etclassname ()); if (Stringutils.isnotempty (Bd.getinitmethodname ())) {Reflectionutils.invokemethod (bean, Bd.getinitmethodnam
            E ());

 }           return bean; } catch (ClassNotFoundException | instantiationexception | illegalaccessexception | IllegalArgumentException | InvocationTargetException |
        Nosuchmethodexception e) {throw new RuntimeException ("Create bean error, class->" +bd.getclassname (), E);
            }} protected void Injectbeanproperties (Object bean, beandefinition beandefinition) {try {  

            Propertydescriptor[] PS = Introspector.getbeaninfo (Bean.getclass ()). Getpropertydescriptors (); For (PropertyDefinition propertyDefinition:beanDefinition.getProperties ()) {for (PropertyDescriptor Pro  

                        PERTYDESCRIPTOR:PS) {if (Propertydescriptor.getname (). Equals (Propertydefinition.getname ())) { 
                        Method setter = Propertydescriptor.getwritemethod (); 

                        Setter.setaccessible (TRUE); Setter.invoke (Bean, Getbean (propertydefinitiOn.getref ())); }}}} catch (SecurityException | illegalaccessexception | IllegalArgumentException | InvocationTargetException |
        Introspectionexception e) {throw new RuntimeException ("Inject bean properties Error", E);
 }
    }
}

There are two key classes involved: Beandefinition and propertydefinition, which are used to describe the definition of javabean and the definition of JavaBean attribute, a beandefinition There can be 1 or more propertydefinition, and they are 1:n relationships. The code is as follows:

Beandefinition.java

Package Com.ricky.framework.ioc.model;

Import java.util.List;
    public class Beandefinition {private String ID;
    Private String ClassName;   Private String scope;
    Singleton|prototype private String Initmethodname;

    Private list<propertydefinition> properties;  
        Public beandefinition (string ID, string className) {this.id = ID;  
    This.classname = ClassName;
    } public String GetId () {return id;
    } public void SetId (String id) {this.id = ID;
    } public String GetClassName () {return className;
    } public void Setclassname (String className) {this.classname = ClassName;
    } public String Getscope () {return scope;
    The public void Setscope (String scope) {this.scope = scope;
    } public String Getinitmethodname () {return initmethodname; } public void Setinitmethodname (String initmethodname) {this.initmethodname = InitmethodName;
    } public list<propertydefinition> GetProperties () {return properties;
    } public void SetProperties (List<propertydefinition> properties) {this.properties = properties;
                } @Override Public String toString () {return "beandefinition [id=" + ID + ", classname=" + className + ", scope=" + Scope + ", initmethodname=" + Initmethodname + ", properties=" + Properties +
    "]";
 }

}

Propertydefinition.java

Package Com.ricky.framework.ioc.model;

public class PropertyDefinition {  
    private String name;
    Private String ref;

    Public propertydefinition (string name, string ref) {  
        this.name = name;  
        This.ref = ref;  
    }  
    Public String GetName () {  
        return name;  
    }  
    public void SetName (String name) {  
        this.name = name;  
    }  
    Public String GetRef () {  
        return ref;  
    }  
    public void SetRef (String ref) {  
        this.ref = ref;  
    }

    @Override public
    String toString () {
        return "propertydefinition [name=" + name + ", ref=" + ref + "]";
    }

}  

2, Next is the Classpathxmlapplicationcontext class, the code is as follows:

Package COM.RICKY.FRAMEWORK.IOC;
Import java.io.FileNotFoundException;
Import Java.util.HashMap;
Import java.util.List;

Import Java.util.Map;
Import Org.apache.commons.lang3.StringUtils;

Import org.dom4j.DocumentException;
Import com.ricky.framework.ioc.model.BeanDefinition;
Import Com.ricky.framework.ioc.parser.BeanXmlConfigParser;
Import Com.ricky.framework.ioc.util.BeanScope;

Import Com.ricky.framework.ioc.util.ReflectionUtils; public class Classpathxmlapplicationcontext extends ApplicationContext {private map<string, beandefinition> be
    Andefinitionmap = new hashmap<string, beandefinition> ();

    Protected Map<string, object> beaninstancemap = new hashmap<string, object> (); Public Classpathxmlapplicationcontext (String xmlfilepath) {System.out.println ("****************container init is

        gin**************** ");
        READXML (Xmlfilepath);
        Initbeans ();

        Injectbeans (); System.out.println ("****************container INIT end**************** "); private void ReadXml (String xmlfilepath) {beanxmlconfigparser beanxmlconfigparser = new Beanxmlconfigpars

        ER ();
        List<beandefinition> bean_def_list = null;
        try {bean_def_list = Beanxmlconfigparser.parse (Xmlfilepath); } catch (FileNotFoundException e) {throw new RuntimeException ("Not Found bean XML, file->" +xmlfilepath, E)
        ; 
        } catch (Documentexception e) {throw new RuntimeException ("Bean XML format error, file->" +xmlfilepath, E); } for (Beandefinition beandefinition:bean_def_list) {if (Stringutils.isempty (Beandefiniti On.getid ()) | | Stringutils.isempty (Beandefinition.getclassname ())) {throw new illegalargumentexception ("Bean definition I

            S empty! ");}
                        if (Beandefinitionmap.containskey (Beandefinition.getid ())) {throw new IllegalArgumentException ( "DUPlicated Bean ID, id-> "+ Beandefinition.getid ());
        } beandefinitionmap.put (Beandefinition.getid (), beandefinition); }} private void Initbeans () {for (map.entry<string, beandefinition> me:beanDefinitionMap.entry
            Set ()) {beandefinition BD = Me.getvalue ();
                    if (Stringutils.isempty (Bd.getscope ()) | | Bd.getscope (). Equals (Beanscope.singleton)) {try {
                    Object Bean = Createbean (BD);
                Beaninstancemap.put (Bd.getid (), Bean); } catch (Exception e) {throw new IllegalArgumentException ("Create Bean error,class->" +bd.getclassn
                Ame (), E);  }}}} private void Injectbeans () {for (map.entry<string, beandefinition> me
            : Beandefinitionmap.entryset ()) {Beandefinition beandefinition = Me.getvalue ();  
 Determine if there is an injected attribute           if (beandefinition.getproperties () = null && beandefinition.getproperties (). Size () >0) {  
                Object bean = Beaninstancemap.get (Beandefinition.getid ());
                try {injectbeanproperties (bean, beandefinition);
                } catch (Exception e) {e.printstacktrace ();  }}}} @Override public Object Getbean (String ID) {//System.out.println ("Get

        Bean by ID: "+id);
        if (Stringutils.isempty (ID)) {return null;

            } if (Beandefinitionmap.containskey (ID)) {beandefinition BD = beandefinitionmap.get (ID); if (Stringutils.isempty (Bd.getscope ()) | | Bd.getscope (). Equals (Beanscope.singleton)) {return Beaninsta
            Ncemap.get (ID);
            } Object bean = null;
                try {bean = Createbean (BD);
 Injectbeanproperties (Bean, BD);               Beaninstancemap.put (Bd.getid (), Bean);
            } catch (Exception e) {e.printstacktrace ();
        } return bean;
    } throw new IllegalArgumentException ("Unknown bean, id->" + ID); } @SuppressWarnings ("Unchecked") @Override public <T> T Getbean (class<t> clazz) {//System

        . OUT.PRINTLN ("Get Bean by Type:" +clazz.getname ()); For (map.entry<string, beandefinition> me:beanDefinitionMap.entrySet ()) {beandefinition BD = Me.getval
            UE ();
            Class<?> beanclass = null;
            try {beanclass = Reflectionutils.loadclass (Bd.getclassname ());
            } catch (ClassNotFoundException e) {e.printstacktrace (); } if (Beanclass!=null && clazz.isassignablefrom (beanclass)) {//System.out.println ("Find
                Bean by Type, class-> "+clazz.getname ()); Return (T) Getbean(Bd.getid ());
    }} return null;
    } @Override protected beandefinition getbeandefinition (String ID) {return beandefinitionmap.get (ID);

        } @Override public void Close () {System.out.println ("container close ...");
        Release resource Beandefinitionmap.clear ();

        Beandefinitionmap = null;
        Beaninstancemap.clear ();
    Beaninstancemap = null;
 }

}

In the Classpathxmlapplicationcontext class, there are three main functions: parsing an XML configuration file, building a bean instance from reflection, and assembling the bean.


Summary

All of the above code has been uploaded to GitHub and you are welcome to fork. In addition, because of the time is more hasty, the code design has unreasonable place also please forgive, later will take time to refactor the code.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.