Ape thinking series 4 — Reflection of the passage of time in learning java

Time:2021-9-15

After reading the last chapter, I believe you have mastered some thinking skills. Today, let’s talk about a new topic. The last article is a simple topic. I hope it is simple but not simple. Of course, if you think it’s too shallow, please tell the ape man factory gentleman immediately. You can consider making some adjustments to better help you. In addition, I really appreciate your support. The struggle against the giant beast has temporarily entered a stalemate stage. The ape man factory gentleman has said that although there are thousands of people, I’ll go. The middle details, ape man factory king, will be disclosed at a convenient time. The program ape duck, and it is OK and cherished.

Ape thinking is an original series of articles to help you quickly master the basic knowledge from a little white. Many basic knowledge lies in the flexibility of thinking. For more wonderful content, please pay attention to the princessApe factory, clickApe man cultivation acquisition

Ape thinking series 4 -- Reflection of the passage of time in learning java

Ape thinking series 4 -- Reflection of the passage of time in learning java

Ape thinking series 4 -- Reflection of the passage of time in learning java

Ape thinking series 4 -- Reflection of the passage of time in learning java

Ape thinking series 4 -- Reflection of the passage of time in learning java

Ape thinking series 4 -- Reflection of the passage of time in learning java

Ape thinking series 4 -- Reflection of the passage of time in learning java

IOC is the English abbreviation of inversion of control. Control reversal? Haha, does it look strange? Control inversion is also an object-oriented programming principle and a programming idea. It refers to handing over the management right of creating objects to the container, and the container assembles and creates objects, so as to reduce the coupling between codes. There are generally two ways to implement the IOC idea, one is dependency lookup, and the other is the most common dependency injection. Dependency lookup means that when the program runs, the program uses the callback interface and context conditions provided by the container to find resources and objects, so that the program can obtain corresponding resources. This method is not widely used. It needs the support of the application server, that is, the routine of JavaEE specification, such as JNDI and EJB… This paper will not discuss it in detail. What is dependency injection? Dependency injection means that when the program is running, the program does not need to do dependency location query, and provides ordinary Java methods to let the container determine the dependency. The container is fully responsible for the assembly of the objects used by the program, and passes the objects conforming to the dependency to the dependent objects through attributes or constructors.

Ape thinking series 4 -- Reflection of the passage of time in learning java

Ape thinking series 4 -- Reflection of the passage of time in learning java

Let’s take a simple example. We have three classes: testservicetestmanager testdao. Testservice has a test () method, which calls the test () method of TestManager, and the test method of TestManager calls the test () method of testdao. If we want to call the test () method of testservice, under normal circumstances, when we write java code, we must need new testservice () newtestmanager (), new testdao (). Then pass the TestManager object as an attribute of testservice to testservice (testservice.setxxx or constructor), and the testdao object as an attribute of TestManager, In the class using testservice, you must import TestManager in the code,

In this way, the newly compiled code of this class is highly dependent, highly coupled and difficult to maintain. Now change to dependency injection. If we want to use testservice, we need to find the container to get testservice. The TestManager object already exists in the testservice object provided by the container, so when we use testservice, we only need to import testservice in the code! The newly compiled classes are less coupled and easier to maintain.

So how do you do it?

Ape thinking series 4 -- Reflection of the passage of time in learning java

It just provides a container to get the object, but the properties in the obtained object have been set by the container. What should I do? Create object by name! Well, to put it bluntly, it’s still reflection. Let’s take a look at a small example to implement simple dependency injection.

First define two annotations:

package  com.pz.study.frame.ioc;

import  java.lang.annotation.ElementType;
import  java.lang.annotation.Retention;
import  java.lang.annotation.RetentionPolicy;
import  java.lang.annotation.Target;


/**
 *Used to annotate classes that need to be managed by the container
 *
 * @author pangzi
 *
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
       String value() default"";

}
package com.pz.study.frame.ioc;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 *Used to annotate the attributes to be injected
 * @author pangzi
 *
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
[email protected] {

}

Define a simple container class:

package  com.pz.study.frame.ioc;

import  java.io.File;
import  java.io.IOException;
import  java.io.InputStream;
import  java.lang.reflect.Field;
import  java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

public class ApplicationContext {

       public static final Map<String,Object> applicationContext = new ConcurrentHashMap<String, Object>();
       static {
              InputStream stream =ApplicationContext.class.getClassLoader().getResourceAsStream("ioc-frame.properties");
          Propertiesproperties = new Properties();
        try {
            properties.load(stream);
        } catch (IOException e) {
            e.printStackTrace();
        }

        StringpackageName=properties.getProperty("package").toString();
              try {
                     instanceBean(packageName);
              } catch (Exception e) {
                     e.printStackTrace();
              }
       }

       /**
        *Get the object according to the name on the annotation
        * @param beanId
        * @return
        */
    public static Object getBean(String beanId){

              returnapplicationContext.get(beanId);

       }

       /**
        *Create an object under the package name and complete dependency injection
        * @param packageName
        * @throws Exception
        */
       private static void instanceBean(StringpackageName) throws Exception {
              instanceByPackageName(packageName);
              autoWared();
       }




       //Gets the instance using componentannotationbean under the specified package path
       private static void instanceByPackageName(String packageName) {
              try {

                     List<String>classNames= getClassName(packageName,true);

                     for(String className:classNames){
                            Class<?>clazz = Class.forName(className);
                            if (clazz.isAnnotationPresent(Component.class)) {
                                   clazz.getAnnotation(Component.class).value();
                                   applicationContext.put(clazz.getAnnotation(Component.class).value(), clazz.newInstance());
                            }

                     }


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


        /**
     *Get all classes under a package
     *
     * @param packageName
     *Package name
     * @param childPackage
     *Whether to traverse the sub package
     *Full name of @ return class
     */
    private static List<String> getClassName(String packageName, boolean childPackage) {
        List<String> fileNames= null;
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        String packagePath =packageName.replace(".", "/");
        URL url =loader.getResource(packagePath);
        if (url != null) {
            String type =url.getProtocol();
            if (type.equals("file")) {
                fileNames = getClassNameByFile(url.getPath(), null, childPackage);
            }
        }
        return fileNames;
    }


    /**
     *Get all classes under a package from the project file
     *
     * @param filePath
     *File path
     * @param className
     *Class name collection
     * @param childPackage
     *Whether to traverse the sub package
     *Full name of @ return class
     */
    private static List<String> getClassNameByFile(String filePath,List<String> className, boolean childPackage) {
        List<String> myClassName= new ArrayList<>();
        File file = new File(filePath);
        File[] childFiles =file.listFiles();
        for (File childFile :childFiles) {
            if (childFile.isDirectory()) {
                if (childPackage) {
                   myClassName.addAll(getClassNameByFile(childFile.getPath(),myClassName, childPackage));
                }
            } else {
                String childFilePath= childFile.getPath();
                if (childFilePath.endsWith(".class")) {
                    childFilePath =childFilePath.substring(childFilePath.indexOf("/classes") + 9,
                           childFilePath.lastIndexOf("."));
                    childFilePath =childFilePath.replace("/", ".");
                    myClassName.add(childFilePath);
                }
            }
        }

        return myClassName;
    }



       /**
        *Traverse map injection properties
        */
       private static void autoWared() {
        Map<String, Object> map= applicationContext;

        try {
        for(StringbeanId:map.keySet()){

             Object obj=map.get(beanId);

              Field[] fields =obj.getClass().getDeclaredFields();
             for (Field field : fields) {
                 if (field.isAnnotationPresent(Autowared.class)) {
                    field.setAccessible(true);
                     Object fieldObj= map.get(field.getName());
                     field.set(obj,fieldObj);
                 }
             }

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

If we want to use the object created by the container, just use ApplicationContext. GetBean () directly.

Next, we write a single validation code, using the objects provided by our annotation and ApplicationContext.

Write 3 interfaces:

package com.pz.study.frame.test;

public interface TestService {
       public void test();

}
package com.pz.study.frame.test;

public interface TestManager {
       public void test();

}
package com.pz.study.frame.test;

public interface TestDao {
       public void test();

}
package com.pz.study.frame.test;

import com.pz.study.frame.ioc.Autowared;
import com.pz.study.frame.ioc.Component;

@Component(value="testService")
public class TestServiceImpl implements TestService {
       @Autowared
       private TestManager testManager;

       public void test(){
              testManager.test();
       }

}
package com.pz.study.frame.test;

import com.pz.study.frame.ioc.Autowared;
import com.pz.study.frame.ioc.Component;

@Component(value="testManager")
public class TestManagerImpl implements TestManager {

       @Autowared
       private TestDao testDao;

       publicvoid test(){
              testDao.test();
       }

}
package com.pz.study.frame.test;

import com.pz.study.frame.ioc.Component;

@Component(value="testDao")
public class TestDaoImpl implements TestDao {

       public void test(){
              System.out.println ("IOC small framework test");
       }

}

Finally, write the running program

package com.pz.study.frame.test;

import com.pz.study.frame.ioc.ApplicationContext;

public class TestIoc {

       public static void main(String args[]){


              TestService testService=(TestService) ApplicationContext.getBean("testService");
              testService.test();

       }

}

After running the program, we find that the code runs correctly, and our program only depends on the testservice interface. The program submits the dependent objects to its own defined container ApplicationContext to create and equip them. We simply implemented the principle of dependency injection!