通過各種裝配方式,幫助自己瞭解Spring容器在裝載的時候到底幹了什麼,以及容器在裝載的時候需要哪些東西?帶着問題熟悉一下。
Spring加載資源並進行裝配的過程,以XML的形式加載爲例
- 定義好Spring的配置文件
- 通過Resource對Spring的配置文件進行抽象,抽象成Resource對象
- 定義Bean的工廠
- 定義XMLBeanDefinitionReader對象,並將工廠作爲參數傳遞進去供後續回調使用
- 通過XMLBeanDefinitionReader讀取抽象出來的Resource對象
- 裝配完成,可以通過工廠獲取Bean
Resource,Spring對其內部使用到的資源全部抽象成Resource,通過Resource來封裝底層資源。
XMLBeanDefinitionReader是用來解析xml配置文件,最後裝配到Bean工廠。具體如何解析這邊不做詳細說明。
常見的裝配過程(不關注細節只關注過程)
bean.xml
1、DefaultListableBeanFactory
- Resource抽象Xml
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
//reader.loadBeanDefinitions(new ClassPathResource("bean.xml"));
reader.loadBeanDefinitions(new FileSystemResource("E:\\javaDev\\workspace\\tools\\src\\main\\resources\\bean.xml"));
factory.getBean("ccc");
解析:定義了一個DefaultListableBeanFactory工廠,並作爲參數傳入XMLBeanDefinitionReader,通過XMLBeanDefinitionReader讀取ClassPathResource或者FileSystemResource抽象出來的資源,從而完成裝載
- AnnotatedBeanDefinitionReader註冊Bean
DefaultListableBeanFactory factory3 = new DefaultListableBeanFactory();
AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(factory3);
//註冊指定對象
annotatedBeanDefinitionReader.register(AAA.class,BBB.class);
System.out.println(factory3.getBean("BBB"));
解析:註冊指定對象,即使AAA.class沒有Spring註解,也能註冊到工廠
- ClassPathBeanDefinitionScanner掃描包的方式註冊bean
DefaultListableBeanFactory factory3 = new DefaultListableBeanFactory();
ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner = new ClassPathBeanDefinitionScanner(factory3);
//掃描包註冊
classPathBeanDefinitionScanner.scan("com.tools.springDemo");
System.out.println(factory3.getBean("AAA"));
解析:ClassPathBeanDefinitionScanner掃描包下面帶註解的Bean,如果AAA沒有@Component或者其他Spring自動裝載的註解,則無法註冊到BeanFactory;即使AAA對象在其他@Configuration配置類中,通過@Bean聲明,也不會註冊到BeanFactory;
2、XMLBeanFactory
繼承自DefaultListableBeanFactory,在Spring3.1以後XmlBeanFactory類被廢除了
ClassPathResource classPathResource = new ClassPathResource("bean.xml");
XmlBeanFactory factory2 = new XmlBeanFactory(classPathResource);
factory2.getBean("ccc");
System.out.println("\n"+factory2.getBean("ccc"));
解析:資源抽象爲ClassPathResource,加載到XmlBeanFactory容器中,此處並沒有見到XMLBeanDefinitionReader或其他的BeanDefinitionReader;那是因爲XMLBeanFactory默認使用XMLBeanDefinitionReader讀取Resource。如下圖
3、應用上下文裝載
- AnnotationConfigApplicationContext ,javaConfig方式
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
ac.register(AppConfig.class);
ac.refresh();
AAA aaa = (AAA)ac.getBean("AAA");
System.out.println("\n[AAA] 獲取 AAA 對象:"+ac.getBean("AAA"));
- ClassPathXmlApplicationContext ,xml方式
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
applicationContext.getBean("ccc");
System.out.println(applicationContext.getBean("ccc"));
注意:ApplicationContext爲什麼也能實現容器的功能?
- 他們都繼承自AbstractApplicationContext抽象類,而AbstractApplicationContext實現了ConfigurableApplicationContext接口,ConfigurableApplicationContext接口中有一個待實現的獲取容器的方法,如下
ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
- 說白了,ApplicationContext內部持有一個DefaultListableBeanFactory來實現容器功能的。具體ApplicationContext作爲一個高級容器能幹什麼不闡述。
以上皆爲個人學習,如有問題請及時指出,謝謝!