Preliminary understanding of IOC container

Posted by CircularStopSign on Wed, 02 Mar 2022 01:35:10 +0100

1,IOC

Inverse of Control – IOC, control reversal, reversing the control of the object to Spring!

Using IOC can solve the problem of high coupling of programs

Control reversal

Suppose I need a function. In this function, I need to call the service layer, and then call the dao layer to get the data. Traditional Java EE development directly creates a new service and then a new dao. In spring, the new process is handed over to the spring framework. It means that I give the right to create resources to the spring framework, which is called control inversion.

decoupling

Just now we said that the creation of resources was entrusted to spring, so I can find it whenever I need it. This process is like engineering mode. But in the spring framework, which objects it needs to create, it needs a configuration file. This configuration file tells spring which resources need to be created.

eg: suppose I need to go to the database to query the data display page

When the program starts, the spring framework looks for the configuration file to create resources, places the resources in a container, starts running, front-end data requests, looks for the controller layer in spring, then looks for the service layer, and then looks for the dao layer for data. Finally, the data is returned to the controller and displayed on the page. The service is injected into the controller layer by spring, and the dao layer is injected into the service layer by spring. The division of labor in this process is clear, and each layer performs its own duties. In a traditional development, new is directly in the servlet, then the data is checked, and then the data is returned to the interface. In case of operating more than one judgment and querying different tables, the code of this servlet becomes very bloated. Not to mention the slow development, it's hard for you to read the code after development. So control inversion can be used to decouple.

0. Configure spring with xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    <bean id="student" class="com.tian.bean.pojo.Student">
        <property name="name" value="zhangsan"></property>
    </bean>

</beans>

1. Load the IOC container as a companion file

After creating a Configuration class and adding it to @ Configuration, the class becomes a Configuration class and is put into the Bean container

package com.tian.bean.config;

import org.springframework.context.annotation.Configuration;

// The configuration file annotation tells spring that this is a configuration class
@Configuration
public class MyConfig {

}

However, the methods in this class will not be directly put into the IOC container. You need to use the @ Bean annotation method to put them into the IOC container

package com.tian.bean.config;

import org.springframework.context.annotation.Configuration;

// The configuration file annotation tells spring that this is a configuration class
@Configuration
public class MyConfig {

    @Bean(name = {"student1"})
    public Student student(){
        return new Student("Zhang San", 19);
    } 
}

According to the above code, the method student annotated by @ Bean can be put into the IOC container. The method name is the id of the method in the container. If you want to change an id for the method, you can click the source code of @ Bean, and we can see it

package org.springframework.context.annotation;

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

import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.support.AbstractBeanDefinition;

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {

	/**
	 * The name of this bean, or if plural, aliases for this bean. If left unspecified
	 * the name of the bean is the name of the annotated method. If specified, the method
	 * name is ignored.
	 */
	String[] name() default {};
    
}

The name attribute of the Bean container receives a string array, so you can use @ Bean(name = {"student1"}) to modify the id of the original method when returning to the source code

The IOC container defaults to the singleton mode. After the IOC container is created, the object of the instance has been put into the container, so every time we take the object out of the container is an object.

package com.tian.bean.test;

import com.tian.bean.config.MyConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.Arrays;

public class MyConfigTest1DomeTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext appc = new AnnotationConfigApplicationContext(MyConfig.class);
        Arrays.stream(appc.getBeanDefinitionNames()).sequential().forEach(System.out::println);
        Object student1 = appc.getBean("student");
        Object student2 = appc.getBean("student");
        System.out.println(student1 == student2);
    }
}
>>> true

However, if @ Scope("prototype") is added to the method, the method will become a multi instance mode, and the same object of getBean() in the container will be different every time.

Execution sequence: since the singleton mode is created only once, all objects in the singleton mode will be put into the container after the IOC container is created, while those in the multi instance mode will be called only when used.

Conditional judgment
package com.tian.bean.conditional;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class ConditionalLinux implements Condition {
    /**
     * ConditionContext: Determine the context in which the condition can be used
     * AnnotatedTypeMetadata: Annotation information
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // Get bean factory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        // Get class loader
        ClassLoader classLoader = context.getClassLoader();
        // Determine whether it is a windows system
        String property = context.getEnvironment().getProperty("os.name");
        // Get the registration class defined by the bean
        BeanDefinitionRegistry registry = context.getRegistry();

        if ("Linux".equals(property)) {
            return true;
        }

        return false;
    }
}
package com.tian.bean.conditional;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class ConditionalWindows implements Condition {
    /**
     * ConditionContext: Determine the context in which the condition can be used
     * AnnotatedTypeMetadata: Annotation information
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // Get bean factory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        // Get class loader
        ClassLoader classLoader = context.getClassLoader();
        // Determine whether it is a windows system
        String property = context.getEnvironment().getProperty("os.name");
        // Get the registration class defined by the bean
        BeanDefinitionRegistry registry = context.getRegistry();

        if ("Windows 8.1".equals(property)) {
            return true;
        }

        return false;
    }
}
package com.tian.bean.test;

import com.tian.bean.config.ConditionalTest;
import com.tian.bean.pojo.ConditionalPojo;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

import java.util.Arrays;
import java.util.Map;


public class ConditionalPojoTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ConditionalTest.class);

        // Gets the value of the environment variable
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        System.out.println(environment.getProperty("os.name"));

        // Get the contents of the bean object
        Map<String, ConditionalPojo> beansOfType = applicationContext.getBeansOfType(ConditionalPojo.class);
        System.out.println(beansOfType);

        // View the objects in the bean container according to the type of class
        String[] beanNamesForType = applicationContext.getBeanNamesForType(ConditionalPojo.class);
        Arrays.stream(beanNamesForType).sequential().forEach(System.out::println);
    }
}
@Import (class name. class)

Quickly import a component into the container

Use FactoryBean()

Summary:

If and add classes to the Bean container

/**
 * To register a component in a container:
 * 1,Package scanning + annotation (@ Controller,@Service,@Component) other customized need to use @ Component annotation
 * 2,@Bean[name={""}]
 * 3,@Import(Class name class)
 * - @Import()
 * - @ImportSelector:Import the selector and return an array of strings
 * - @ImportBeanDefinitionRegistrar:
 * 4,Use factorybean (project Bean) provided by Spring
 * - The factory Bean obtains the returned object by default
 * - To get the factory itself, you need to add a & representation to it
 */

2. Bean lifecycle

The process from Bean creation to initialization to destruction. The Bean life cycle is managed by the container.

1. Specify initialization and destruction methods

Init method and destruction method

2. Use annotations to specify lifecycle initialization and destruction methods

@Bean(initMethod = "init",destroyMethod = "detory")
public Test test() {
    return new Test();
}

Initialization: call after the object is created and assigned

Destroy: when the container is about to close, single instance beans will be destroyed, but multi instance beans will not be destroyed

3. Let the Bean implement the InitializingBean and DisposableBean interfaces, and define initialization and destruction

package com.tian.bean.pojo;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

@Component
public class Cat implements InitializingBean, DisposableBean {
    @Override
    public void destroy() throws Exception {
        System.out.println("cat Destroy");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("cat establish");
    }
}

4. The initialization and destruction methods are defined using PostConstruct and PreDestory defined in the JSR250 specification

package com.tian.bean.pojo;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class Dog {
    public Dog() {
        System.out.println("Dog Nonparametric structure");
    }

    // After the object is created and assigned, it is called.
    @PostConstruct
    public void init() {
        System.out.println("init Method called");
    }

    @PreDestroy
    public void destory() {
        System.out.println("destory Method called");
    }
}

5. BeanPostProcessor is the processing operation before and after Bean initialization

  • postProcessBeforeInitialization
  • postProcessAfterInitialization
package com.tian.bean.pojo;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class Car implements BeanPostProcessor {
    public Car() {
        System.out.println("------Car Nonparametric structure-----");
    }

    /**
     * Called before initialization
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization call");
        return bean;
    }

    /**
     * Called after initialization
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization Called");
        return bean;
    }
}

Topics: Java Spring ioc