The first time I learned the concept of control inversion (inversion of controls) was when learning the Spring
framework. IOC
and AOP
as Spring
the two major characteristics, nature is 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 the 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 beginning of the dependency between the object is self-addressed, what needs to be New
an object out of the use, 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 outside of the object IOC容器
. 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. It can be injected through the object's constructor, which is called 构造器注入(Constructor Injection)
. If it is through JavaBean
the attribute method of the parameter injection, it is called 设值方法注入(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 mentioned earlier IOC容器
.
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(); }}
public class OrderService { private OrderDao dao = new OrderDao(); test() { dao.doSomeThing(); }}
public class OrderDao { 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 { doSomeThing();}
public class OrderDao implements Dao { @Override doSomeThing() { System.out.println("test"); }}
public class OrderService { private Dao dao; public OrderService(Dao dao) { this.dao = dao; } test() { dao.doSomeThing(); }}
- Then use containers for the benefit of mankind.
// 引导类要放在项目根目录下,也就是在 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(); }}
@Componentpublic class OrderService { @Autowired private Dao dao; test() { dao.doSomeThing(); } public Dao getDao() { return dao; } public void setDao(Dao dao) { this.dao = dao; }}
@Componentpublic class OrderDao implements Dao { @Override doSomeThing() { System.out.println("test"); }}
public interface Dao { doSomeThing();}
@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE})public @interface Component {}
@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.FIELD,ElementType.METHOD})public @interface Autowired {}
public class Container {private list<string> classpaths = new arraylist<> (); Private String separator; Private Map<class, object> components = new hashmap<> (); Public Container (Class CLS) {File File = new file (Cls.getresource (""). GetFile ()); Separator = File.getname (); Renderclasspaths (New File (This.getclass (). GetResource (""). GetFile ())); Make (); Di (); } private voidMake () {Classpaths.foreach (ClassPath) {try {Class c = class.forname (ClassPath); Find @ioc. Component Annotated class and instantiateif (C.isannotationpresent (Component.class)) {Components.put (c, c.newinstance ());}} catch (ClassNotFoundException | instantiationexception | Illegalaccessexception e) {e.printstacktrace ();}}); }/** * Injection dependent */private voidDi () {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.isdirectory ()) {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 try to achieve the next IOC容器
, the beginning of writing to know that their previous understanding there is a problem. 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 Spring
the implementation of the estimate can learn a lot of things.
My blog Address
Resources
- Understanding of control inversion and dependency injection
- The advanced terminology that those years don't understand--dependency inversion? Control inversion? Interface-oriented programming
- Control inversion (IOC) and Dependency injection (DI)
Spring theory base-control inversion and dependency injection