栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring高级篇-容器和Bean

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring高级篇-容器和Bean

1. 容器接口
  1. BeanFactory能做哪些事
  2. ApplicationContext有哪些扩展功能
  3. 事件解耦
1.1 BeanFactory和ApplicationContext

BeanFactory是ApplicationContext的父接口,它才是Spring的核心容器,提供getBean的能力
主要的子类ApplicationContext是组合了BeanFactory的功能。它扩展了 BeanFactory 接口的功能,如:

  • 国际化
  • 通配符方式获取一组 Resource 资源
  • 整合 Environment 环境(能通过它获取各种来源的配置信息)
  • 事件发布与监听,实现组件之间的解耦
1.2 BeanFactory能做什么

表面上只有 getBean
实际上控制反转、基本的依额注入、直至 Bean 的生命周期的各种功能,都由它的实现类提供
可以查看类org.springframework.beans.factory.support.DefaultListableBeanFactory

可以看到BeanFactory只是DefaultListableBeanFactory实现的一个很小的类,提供getBean的功能。

父类作用
SingletonBeanRegistry注册单例
HierarchicalBeanFactory父子容器
ListableBeanFactory列出容器中所有Bean
BeanDefinitionRegistry注册新的Bean
DefaultSingletonBeanRegistry管理单例对象,容器三级缓存就在这个类里面
1.3 ApplicationContext多了什么功能

ApplicationContext的实现类可以查看org.springframework.context.ConfigurableApplicationContext

父类功能
MessageSource资源国际化
ResourcePatternResolver通配符匹配资源(类路径、磁盘路径)
ApplicationEventPublisher事件发布器,发布事件监听事件的能力
EnvironmentCapable读取环境变量的能力,在yaml、properties文件中读取
1.4 国际化
  1. ApplicationContext 中 MessageSource bean 的名字固定为 messageSource
  2. 使用 SpringBoot 时,国际化文件名固定为 messages
  3. 空的 messages.properties 也必须存在
public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();

        context.registerBean("messageSource", MessageSource.class, () -> {
            ResourceBundleMessageSource ms = new ResourceBundleMessageSource();
            ms.setDefaultEncoding("utf-8");
            ms.setBasename("messages");
            return ms;
        });

        context.refresh();

        System.out.println(context.getMessage("hi", null, Locale.ENGLISH));
        System.out.println(context.getMessage("hi", null, Locale.CHINESE));
    }

IDEA需要修复File Encoding为UTF-8编码格式,Locale.CHINA的信息可以从游览器的请求头带过来

1.5 事件发布器

定义事件

@Slf4j
public class UserRegisteredEvent extends ApplicationEvent {

    public UserRegisteredEvent(Object source) {
        super(source);
        log.info("用户注册事件:{}", source);
    }
}

发布事件

@Autowired
    private ApplicationEventPublisher context;

    public void register() {
        log.debug("用户注册");
        context.publishEvent(new UserRegisteredEvent(this));
    }
2. 容器实现
  1. BeanFactory实现的特点
  2. ApplicationContext的常见实现和用法
  3. 内嵌容器、注册DispatcherServlet

常见的容器实现类

功能
DefaultListableBeanFactory是 BeanFactory 最重要的实现,像控制反转和依赖注入功能,都是它来实现
ClassPathXmlApplicationContext从类路径查找 XML 配置文件,创建容器(旧)
FileSystemXmlApplicationContext从磁盘路径查找 XML 配置文件,创建容器(旧)
XmlWebApplicationContext传统 SSM 整合时,基于 XML 配置文件的容器(旧)
AnnotationConfigWebApplicationContext传统 SSM 整合时,基于 java 配置类的容器(旧)
AnnotationConfigApplicationContextSpring boot 中非 web 环境容器(新)
AnnotationConfigServletWebServerApplicationContextSpring boot 中 servlet web 环境容器(新)
AnnotationConfigReactiveWebServerApplicationContextSpring boot 中 reactive web 环境容器(新)

另外要注意的是,后面这些带有 ApplicationContext 的类都是 ApplicationContext 接口的实现,但它们是组合了 DefaultListableBeanFactory 的功能,并非继承而来

BeanFactory实现

手动创建Bean

Bean的定义

@Configuration
static class Config {
   @Bean
   public Bean1 bean1() {
       return new Bean1();
   }

   @Bean
   public Bean2 bean2() {
       return new Bean2();
   }

   
}

static class Bean1 {
   private static final Logger log = LoggerFactory.getLogger(Bean1.class);

   public Bean1() {
       log.debug("构造 Bean1()");
   }
   @Autowired
   private Bean2 bean2;

   public Bean2 getBean2(){
       return bean2;
   }
 
}

static class Bean2 {
   private static final Logger log = LoggerFactory.getLogger(Bean2.class);

   public Bean2() {
       log.debug("构造 Bean2()");
   }
}

创建和注册Bean

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// bean 的定义(class, scope, 初始化, 销毁)
AbstractBeanDefinition beanDefinition =
        BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
//注册Bean
beanFactory.registerBeanDefinition("config", beanDefinition);
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
    System.out.println(beanDefinitionName);
}

打印结果:config。
为什么Config中的Bean1、Bean2都没有注册上去呢?因为解析@Configuration、@Bean的功能需要添加额外的后置处理器

// 给 BeanFactory 添加一些常用的后处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);

打印结果:

为什么还是没有打印出Bean1、Bean2?
因为上面只是将解析注解的类加入到Bean工厂中,但是还没有生效

// BeanFactory 后处理器主要功能,补充了一些 bean 定义
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
    //执行Bean工厂后置处理器
    beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
System.out.println("========== 添加完后置处理器后 ===========");
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
    System.out.println(beanDefinitionName);
}
System.out.println(beanFactory.getBean(Bean1.class).getBean2());

执行完BeanFactory的后置处理器后可以打印出Bean1、Bean2,但是通过Bean1获取Bean2为什么是null?

这是因为@Autowired、@Resource是Bean的后置处理器实现的功能,针对Bean的生命周期各个阶段提供扩展功能

添加Bean的后置处理器

// Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ...
        beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);
        System.out.println("========== 添加完Bean后置处理器后 ===========");

        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        //提前准备好所有的单例对象
        beanFactory.preInstantiateSingletons();
        System.out.println(beanFactory.getBean(Bean1.class).getBean2());
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/885102.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号