Simple IOC container Implementation-based on annotations

Source: Internet
Author: User
Tags bind string find

The previous article describes how to implement a simple IOC container based on an XML file. But spring not only supports the way XML files are configured, but also supports configuration via annotations, this article focuses on how to implement a simple IOC container with annotations. Use

First, let's look at how to do dependency injection based on annotations, with the following code:

Import Com.ricky.framework.ioc.bind.annotation.Inject;
Import com.ricky.ioc.sample.model.Student;
Import Com.ricky.ioc.sample.service.StudentService;

@Bean (id= "Studentcontroller") public
class Studentcontroller {

    @Inject
//  @Inject (name= " Studentservice ")
    private studentservice studentservice;

    Public String find (long id) {
        Student stu = studentservice.find (ID);
        System.out.println ("Stu:" +stu);
        Return "Fin
    }

}

Studentservice interface

Import com.ricky.ioc.sample.model.Student;

Public interface Studentservice {public

    Student find (long ID);
}

Studentservice interface Implementation Class

Import Com.ricky.framework.ioc.bind.annotation.Bean;
Import Com.ricky.framework.ioc.bind.annotation.Inject;
Import Com.ricky.ioc.sample.dao.StudentDao;
Import com.ricky.ioc.sample.model.Student;
Import Com.ricky.ioc.sample.service.StudentService;

@Bean (id= "Studentservice") Public
class Studentserviceimpl implements Studentservice {

    @Inject
    private Studentdao Studentdao;

    @Override Public
    Student find (Long id) {

        return studentdao.find (ID);
    }

}


The above uses two custom annotations: @Bean and @Inject. @Bean annotations are annotated on the Studentserviceimpl class, indicating that the class is given to "container" processing, and the ID of the Bean generated by the IOC container is the ID value of the @bean annotation. @Inject annotations are annotated on the Studentservice field, indicating that the field will be injected without new Studentserviceimpl (), @Inject annotations By default find the bean based on the name of the field, while @inject Annotations also support specifying beans through the Name property.


Then we need to configure the automatic annotation properties in the Beans.xml configuration file:

<?xml version= "1.0" encoding= "UTF-8"?>
<beans>

    <!--the package to be scanned--
    <context: Component-scan base-package= "Com.ricky.ioc.sample"/>  

    <bean id= "Userdao" class= " Com.ricky.framework.ioc.dao.UserDaoImpl "></bean>
    <bean id=" UserService "class=" Com.ricky.framework.ioc.service.UserServiceImpl ">
        <property name=" Userdao "ref=" Userdao "></ property>
    </bean>
    <bean id= "Usercontroller" class= " Com.ricky.framework.ioc.controller.UserController ">
        <property name=" UserService "ref=" UserService "> </property>
    </bean>
</beans>


In this case, the annotated IOC container is already configured, exactly as the spring IOC is used, and the next step is to see how this function is implemented.


Implement

@Bean annotations

Import java.lang.annotation.Documented;
Import Java.lang.annotation.ElementType;
Import java.lang.annotation.Retention;
Import Java.lang.annotation.RetentionPolicy;
Import Java.lang.annotation.Target;

@Retention (retentionpolicy.runtime)
@Target ({elementtype.type})
@Documented public
@interface Bean {/ /similar to bean String ID in spring config file
    ();
}

@Inject annotations

Import java.lang.annotation.Documented;
Import Java.lang.annotation.ElementType;
Import java.lang.annotation.Retention;
Import Java.lang.annotation.RetentionPolicy;
Import Java.lang.annotation.Target;

@Retention (retentionpolicy.runtime)
@Target ({elementtype.field, elementtype.method})
@Documented Public
@interface Inject {public

    String name () default "";
}

Finally, we scan all classes with @bean annotations under the current classpath, then construct the bean instance object with reflection and complete the dependency injection. The entire code is as follows:

Import Java.beans.Introspector;
Import Java.beans.PropertyDescriptor;
Import java.io.IOException;
Import Java.lang.reflect.Field;
Import Java.lang.reflect.Method;
Import Java.util.HashMap;
Import java.util.List;
Import Java.util.Map;
Import Com.ricky.framework.ioc.bind.annotation.Bean;
Import Com.ricky.framework.ioc.bind.annotation.Inject;

Import Com.ricky.framework.ioc.util.ClassDetector; public class Annotationioccontainer {protected Map<string, object> beaninstancemap = new hashmap<string, Ob

    Ject> ();

        public void bind (String packagename) {Initializebean (PackageName);
    Inject (); }/** * Instantiate bean */private void Initializebean (String packagename) {try {list&lt ;

            class<?>> list = new Classdetector (packagename). Detect (Bean.class);

                for (class<?> clazz:list) {Bean beanannotation = clazz.getannotation (Bean.class); System.out.println ("class=" +Clazz.getname () + ", bean_id=" +beanannotation.id ());  Object bean = clazz.newinstance ();
            If you need to inject through the constructor, you need to deal with Beaninstancemap.put (Beanannotation.id (), Bean) here;
        }} catch (IOException e) {e.printstacktrace ();
        } catch (Instantiationexception e) {e.printstacktrace ();
        } catch (Illegalaccessexception e) {e.printstacktrace ();  }} private void Inject () {for (String BeanName:beanInstanceMap.keySet ()) {Object Bean =  
            Beaninstancemap.get (Beanname);
                if (bean!=null) {processsetterannotation (bean);
            Processfieldannotation (Bean); }}}/** * processing annotations on field * @param bean */protected void processfieldannotation (Obje
            CT Bean) {try {field[] fields = Bean.getclass (). Getdeclaredfields (); for (Field field:fields) {if (Field!=null && field.isannotationpresent (inject.class)) {Inject resource = Field.getannotati  
                    On (Inject.class);  
                    String name = Resource.name ();  
                    Object Injectbean = null; if (name!=null&&! "".  
                    Equals (name)) {Injectbean = Beaninstancemap.get (name); }else{for (String Key:beanInstanceMap.keySet ()) {//Determines whether the type to which the current property belongs  
                                An if (Field.gettype (). IsAssignableFrom (Beaninstancemap.get (key). GetClass ()) is present in the configuration file {  
                                Gets the instance object of type match Injectbean = Beaninstancemap.get (key);
                            Break }}} if (Injectbean!=null) {//Allow visit Ask the Private field field.setaccessible (trUE);  
                    Inject the reference object into the attribute Field.set (bean, Injectbean);
                    }else{System.out.println ("Field inject failed,name=" +name);
        }}}} catch (Exception e) {e.printstacktrace (); }}/** * Handling annotations on set methods * @param bean */protected void processsetterannotation (Object bean) {try {//Get Bean's property descriptor propertydescriptor[] PS = Introspector.getbean  
            Info (Bean.getclass ()). Getpropertydescriptors ();  

                for (PropertyDescriptor pd:ps) {Method setter = Pd.getwritemethod ();  
                    if (Setter!=null && setter.isannotationpresent (inject.class)) {//Gets the current annotation and determines if the Name property is empty  
                    Inject resource = setter.getannotation (Inject.class);
       String name = Resource.name ();             Object Injectbean = null; if (name!=null&&! "".
                    Equals (name)) {Injectbean = Beaninstancemap.get (name);
                            }else{//If the current annotation does not specify a Name property, the match is based on the type for (String Key:beanInstanceMap.keySet ()) {  
                                if (Pd.getpropertytype (). IsAssignableFrom (Beaninstancemap.get (key). GetClass ())) { 
                                Injectbean = Beaninstancemap.get (key);
                            Break }}} if (Injectbean!=null) {//Allow visit
                        Ask Private Method Setter.setaccessible (True);
                    Inject the reference object into the attribute Setter.invoke (bean, Injectbean);
                    }else{System.out.println ("Setter inject failed,name=" +name); }}}} catch (ExcEption e) {e.printstacktrace (); }  
    }

}

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.