深度理解spring——BeanFactory的实现

BeanFactory

Spring之BeanFactory

什么是BeanFactory

BeanFactory是SpringApplication类的父类接口

BeanFactory才是Spring的核心容器,主要的SpringApplication类都组合了他的功能。

通过Ctrl+alt+u可以看到

可以从图片中看到SpringApplication是继承了BeanFactory接口对BeanFactory进行了功能性的扩展。

比如SpringApplication获取一个bean的对象

复制代码
       run.getBean(BreadRollMallServer.class);

他实际上是通过组合了BeanFactory实现找个获取对象的功能,可以看出来SpringApplication是间接的调用了BeanFactory的功能

ApplicationContext相对BeanFactory实现的功能性扩展

1. MessageSource

MessageSource 是 Spring 框架里用于消息解析与国际化的核心接口。借助它,你能够依据不同的语言环境获取对应的文本消息,从而实现国际化支持。像错误消息、提示信息这类文本内容,就可以通过 MessageSource 进行管理。

2. ResourcePatternResolver

ResourcePatternResolver 接口可用来解析资源路径,并且支持使用通配符来匹配多个资源。它是 ResourceLoader 的扩展,能够依据给定的资源路径模式查找多个资源。在加载配置文件、静态资源等场景中会经常用到。

3. ApplicationEventPublisher

ApplicationEventPublisher 接口提供了发布应用事件的功能。在 Spring 应用里,事件机制是一种重要的设计模式,允许组件之间以松耦合的方式进行通信。通过 ApplicationEventPublisher,你可以发布自定义的应用事件,其他组件可以监听这些事件并做出响应。

应用场景:用户注册时候的发短信发邮件。

4. EnvironmentCapable

EnvironmentCapable 接口表明一个对象具备获取 Environment 对象的能力。Environment 对象封装了应用程序运行时的环境信息,包含系统属性、环境变量、配置文件属性等。借助 Environment,你可以方便地获取和管理这些属性。

通用ApplicationContext实践实现BeanFactory

复制代码
public class TestBeanFactory {

    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        // bean 的定义(class(类型), scope(单例or多例), 初始化方法, 销毁方法)
		// BeanDefinitionBuilder..xxx.xxx.xxx.getBeanDefinition()
        AbstractBeanDefinition beanDefinition =
                BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
        //(beanName,xxx)将bean注册到bean工厂中
        beanFactory.registerBeanDefinition("config", beanDefinition);

        // 【重点】给 BeanFactory 添加一些常用的后处理器(对BeanFactory的扩展) 
        //将后处理添加到bean工厂
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);

        // BeanFactory 后处理器主要功能,补充了一些 bean 定义
        // beanFactory.getBeansOfType 根据类型获取多个bean
        //BeanFactoryPostProcessor.class拿到bean工厂的所有后处理器,对bean工厂做出扩展就可以解析@bean注解等。
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
        	//拿到bean工厂的所有后处理器并且执行
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);//执行BeanFactory后置处理器
        });
        
       // 添加 BeanPostProcessor  也就是添加bean的后处理器
       //bean后处理器 针对bean的生命周期各个阶段进行扩展,例如@Autowire @Resouse
        beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);

        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        
    }

    @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);
        @Autowired
        private Bean2 bean2;
    }

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

通过这个案例,你可以看到如何使用 DefaultListableBeanFactory 创建和管理 Bean,以及如何使用后置处理器在 Bean 的生命周期中执行自定义逻辑。

区别对比

  1. 作用时机
    BeanFactoryPostProcessor:在 BeanFactory 完成 Bean 定义的加载之后,但在 Bean 实例化之前执行。也就是说,它处理的是 Bean 的定义信息,而不是 Bean 实例。
    BeanPostProcessor:在 Bean 实例化之后,初始化前后执行。它作用于已经创建好的 Bean 实例。
  2. 作用对象
    BeanFactoryPostProcessor:作用于 BeanFactory 本身,主要用于修改 BeanFactory 中 Bean 的定义信息,例如修改 Bean 的属性值、作用域等。
    BeanPostProcessor:作用于具体的 Bean 实例,允许开发者在 Bean 初始化前后对其进行定制化处理。
  3. 功能侧重点
    BeanFactoryPostProcessor:侧重于对 Bean 定义的全局修改和扩展,例如动态添加或修改 Bean 定义,调整 Bean 的配置等。
    BeanPostProcessor:侧重于对 Bean 实例的个性化处理,例如对 Bean 进行增强、验证、日志记录等。

总结:

1.bean工厂不会主动调用beanFactory后处理器

2.bean不会主动添加后处理器

3.不会主动初始化单例

4.不会解析BeanFactory

BeanFactory后处理器排序让谁优先执行

第一种实现通过xml等方式实现的bean注入原理

通过xml注入bean容器

复制代码
  // ⬇️1.最为经典的容器,基于classpath 下 xml 格式的配置文件来创建
    public void testClassPathXmlApplicationContext() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring_bean.xml");
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println(context.getBean(Bean2.class).getBean1());
    }
第二种基于磁盘路径下 xml 格式的配置文件来创建
复制代码
        //基于磁盘路径下 xml 格式的配置文件来创建
        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 FileSystemResource("src\\main\\resources\\spring_bean.xml"));
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }
第三种较为经典的容器,基于java配置类来创建

较为经典的容器,基于java配置类来创建,通过这个配置类创建会帮我们创建后处理器了来解析@Bean注解

复制代码
   // ⬇️3.较为经典的容器,基于java配置类来创建
    public void testAnnotationConfigApplicationContext() {
        // 会自动加上5个后处理器
        // org.springframework.context.annotation.internalConfigurationAnnotationProcessor
        // org.springframework.context.annotation.internalAutowiredAnnotationProcessor
        // org.springframework.context.annotation.internalCommonAnnotationProcessor
        // org.springframework.context.event.internalEventListenerProcessor
        // org.springframework.context.event.internalEventListenerFactory
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println(context.getBean(Bean2.class).getBean1());
    }
// 单元测试的过程中如果要解析一些Spring注解,比如@Configuration的时候不要把相关类定义到写单元测试类的内部类,会读取不到
@Configuration
class Config {
    @Bean
    public Bean1 bean1() {
        return new Bean1();
    }

    @Bean
    public Bean2 bean2(Bean1 bean1) {
        Bean2 bean2 = new Bean2();
        bean2.setBean1(bean1);
        return bean2;
    }
}

class Bean1 {

}

class Bean2 {
    private Bean1 bean1;

    public Bean1 getBean1() {
        return bean1;
    }

    public void setBean1(Bean1 bean1) {
        this.bean1 = bean1;
    }
}
第四种较为经典的容器,基于java配置类来创建,并且还可以用于web环境
复制代码
   // 模拟了 springboot web项目内嵌Tomcat的工作原理
    public void testAnnotationConfigServletWebServerApplicationContext() throws IOException {
        AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
        // 防止程序终止
        System.in.read();
    }
    
@Configuration
class WebConfig {
    @Bean
    // 1. WebServer工厂
    public ServletWebServerFactory servletWebServerFactory() {
        return new TomcatServletWebServerFactory();
    }

    @Bean
    // 2. web项目必备的DispatcherServlet
    public DispatcherServlet dispatcherServlet() {
        return new DispatcherServlet();
    }

    @Bean
    // 3. 将DispatcherServlet注册到WebServer上
    public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet) {
        return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
    }

    @Bean("/hello")
    public Controller controller1() {
        return (request, response) -> {
            response.getWriter().println("hello");
            return null;
        };
    }
}
相关推荐
烛阴4 分钟前
Node.js中必备的中间件大全:提升性能、安全与开发效率的秘密武器
javascript·后端·express
南雨北斗8 分钟前
WMware虚拟机下载方法(2025年4月)
后端
朝阳58124 分钟前
Rust项目GPG签名配置指南
开发语言·后端·rust
微网兔子24 分钟前
伺服器用什么语言开发呢?做什么用什么?
服务器·c++·后端·游戏
朝阳58125 分钟前
Rust实现高性能目录扫描工具ll的技术解析
开发语言·后端·rust
zhang238390615432 分钟前
IDEA add gitlab account 提示
java·gitlab·intellij-idea·idea
小希爸爸1 小时前
2、中医基础入门和养生
前端·后端
牛马baby1 小时前
Java高频面试之并发编程-07
java·开发语言·面试
卓怡学长1 小时前
w304基于HTML5的民谣网站的设计与实现
java·前端·数据库·spring boot·spring·html5
YONG823_API1 小时前
深度探究获取淘宝商品数据的途径|API接口|批量自动化采集商品数据
java·前端·自动化