一、BeanFactory与ApplicationContext的区别与联系
BeanFactory是ApplicationContext的父接口
它是Spring的核心容器,主要的ApplicationContext实现都【组合】了它的功能
BeanFactory实际上是ApplicationContext的成员变量
表面上只有getBean,实际上控制反转、基本的依赖注入、直至Bean的生命周期的各种功能,都由它的实现类提供
二、容器实现
1.BeanFactory实现的特点
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//bean的定义(class,scope,初始化,销毁)
AbstractBeanDefinition beanDefinition =
BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope(“singleton”).getBeanDefinition();
beanFactory.registerBeanDefinition(“config”, beanDefinition);
//给BeanFactory添加一些常用的后处理器,将后处理器加到BeanFactory中
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
//获取内置后处理器
//beanFactory后处理器主要功能,补充了一些bean定义
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().stream().forEach(beanFactoryPostProcessor -> {
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
//Bean 后处理器 ,针对bean的生命周期的各个阶段提供扩展,例如 @Autowired @Resource 这里是建立BeanFactory和后处理器的联系
beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
//提前准备好所有单例对象
beanFactory.preInstantiateSingletons();
System.out.println(beanFactory.getBean(Bean1.class).getBean2());
}
学到了什么:
beanFactory 不会做的事
不会主动调用BeanFactory后处理器
不会主动添加Bean后处理器
不会主动初始化单例
不会解析BeanFactory 还不会解析${}与#{}
bean后处理器会有排序的逻辑
2.ApplicationContext的常见实现和用法
四个ApplicationContext接口的实现类:
ClassPathXmlApplicationContext
FileSystemXmlApplicationContext
AnnotationConfigApplicationContext
AnnotationConfigServletWebServerApplicationContext
四个接口的测试代码如下:
//较为经典的容器,基于classpath下xml格式的配置文件来创建
private static void testClassPathXmlApplicationContext(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(“b01.xml”);
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean2.class).getBean1());
}
//基于磁盘路径下xml格式的配置文件来创建
private static void testFileSystemXmlApplicationContext(){
FileSystemXmlApplicationContext context
= new FileSystemXmlApplicationContext("src\\main\\resources\\b01.xml");
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean2.class).getBean1());
}
//较为经典的容器,基于java配置类来实现
private static void testAnnotationConfigApplicationContext(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean2.class).getBean1());
}
//较为经典的容器,基于 java 配置类来创建,用于web环境
private static void testAnnotationConfigServletWebServerApplicationContext(){
AnnotationConfigServletWebServerApplicationContext context =
new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
}
@Configuration
static class WebConfig{
@Bean
public ServletWebServerFactory servletWebServerFactory(){
return new TomcatServletWebServerFactory();
}
@Bean
public DispatcherServlet dispatcherServlet(){
return new DispatcherServlet();
}
@Bean
public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet){
return new DispatcherServletRegistrationBean(dispatcherServlet,"/");
}
@Bean("/hello")
public Controller controller1(){
return (request,response) -> {
response.getWriter().print("hello");
return null;
};
}
}
@Configuration
static class Config{
@Bean
public Bean1 bean1(){
return new Bean1();
}
@Bean
public Bean2 bean2(Bean1 bean1){
Bean2 bean2 = new Bean2();
bean2.setBean1(bean1);
return bean2;
}
}
static class Bean1{}
static class Bean2{
private Bean1 bean1;
public void setBean1(Bean1 bean1) {
this.bean1 = bean1;
}
public Bean1 getBean1() {
return bean1;
}
}
ClassPathXmlApplicationContext的内部实现:
//内部实现
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
System.out.println(“读取之前…”);
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(“读取之后…”);
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(new ClassPathResource(“b01.xml”));
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
(FileSystemXmlApplicationContext和ClassPathXmlApplicationContext的内部实现基本类似,导入xml文件方式不同)
学到了什么:
常见的ApplicationContext容器实现
内嵌容器、DispatcherServlet的创建方法、作用