Spring技术原理之Spring IOC

依赖倒置原则: 依赖倒置的核心是面向接口编程

  1. 定义:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
  2. 问题由来:类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。
  3. 解决方案:将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率。

控制反转(Inversion of Control):

是依赖倒置原则的一种代码设计的思路。具体采用的方法就是所谓的依赖注入(Dependency Injection)。

image-20210531154233077

IoC Contain:

  1. 避免写大量的new来创建对象,将对象间的依赖关系,配置化。
  2. 创建实例的时候不需要了解具体的细节。

Spring Bean生产总体流程:

image-20210531154528351

Spring 是一个大的 Bean 工厂,创建Bean时要考虑如下问题:

  1. Bean定义。根据配置文件或者注解加载Bean定义到BeanDefinitionMap。
  2. 作用域。单例作用域或者原型作用域,单例的话需要全局实例化一次,原型每次创建都需要重新实例化。
  3. 依赖关系。一个 Bean 如果有依赖,我们需要初始化依赖,然后进行关联。如果多个 Bean 之间存在着循环依赖,A 依赖 B,B 依赖 C,C 又依赖 A,需要解这种循环依赖问题。

Bean 定义:

  1. 基于XML

    <bean id="userService" class="com.javhl.***.UserService" init-method="init" destory-method="destory"/>
    
  2. 基于注解

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

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

作用域:

image-20210531154900643

循环依赖问题:

image-20210531155242911

  1. 循环依赖根据注入方式分成两种类型:

    1. 构造器循环依赖。依赖的对象是通过构造器传入的,发生在实例化 Bean 的时候。
    2. 设值循环依赖。依赖的对象是通过 setter 方法传入的,对象已经实例化,发生属性填充和依赖注入的时候。
    3. 如果是构造器循环依赖,本质上是无法解决的。比如我们调用 A 的构造器,发现依赖 B,于是去调用 B 的构造器进行实例化,发现又依赖 C,于是调用 C 的构造器去初始化,结果依赖 A,整个形成一个死结, 导致 A 无法创建。如:A { public A(B b){}};B{public B(A a){}},A,B实例化时形成构造器循环依赖
    4. 如果是设值循环依赖,Spring框架只支持单例下的设值循环依赖。Spring 通过对还在创建过程中的单例,缓存并提前暴露该单例,使得其他实例可以引用该依赖。
  2. 原型模式和单例构造器循环依赖问题:

    image-20210531155434107

    1. 加载 A,记录 singletonsCurrentlyInCreation = [a],构造依赖 B,开始加载 B。
    2. 加载 B,记录 singletonsCurrentlyInCreation = [a, b],构造依赖 C,开始加载 C。
    3. 加载 C,记录 singletonsCurrentlyInCreation = [a, b, c],构造依赖 A,又开始加载 A
    4. 加载 A,检测到循环依赖,直接抛出异常结束操作
  3. 单例setter循环依赖解决方法:

    image-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. 采用三级缓存
    2. singletonObjects(一级缓存),单例缓存,存储已经实例化完成的单例,成品的Bean。
    3. earlySingletonObjects(二级缓存),提前暴露的单例缓存,这时候的单例刚刚创建完,后期还会注入依赖,存放半成品的Bean。
    4. singletonFactories(三级缓存),生产单例的工厂的缓存,存的是Bean工厂对象,用来生成半成品的Bean并放入到二级缓存中。用以解决循环依赖。如果Bean存在AOP的话,返回的是AOP的代理对象。为了解决二级缓存中 AOP 生成新对象的问题,Spring 中的解决方案就是提前 AOP。
    5. 从流程图上看,实际上注入 C的 A 实例,还在填充属性阶段,并没有完全地初始化。等递归回溯回去,A 顺利拿到依赖 B,才会真实地完成 A 的加载。

BeanFactory & FactoryBean:

  1. BeanFactory: 以Factory结尾,表示它是一个工厂类(接口), 它负责生产和管理bean的一个工厂。在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。BeanFactory只是个接口,并不是IOC容器的具体实现,但是Spring容器给出了很多种实现,如DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等,其中XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。
  2. FactoryBean: 一般情况下,Spring通过反射机制利用的class属性指定实现类实例化Bean,在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。FactoryBean接口对于Spring框架来说占用重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂Bean的细节,给上层应用带来了便利。从Spring3.0开始,FactoryBean开始支持泛型,即接口声明改为FactoryBean的形式
  3. 以Bean结尾,表示它是一个Bean,不同于普通Bean的是:它是实现了FactoryBean接口的Bean,根据该Bean的ID从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象,而不是FactoryBean本身,如果要获取FactoryBean对象,请在id前面加一个&符号来获取。
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();

猜你喜欢

转载自blog.csdn.net/a1774381324/article/details/120855863