Order
The first time I learned the concept of control inversion (inversion of controls) was when learning the spring framework. IOC and AOP, as the two characteristics of spring, are naturally going to learn well. and Dependency Injection (Dependency injection, short di) makes me confused for a long time, always trying not to understand the connection between them.
Control Reversal
Control reversal as the name implies, is to reverse control, then exactly what control is reversed? In 2004 Martin Fowler, the Great God, made
"What aspects of control have been reversed?" ”
The problem, he concludes, is that the acquisition of dependent objects is reversed.
Under the design of a single responsibility principle, there are few tasks that can be accomplished by a single object. Most tasks require a complex number of objects to work together, so that there is a dependency between the object and the object. The first dependency between objects is self-addressed, what is needed for the new one to come out with, control is in the object itself. But this coupling is very high, perhaps a small modification of an object will cause a chain reaction, the need to change the dependent objects all the way past.
If the dependency object's gain is reversed, what dependent object is generated and when it is generated is determined by the IOC container outside the object. objects can be obtained only when they are used with dependent objects, and are commonly used in the form of dependency injection and dependency lookup (Dependency lookup). The coupling between objects and objects is removed to the object, and subsequent modifications do not need to modify the original code.
To summarize, control reversal refers to the transfer of the object's dependency management from the inside to the outside.
Dependency Injection
Control inversion is to refer to the dependencies between the objects outside management, can rely on the object is referred to outside, the object itself or to use the dependent object, this time to use the dependency injection. As the name implies, the application needs to inject the dependencies needed by the object from the outside. This can be injected through the object's constructor, called the constructor injection (Constructor injection). If it is through the JavaBean attribute method of the parameter injection, it is called the Set Value method injection (Setter injection).
No matter how it is injected, it is too troublesome if we inject it manually. At this point, we need a container to help us implement this function, and automatically inject the required dependency into the object, which is the IOC container mentioned earlier.
The relationship between control inversion and dependency injection is clear, they are essentially the same, but specific concerns differ. The focus of control inversion is the transfer of control, while the dependency injection contains the meaning of control inversion, which clearly describes that the dependent object is managed externally and then injected into the object. The dependency injection is implemented, and the control is reversed.
Example
The first is the traditional way, the coupling is very serious.
public class Main {
public static void main(String[] args) { OrderService service = new OrderService(); service.test();}
}
private OrderDao dao = new OrderDao();public void test() { dao.doSomeThing();}
}
public class Orderdao {
public void doSomeThing() { System.out.println("test");}
}
The next step is not to use the container, loosely coupled, but manual injection is very troublesome.
public class Main {
public static void main(String[] args) { Dao dao = new OrderDao(); OrderService service = new OrderService(dao); service.test();}
}
Public interface Dao {
void doSomeThing();
}
public class Orderdao implements Dao {
@Overridepublic void doSomeThing() { System.out.println("test");}
}
public class OrderService {
private Dao dao;public OrderService(Dao dao) { this.dao = dao;}public void test() { dao.doSomeThing();}
}
Then use containers for the benefit of mankind.
The boot class should be placed under the project root, which is below SRC
public class Main {
public static void main(String[] args) { // 生成容器 Container container = new Container(Main.class); // 获取Bean OrderService service = container.getBean(OrderService.class); // 调用 service.test();}
}br/> @Component
< p="">
@Autowiredprivate Dao dao;public void test() { dao.doSomeThing();}public Dao getDao() { return dao;}public void setDao(Dao dao) { this.dao = dao;}
}
@Component
public class Orderdao implements Dao {
@Overridepublic void doSomeThing() { System.out.println("test");}
}
Public interface Dao {
void doSomeThing();
}br/> @Retention (Retentionpolicy.runtime)
Public @interface Component {br/>}
@Retention (Retentionpolicy.runtime)
Public @interface autowired {
}
public class Container {
Private list<string> classpaths = new arraylist<> ();p rivate String separator;private map<class, Object > Components = new hashmap<> ();p ublic Container (Class cls) {File File = new file (Cls.getresource (""). GetFile ( )); Separator = File.getname (); Renderclasspaths (New File (This.getclass (). GetResource (""). GetFile ())); Make (); Di ();} private void Make () {Classpaths.foreach (ClassPath, {try {Class c = class.forname (ClassPath); Find a @ioc. Component the annotated class and instantiates if (C.isannotationpresent (Component.class)) {Components.put (c, c.newinstance ()); }} catch (ClassNotFoundException | instantiationexception | Illegalaccessexception e) {e.printstacktrace (); } });} /** * injects dependent */private void Di () {Components.foreach ((AClass, O), Arrays.stream (Aclass.getdeclaredfields ()). ForEach (field, {if (Field.isannotationpresent (Autowired.class)) {try {String methodName = "Set" + Field.gettype (). GetName (). substring (Field.gettype (). GetName (). lastIndexOf (".") + 1); method = Aclass.getmethod (MethodName, Field.gettype ()); if (Field.gettype (). Isinterface ()) {Components.keyset (). ForEach (AClass1, { if (Arrays.stream (Aclass1.getinterfaces ()). AnyMatch (AClass2-Aclass2.equals (Field.gettype ()))) { try {method.invoke (O, Components.get (ACLASS1)); } catch (Illegalaccessexception | InvocationTargetException e) {e.printstacktrace (); } } }); } else {Method.invoke (O, Components.get (Field.gettype ())); }} catch (Nosuchmethodexception | illegalaccessexception | InvocationTargetException e) { E.printstacktrace (); } } }));} /** * This method will get all classes, write the full class name of the class to Classpaths * * @param file package */private void renderclasspaths (file file) {if (file.isdirecto Ry ()) {file[] files = file.listfiles (); Arrays.stream (Objects.requirenonnull (Files)). ForEach (this::renderclasspaths); } else {if (File.getname (). EndsWith (". Class")) {String ClassPath = File.getpath (). SUBSTRING (File.getpath (). LastIndexOf (separator) + separator.length () + 1). replace (' \ \ ', '. ') . replace (". Class", ""); Classpaths.add (ClassPath); }}}public <T> T Getbean (Class c) {return (T) Components.get (c);}
}
PostScript
Some concepts are thought to be clear in the mind, and when used or written in writing, there are a lot of things that you don't understand. The purpose of this article is to comb the concepts and make some records. This time I tried to implement the next IOC container, and at the beginning of writing I knew that I had a problem with my previous understanding. At least I wrote a version that I could use to deal with the examples in the article. The following can be used to refer to the implementation of spring, it is estimated to learn a lot of things.
My blog Address
Spring theory base-control inversion and dependency injection