Spring Source _Simulated Spring IOC Based on XML (Simulated Attribute Injection, Construction Method Injection, Automatic Injection)

Keywords: Attribute Spring Java xml

1. The concept of inversion of control:

Controlling inversion is a relatively abstract concept, illustrated by examples. In real life, when people want to use one thing, people's basic idea is to find something, such as a glass of orange juice. In the days without a drink shop, the most intuitive way is to buy a juicer, orange, ready to boil water. Please note that this is your own "active" creative process, that is, a glass of orange juice needs to be created actively. Today, however, because of the popularity of beverage shops, there is no need to squeeze orange juice by oneself. As soon as the idea of orange juice comes up, the first idea is to find the contact information of the drinks shop, describe your needs, address, contact information and so on through telephone and Wechat channels, place an order and wait, someone will send orange juice later. Please note that you did not "actively" create orange juice, that is, orange juice is created by the drinks shop, not you, but also fully meet your requirements.

Controlling inversion is a way of generating or acquiring specific objects through description (XML or annotations in Java) and through third parties.

In Spring, the IoC container is used to implement control inversion, and its implementation method is Dependency Injection (DI). As mentioned above, the juice maker relies on the beverage store and the order to make the juice, and the beverage store is created by others. We just need to know that it can produce the juice, and we don't need to understand how to create the juice.

The design of Spring IoC container is mainly based on BeanFactory and ApplicationContext interfaces. ApplicationContext is one of the sub-interfaces of BeanFactory. In other words, BeanFactory is the bottom interface defined by Spring IoC container. ApplicationContext is one of its advanced interfaces, and BeanFactory functions are also implemented. Many useful extensions, so in most work scenarios, Application Context is used as a Spring IoC container

2. Inversion of analog control

2.1 Creating dao Layer Interface

package com.lic.dao;
public interface UserDao {
    public void query();
}

2.2 Create dao Layer Implementation Classes

package com.lic.dao;
public class UserDaoImpl implements UserDao{
    @Override
    public void query() {
        System.out.println("Analog Query");
    }
}

2.3 Creating service Layer Interface

package com.lic.service;

public interface UserService {
    public void query();
}

2.4 Create service Layer Implementation Class

package com.lic.service;
import com.lic.dao.UserDao;
public class UserServiceImpl implements UserService {
    private UserDao userDao;
    private UserDao userDao1;
 
    //Construction method
    /*public UserServiceImpl(UserDao userDao,UserDao userDao1) {
        this.userDao = userDao;
        this.userDao1 = userDao1;
    }*/
    
    public void query() {
        userDao.query();
        userDao1.query();
    }
}

2.5 Create Configuration Files

<?xml version='1.0' encoding='UTF-8'?>

<beans default-autowire="byName">
    <bean name="userDao" class="com.lic.dao.UserDaoImpl"></bean>
    <bean name="userDao1" class="com.lic.dao.UserDaoImpl"></bean>

    <bean name="userService" class="com.lic.service.UserServiceImpl">
        <!-- Attribute injection -->
       <!-- <property name="userDao" ref="userDao"></property>
        <property name="userDao1" ref="userDao1"></property>-->

        <!-- Constructor injection test constructor injection needs serviceImpl Create a parametric construction method in-->
       <!-- <constructor-arg name="userDao" ref="userDao"></constructor-arg>
        <constructor-arg name="userDao1" ref="userDao1"></constructor-arg>-->
    </bean>
</beans>

2.6 Create Factory Class

package com.lic.spring;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.*;

public class BeanFactory {
    // ioc container for storing registered bean objects
    Map<String,Object> map =new HashMap<>();
    // Construction method
    public BeanFactory(String path){
        parseXml(path);
    }

    //Resolve configuration files and register related objects
    private void parseXml(String path){
        File file = new File(this.getClass().getResource("/").getPath()+"//"+path);
        //Need to import dom4j jar package
        SAXReader reader = new SAXReader();
        try{
            //Parsing configuration files using dom4j
            Document document = reader.read(file);
            //Get the root node < beans >
            Element elementRoot = document.getRootElement();

            //Automatic injection of labels, default to false
            boolean autowireFlag = false;
            String autowire = elementRoot.attribute("default-autowire").getValue();
            //If automatic injection is set, it will be injected as the case may be (attribute injection, construction method injection priority is higher than automatic injection)
            if (autowire.trim().length() > 1) {
                autowireFlag = true;
            }

            //Get the child node of the root node < bean >
            for (Iterator<Element> beanFir = elementRoot.elementIterator(); beanFir.hasNext();) {
                /**
                 * setup1,Instantiate the object to get the class information of the instantiated object
                 */
                Element elementChild = beanFir.next();
                //Get the name attribute value of the current bean object
                String attrName = elementChild.attribute("name").getValue();
                //Gets the class attribute value of the current bean object
                String attrClass = elementChild.attribute("class").getValue();
                Class clazz = Class.forName(attrClass);

                /**
                 * setup2,Maintaining dependencies
                 * See if the object has a dependency (to determine whether there is a property subtag). Or determine whether a class has attributes
                 * If so, inject
                 */
                Object object = null;
                //Store the parameters of the constructor, and instantiate the object with parameters
                List conObj = new ArrayList<Object>();
                //Store the type of constructor parameters so that you can find the specified constructor
                List<Class> conArgs = new ArrayList<Class>();
                //When all the parameters of the construction method are ready, the object is instantiated outside the for loop.
                boolean haveConstructor = false;
                for (Iterator<Element> propertyFir = elementChild.elementIterator(); propertyFir.hasNext(); ) {
                    /*
                     *    Injection by property name
                     */
                    //Get the attribute key value
                    Element propertyEle = propertyFir.next();
                    if (propertyEle.getName().equals("property")) {
                        System.out.println(attrName + "Injecting by property name...");
                        //Instantiating objects with default constructors
                        if (object == null)
                            object = clazz.newInstance();
                        //Get the name attribute value
                        String proAttrName = propertyEle.attribute("name").getValue();
                        //Get the ref attribute value
                        String proAttrRef = propertyEle.attribute("ref").getValue();
                        //Getting registered property objects from containers
                        Object objectRefObj = map.get(proAttrRef);
                        //Getting Object Dependency Properties
                        Field property = clazz.getDeclaredField(proAttrName);
                        property.setAccessible(true);
                        property.set(object, objectRefObj);

                        /*
                         *    Injection by constructor
                         */
                    } else if (propertyEle.getName().equals("constructor-arg") && object == null) {
                        System.out.println(attrName + "Injecting through construction method...");
                        haveConstructor = true;
                        //Objects cannot be instantiated using default constructors
                        //Get the ref attribute value
                        String conArgRef = propertyEle.attribute("ref").getValue();
                        //Getting registered property objects from containers
                        Object conArgRefObj = map.get(conArgRef);
                        conObj.add(conArgRefObj);
                        conArgs.add(conArgRefObj.getClass().getInterfaces()[0]);
                    } else if(object == null){
                        throw new CannotParseExecption("What label is this?,Failure of parsing...");
                    }
                }
                //Initialization of objects through custom constructors
                if (haveConstructor) {
                    Class[] args = new Class[conArgs.size()];
                    for (int i = 0; i < conArgs.size(); i++) {
                        args[i] = conArgs.get(i);
                    }
                    Constructor constructor = clazz.getConstructor(args);
                    object = constructor.newInstance(conObj.toArray());
                }

                //If automatic injection is declared and property injection or constructor injection is not used in the bean, automatic injection is used
                if (autowireFlag && object == null) {
                    /*
                     *   Automatic injection according to type
                     */
                    if ("byType".equalsIgnoreCase(autowire)) {
                        //Gets all properties defined in the current class
                        Field[] fields = clazz.getDeclaredFields();
                        for (Field field : fields) {
                            //Get the name of the attribute type: com.lic.UserDao
                            String fieldClassName = field.getType().getName();
                            //Number of bean Objects with Compound Conditions
                            int countClass = 0;
                            //Storing eligible bean objects
                            Object tempObject = null;
                            //The class of attributes determines whether the interface is the same as that implemented by the registered class in map one by one. If the interface is the same and there is only one, then injection
                            for (String key : map.keySet()) {
                                //Get the interface of the registered class implementation in map
                                String tempClassName = map.get(key).getClass().getInterfaces()[0].getName();
                                //Comparisons
                                if (fieldClassName.equals(tempClassName)) {
                                    countClass++;
                                    tempObject = map.get(key);
                                }
                            }
                            if (countClass > 1) {
                                //If two identical matches are matched, an exception is thrown
                                throw new TooManyExpectClassrExecption("Expect to find an object,But we found two.!");
                            } else {
                                System.out.println(attrName + "Automatically injecting by type...");
                                //Create the current object using the default constructor
                                if (object == null)
                                    object = clazz.newInstance();
                                //Setting property values
                                field.setAccessible(true);
                                field.set(object, tempObject);
                            }
                        }

                        /*
                         *   Automatic injection based on attribute name
                         */
                    } else if ("byName".equalsIgnoreCase(autowire)) {
                        Field[] fields = clazz.getDeclaredFields();
                        for (Field field : fields) {
                            String fieldName = field.getName();
                            int countClass = 0;
                            for (String key : map.keySet()) {
                                if (fieldName.equalsIgnoreCase(key)) {
                                    //The key is unique in the map, so it is impossible to have a second identical name.
                                    System.out.println(attrName + "Automatically injecting by name...");
                                    if (object == null)
                                        object = clazz.newInstance();
                                    field.setAccessible(true);
                                    field.set(object, map.get(key));
                                    break;
                                }
                            }
                        }
                    } else {
                        throw new CannotParseExecption("What attributes are they?,Failure of parsing...");
                    }
                }

                //If the bean object has no subtags, the default constructor is called
                if(object == null){
                    object=clazz.newInstance();
                }
                //Put the created object in the container
                map.put(attrName,object);

            }
        }catch(Exception e){
            e.printStackTrace();
        }

    }

    public Object getBean(String beanName){
        return map.get(beanName);
    }
}

2.7 Create test methods

package com.lic.test;
import com.lic.service.UserService;
import com.lic.spring.BeanFactory;

public class SpringTest {
    public static void main(String[] args) {
        BeanFactory beanFactory = new BeanFactory("spring.xml");
        UserService userService = (UserService) beanFactory.getBean("userService");
        userService.query();
    }
}

Analysis:
The configuration file is parsed by dom4j, and the parsed object information is registered in the map container by reflecting the generated object, and the dependency is maintained. There are three main kinds of dependency maintenance: attribute injection, construction method injection and automatic injection; after automatic injection of life, if two other types of annotations are used before automatic injection. Input, automatic injection is no longer used;

Posted by steviemac on Mon, 05 Aug 2019 01:52:00 -0700