Administrator
发布于 2021-08-14 / 679 阅读
0
0

Spring - IoC

Spring 的依赖查找

  1. 根据Bean名称查找
  • 实时查找:获得BeanFactory后,直接获取Bean
  • 延迟查找:延迟依赖查找主要用于获取 BeanFactory 后,不马上获取相关的 Bean,不是延迟加载Bean
  1. 根据Bean类型查找
  • 单个Bean对象
  • 集合Bean对象
  1. 根据Bean名称+类型查找

  2. 根据Java注解查找

  • 单个Bean对象
  • 集合Bean对象

Spring 的依赖注入

关键注解:@Autowrite

  1. 根据Bean名称注入
  2. 根据Bean类型注入
  • 单个Bean对象
  • 集合Bean对象
  1. 注入容器内建对象
  2. 注入非Bean对象
  3. 注入类型
  • 实时注入
  • 延迟注入

Spring的依赖来源

依赖来源

  • 自定义Bean:XML配置或注解定义的Bean
  • 容器内建Bean对象:由容器创建的普通的Bean
  • 容器内建依赖:通过AutowireCapableBeanFactory中的#resolveDependency方法来注册,不是一个普通Bean,无法通过依赖查找获取

BeanFactory和ApplicationContext,谁才是Spring Ioc的容器?

    public static void main(String[] args) {
        //假设在Bean.xml中,已经写了配置注入BeanFactory
        BeanFactory beanFactoryFromXML = new ClassPathXmlApplicationContext("classpath:/META-INF/bean.xml");
        //获取容器里的BeanFactory
        BeanFactory beanFactoryFromIoC = beanFactoryFromXML.getBean(BeanFactory.class);
        //可以看到 == 时,beanfactoryFromIoC并不等于beanfactoryFromXML
        System.out.println(beanFactoryFromIoC == beanFactoryFromXML);
        //false
        System.out.println(beanFactoryFromXML);
        //org.springframework.context.support.ClassPathXmlApplicationContext@574caa3f
        //说明依赖查找时的真实容器是ClassPathXmlApplicationContext
    }

为什么从容器内获得的BeanFactory不等于new容器时返回的BeanFactory
来看看ApplicationContext的抽象实现类AbstractApplicationContext以及实现类GenericApplicationContext

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
    //专注于getBean方法,这是依赖查找的主要API
    public Object getBean(String name) throws BeansException {
        //校验BeanFactory是否在激活状态
        this.assertBeanFactoryActive();
        //可以看到,ApplicationContext是先获取BeanFactory后,再调用BeanFactory的getBean方法 
        //那BeanFactory又是从哪里来的?继续看看源代码
        return this.getBeanFactory().getBean(name);
    }

    //getBeanFactory是一个抽象方法,看看子类GenericApplicationContext对其的实现
    public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}

//通用的ApplicationContext实现,不再是抽象类或接口
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
    //有一个为DefaultListableBeanFactory类型的属性
    private final DefaultListableBeanFactory beanFactory;

    //实现了父类的getBeanFactory方法,并且从自身属性返回了一个BeanFactory
    public final ConfigurableListableBeanFactory getBeanFactory() {
        return this.beanFactory;
    }
}

//DefaultListableBeanFactory本身也是BeanFactory的实现者
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
}
  • 首先ApplicationContext实现了BeanFactory,因此拥有了BeanFactory的能力,
  • 采用了组合的模式,将BeanFactory做为自己的属性
  • 当外部调用getBean等属于BeanFactory的能力时,实际是使用了属性中的BeanFactory,有点代理的味道了

其实这么做事很有道理的,ApplicationContext提供更多企业级的能力,专注点在于扩展而不是容器重实现

ApplicationContext is BeanFactory,都是Spring的IoC,但是new ClassPathXmlApplicationContext时的BeanFactory与容器内的BeanFactory,不是同一个对象

ApplicationContext 除了IoC,还提供的功能

  • 面向切面(AOP)
  • 配置元信息(Configuration Metadata)
  • 资源管理(Resources)
  • 事件(Evens)
  • 国际化(i8n)
  • 注解(Annotation)
  • Environment抽象(Environment Abstract)

问题:使用Spring容器,选择BeanFactory还是ApplicationContext?

未完待续…


附:BeanFactory体系的最终实现类 - DefaultListableBeanFactory的类图
Description
附:ApplicationContext体系的最终实现类 - AnnotationConfigApplicationContext的类图
Description


评论