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;