Spring IOC de Spring Technology Principio

Principio de inversión de dependencia : el núcleo de la inversión de dependencia es la programación orientada a la interfaz

  1. Definición: Los módulos de alto nivel no deben depender de los módulos de bajo nivel, ambos deben depender de sus abstracciones; las abstracciones no deben depender de los detalles; los detalles deben depender de las abstracciones.
  2. El origen del problema: La clase A depende directamente de la clase B. Si quieres cambiar la clase A para que dependa de la clase C, debes modificar el código de la clase A para lograrlo. En este escenario, la clase A es generalmente un módulo de alto nivel responsable de la lógica comercial compleja; la clase B y la clase C son módulos de bajo nivel responsables de las operaciones atómicas básicas; si se modifica la clase A, traerá riesgos innecesarios al programa.
  3. Solución: Modifique la clase A para que dependa de la interfaz I, la clase B y la clase C implementan la interfaz I respectivamente, y la clase A contacta indirectamente con la clase B o la clase C a través de la interfaz I, lo que reducirá en gran medida la probabilidad de modificar la clase A.

Inversión de Control :

Es una idea de diseño de código basada en el Principio de Inversión de Dependencia. El método específico utilizado es el llamado Inyección de Dependencia.

imagen-20210531154233077

IoC contiene :

  1. Evite escribir muchos objetos nuevos para crear y configure dependencias entre objetos.
  2. No necesita conocer los detalles al crear una instancia.

El proceso general de producción de Spring Bean :

imagen-20210531154528351

Spring es una gran fábrica de frijoles. Al crear frijoles, tenga en cuenta los siguientes aspectos:

  1. Definición de frijol. Cargue las definiciones de Bean en BeanDefinitionMap según los archivos de configuración o las anotaciones.
  2. alcance. Ámbito de singleton o ámbito de prototipo, singleton debe instanciarse globalmente una vez, y el prototipo debe volver a instanciarse cada vez que se crea.
  3. dependencias Si un Bean tiene dependencias, necesitamos inicializar las dependencias y luego asociarlas. Si hay una dependencia circular entre múltiples beans, A depende de B, B depende de C y C depende de A, y este problema de dependencia circular debe resolverse.

Definición de frijol :

  1. basado en XML

    <bean id="userService" class="com.javhl.***.UserService" init-method="init" destory-method="destory"/>
    
  2. basado en anotaciones

    @Component:当对组件的层次难以定位的时候使用这个注解
    @Controller:表示控制层的组件
    @Service:表示业务逻辑层的组件
    @Repository:表示数据访问层的组件
    
  3. Basado en JavaConfig

    @Configuration
    public class JavaConfigBeanTest {
          
          
        @Bean
        public BeanTest beanTest(){
          
          
            BeanTest beanTest = new BeanTest();
            beanTest.setTestField("I am a beanTest");
            return beanTest;
        }
    }
    

Alcance :

imagen-20210531154900643

Problema de dependencia circular :

imagen-20210531155242911

  1. Las dependencias circulares se dividen en dos tipos según el método de inyección:

    1. Dependencias circulares del constructor . Los objetos dependientes se pasan a través del constructor, lo que sucede cuando se crea una instancia del bean.
    2. Establecer dependencias circulares de valor . El objeto dependiente se pasa a través del método setter, el objeto ha sido instanciado, cuando ocurre el llenado de propiedades y la inyección de dependencia.
    3. Si se trata de una dependencia circular del constructor, es esencialmente irresoluble . Por ejemplo, llamamos al constructor de A y encontramos que depende de B, entonces llamamos al constructor de B para instanciación y encontramos que depende de C, entonces llamamos al constructor de C para inicializar, y el resultado depende de A, que forma un nudo muerto, lo que hace que A sea incapaz de crear. Tales como: A { public A(B b){}};B{public B(A a){}}, cuando se crea una instancia de A, B, se forma una dependencia circular del constructor
    4. Si se trata de una dependencia circular de valor establecido, Spring Framework solo admite dependencias circulares de valor establecido bajo un singleton . Spring almacena en caché y expone el singleton por adelantado al almacenar en caché el singleton que aún está en proceso de creación, de modo que otras instancias puedan hacer referencia a la dependencia.
  2. Patrón prototipo y problema de dependencia circular del constructor singleton:

    imagen-20210531155434107

    1. Cargue A, registre singletonsCurrentlyInCreation = [a], construya la dependencia B y comience a cargar B.
    2. Cargue B, registre singletonsCurrentlyInCreation = [a, b], construya la dependencia C y comience a cargar C.
    3. Cargue C, registre singletonsCurrentlyInCreation = [a, b, c], construya la dependencia A y comience a cargar A nuevamente
    4. Cargue A, detecte una dependencia circular y lance directamente una excepción para finalizar la operación
  3. Solución de dependencia circular de setter Singleton:

    imagen-20210531155600284

    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
          
          
        // 查询缓存中是否有创建好的单例
        Object singletonObject = this.singletonObjects.get(beanName);
        // 如果缓存不存在,判断是否正在创建中
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
          
          
            // 加锁防止并发
            synchronized (this.singletonObjects) {
          
          
                // 从earlySingletonObjects中查询是否有early缓存
                singletonObject = this.earlySingletonObjects.get(beanName);
                // early缓存也不存在,且允许early引用
                if (singletonObject == null && allowEarlyReference) {
          
          
                    // 从单例工厂Map里查询beanName
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
          
          
                        // singletonFactory存在,则调用getObject方法拿到单例对象
                        singletonObject = singletonFactory.getObject();
                        // 将单例对象添加到early缓存中
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        // 移除单例工厂中对应的singletonFactory
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return (singletonObject != NULL_OBJECT ? singletonObject : null);
    }
    
    1. caché L3
    2. singletonObjects (caché de primer nivel), caché de singleton, almacena el singleton que se ha instanciado, el bean terminado.
    3. earlySingletonObjects (caché de segundo nivel), el caché de singleton expuesto de antemano, el singleton se acaba de crear en este momento y las dependencias se inyectarán más tarde para almacenar beans semiacabados.
    4. singletonFactories (caché de tercer nivel), el caché de fábricas que producen singletons, almacena objetos de fábrica de Bean, que se utilizan para generar beans semiacabados y colocarlos en el caché de segundo nivel. para resolver dependencias circulares. Si hay AOP en el bean, devuelve el objeto proxy de AOP. Para resolver el problema de que AOP genera nuevos objetos en el caché de segundo nivel, la solución en Spring es avanzar en AOP.
    5. Del diagrama de flujo, la instancia de A que realmente se inyecta en C todavía está en la etapa de llenado de propiedades y no se ha inicializado por completo. Cuando la recursión retrocede y A obtiene con éxito la dependencia B, la carga de A se habrá completado realmente.

BeanFactory y FactoryBean :

  1. BeanFactory : termina en Factory, lo que indica que es una clase de fábrica (interfaz), que se encarga de producir y administrar una fábrica de frijoles. En Spring, BeanFactory es la interfaz central del contenedor IOC y sus responsabilidades incluyen: crear instancias, ubicar, configurar objetos en la aplicación y establecer dependencias entre estos objetos. BeanFactory es solo una interfaz, no una implementación específica del contenedor IOC, pero el contenedor Spring proporciona muchas implementaciones, como DefaultListableBeanFactory, XmlBeanFactory, ApplicationContext, etc.
  2. FactoryBean : En general, Spring usa el atributo de clase usado por el mecanismo de reflexión para especificar la clase de implementación para instanciar beans. En algunos casos, el proceso de instanciar beans es complicado. Si se usa el método tradicional, se necesita una gran cantidad de información de configuración. que se proporcionará en el Bean. La flexibilidad del método de configuración es limitada y se puede obtener una solución simple utilizando el método de codificación. Spring proporciona una interfaz de clase de fábrica de org.springframework.bean.factory.FactoryBean para este propósito, y los usuarios pueden personalizar la lógica de creación de beans implementando esta interfaz. La interfaz de FactoryBean ocupa una posición importante para el marco Spring, y Spring mismo proporciona más de 70 implementaciones de FactoryBean. Ocultan los detalles de la creación de instancias de algunos beans complejos y brindan comodidad a las aplicaciones de capa superior. Desde Spring 3.0, FactoryBean comenzó a admitir genéricos, es decir, la declaración de la interfaz se cambió a la forma de FactoryBean
  3. Terminar con un Bean significa que es un Bean, que es diferente de los Beans ordinarios: es un Bean que implementa la interfaz FactoryBean.De acuerdo con la ID del Bean, el objeto obtenido de BeanFactory es en realidad el objeto devuelto por getObject () del FactoryBean, no del FactoryBean en sí, si desea obtener el objeto FactoryBean, agregue un ampersand delante del id para obtenerlo.
public interface BeanFactory {
    
    
    String FACTORY_BEAN_PREFIX = "&";
    Object getBean(String var1) throws BeansException;
    <T> T getBean(String var1, Class<T> var2) throws BeansException;
    Object getBean(String var1, Object... var2) throws BeansException;
    <T> T getBean(Class<T> var1) throws BeansException;
    <T> T getBean(Class<T> var1, Object... var2) throws BeansException;
    boolean containsBean(String var1);
    boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;
    boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;
    boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;
    boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;
    Class<?> getType(String var1) throws NoSuchBeanDefinitionException;
    String[] getAliases(String var1);
}

public interface FactoryBean<T> {
    
    
    T getObject() throws Exception;
    Class<?> getObjectType(); 
    boolean isSingleton(); 
} 

//FactoryBean实例
@Component public class FactoryBeanTest implements FactoryBean{
    
    
    private String type=”a”; 
    @Override
    public Object getObject() throws Exception {
    
     
        if("a".equals(type)){
    
     
            return new A(); 
        }else{
    
    
            return new B(); 
        } 
    }
    @Override public Class getObjectType() {
    
     
        if("a".equals(type)){
    
     
            return A.class; 
        }else{
    
    
            return B.class; 
        } 
    }
    @Override public boolean isSingleton() {
    
     
        return true; 
    } 
}

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("testBeans.xml");
String[] names = applicationContext.getBeanDefinitionNames();
Arrays.stream(names).forEach(e->System.out.println(e));
//此处获取的是类A的实例
Object realBean = applicationContext.getBean("factoryBeanTest");
System.out.println(realBean.getClass().getName());
//此处获取的是FactoryBeanTest的实例
FactoryBeanTest factoryBeanTest = (FactoryBeanTest)
applicationContext.getBean("&factoryBeanTest");
((ClassPathXmlApplicationContext) applicationContext).close();

Supongo que te gusta

Origin blog.csdn.net/a1774381324/article/details/120855863
Recomendado
Clasificación