My blog reprint please indicate the original source.

sequence

I first learned about Inversion of Control while studying the Spring framework. IOC and AOP, as the two major features of Spring, are naturally to learn. On the other hand, Dependency Injection (DI) has puzzled me for a long time.

Inversion of control

Inversion of control, as the name suggests, is to reverse control, so which controls are being reversed? Martin Fowler did it in 2004

“Where has control been reversed?”

The problem, he concluded, was that the acquisition of dependent objects was reversed.

Under the 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 are dependencies between objects. From the beginning, the dependency between objects is solved by themselves. If you need any objects, you can use New ones. The control is in the object itself. But the coupling is so high that a small change in one object can cause a chain reaction that requires modification of dependent objects all the way through.

If the acquisition of a dependency object is reversed, it is up to the IOC container outside the object to decide exactly what dependency object is generated and when. Objects are available only when dependent objects are needed, often in the form of Dependency injection and Dependency Lookup. The coupling between objects is removed from the object, and there is no need to modify the original code in case of subsequent dependency changes.

To summarize, inversion of control refers to the transfer of dependency management of an object from internal to external.

Dependency injection

Inversion of control refers to the external management of dependencies between objects. However, dependencies are managed outside of objects, and objects themselves still need to use dependent objects, so dependency injection is needed. As the name implies, the application needs to inject the dependencies needed by the object from outside. This can be done by passing arguments to an object’s Constructor. This is called Constructor Injection. If it is injected via a JavaBean property method, it is called Setter Injection.

No matter how it was injected, it would have been too much trouble if we had injected it manually. We need a container to do this for us, automatically injecting the dependencies needed by the object. This container is the IOC container mentioned earlier.

The relationship between inversion of control and dependency injection is also clear. They are essentially the same, but the specific focus is different. Inversion of control focuses on the transfer of control, while dependency injection implies inversion of control, which explicitly describes how dependent objects are managed externally and then injected into them. With dependency injection, control is reversed.

example

  • The first is the traditional way, where there’s a lot of coupling.
public class Main { public static void main(String[] args) { OrderService service = new OrderService(); service.test(); }}Copy the code
public class OrderService {

    private OrderDao dao = new OrderDao();

    public void test() { dao.doSomeThing(); }}Copy the code
public class OrderDao {

    public void doSomeThing() {
        System.out.println("test"); }}Copy the code
  • The next step is to use no container, loose coupling, but manual injection is cumbersome.
public class Main { public static void main(String[] args) { Dao dao = new OrderDao(); OrderService service = new OrderService(dao); service.test(); }}Copy the code
public interface Dao {

    void doSomeThing();

}
Copy the code
public class OrderDao implements Dao {

    @Override
    public void doSomeThing() {
        System.out.println("test"); }}Copy the code
public class OrderService {

    private Dao dao;

    public OrderService(Dao dao) {
        this.dao = dao;
    }

    public void test() { dao.doSomeThing(); }}Copy the code
  • Next, use containers for the benefit of mankind.
// The bootstrap class should be placed in the project root directory, Public class Main {public static void Main (String[] args) {Container Container = new Container(Main.class); OrderService service = container. GetBean (orderService.class); The (); / / to invoke the service }}Copy the code
@Component
public class OrderService {

    @Autowired
    private Dao dao;

    public void test() {
        dao.doSomeThing();
    }

    public Dao getDao() {
        return dao;
    }

    public void setDao(Dao dao) { this.dao = dao; }}Copy the code
@Component
public class OrderDao implements Dao {

    @Override
    public void doSomeThing() {
        System.out.println("test"); }}Copy the code
public interface Dao {

    void doSomeThing();

}
Copy the code
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Component {
}
Copy the code
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD})
public @interface Autowired {
}
Copy the code
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 void make() { classPaths.forEach(classPath -> { try { Class c = Class.forName(classPath); // Find the @ioc.componentannotated class and instantiate itif(c.isAnnotationPresent(Component.class)) { components.put(c, c.newInstance()); } } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { e.printStackTrace(); }}); } /** * inject dependencies */ 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 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(); }}})); } private void renderClassPaths(file file) {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); }}Copy the code

Afterword.

Some concepts are always thought to be clear in my mind, but when I actually use them or write them into words, I find there are many things I don’t understand. The purpose of this article is to sort out the concepts and make some notes. This time, I tried to implement IOC container. At the beginning of writing, I knew there was something wrong with my previous understanding. At least you’ve written a working version of the example in the article. Later you can refer to the implementation of Spring, estimated to learn a lot of things.

My blog address

The resources

  • Understanding inversion of control and dependency injection
  • I didn’t understand the jargon of those years — dependency inversion • inversion of control • dependency injection • interface oriented programming
  • Inversion of Control (IOC) and Dependency Injection (DI)