Spring的BeanFactory与ApplicationContext

写在前面(感慨):笔者曾在十一月份通过了字节跳动的三次面试, 但是最终因为疫情原因不能满足公司的入职时间要求, 没有拿到offer。近期也是投递了大量大厂的实习岗, 但是要么已读不回, 要么明确告诉我学历至少要硕士(天天被阿里cpu)。说实话一直以为自己能靠技术吃饭, 过去的几年里, 我学过很多技术, 从最开始的C/C++、Python到Php, Java, C#, 当然不只是语言层面, 也包括很多对应的框架, 像C++的cocos2dx、Python的Scrapy、C#的Unity等等, 最终还是选择了Java这条赛道。 我知道竞争很激烈, 我也从未停歇过, 一年里除去玩的时间可能也就两个月, 其他时间都是从早到晚的学(甚至五点多起床六点就到教室坐着看书), b站Java有关的视频我都看过, 也有自己买过培训班的课程, 相关的技术书籍更是看过少说二三十本, 有些还是来来回回看了几遍, 各种框架源码, 甚至于JVM源码也是常常钻研。但是这些好像不够, 至少说, 对于当下如此内卷, 本科生学历已经远远跟不上很多大厂的要求, 就连我之前通过字节三面的部门, leader也是让尽量捞研究生简历。有时候真的很累很想放弃, 我的志向并不是想做什么技术专家, 只是因为做技术钱多, 家里缺钱, 仅此而已。马上开学大三下了, 考研也就剩不到一年了, 未来何去何从呢, 暂且不知(三月再决定吧), 可能考研, 可能运气好拿到个大厂实习然后就这样到毕业。。。。。。
但不管怎么样, 接下来的时间笔者将与大家一起努力! 披星戴月路过山水万城,祝自己与温柔重逢。

1. BeanFactory与ApplicationContext等接口关系

BeanFactoryApplicationContext并不仅仅只是继承关系,

BeanFactoryApplicationContext的一个成员变量, 二者为组合关系。并在原有基础上进行了增强功能, 见2

DefaultSingletonBeanRegistry 管理了所有的单例Bean对象 – 存储在singletonObjects这个map
↑ 实现
DefaultListableBeanFactoryApplicationContext中实际的BeanFactory实现类

下面是获取DefaultSingletonBeanRegistry中管理单例Bean对象的singletonObjects示例:

@SpringBootApplication
public class SpringSourceStudyApplication {

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

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        ConfigurableApplicationContext context = SpringApplication.run(SpringSourceStudyApplication.class, args);
        Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
        singletonObjects.setAccessible(true);
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //一级缓存, 单列Bean对象的Map, 来自DefaultSingletonBeanRegistry
        Map<String, Object> singletonObjectsMap = (Map<String, Object>) singletonObjects.get(beanFactory);
        singletonObjectsMap.forEach((k,v)->{
            System.out.println(k + "====" + v);
        });
    }
}

2. ApplicationContext实现的四个功能接口

MessageSource: 具有处理国际化的能力

ResourcePatternResolver: 具有处理资源通配符的能力

/* 示例 */
Resource[] resources1 = context.getResources("classpath:application.properties");
Resource[] resources2 = context.getResources("classpath*:META-INFO/spring.factories");//*号会将jar包也进行扫描

EnvironmentCapable: 具有处理环境信息的能力

/* 示例 */
context.getEnvironment().getProperty("java_home");	//不区分大小写
context.getEnvironment().getProperty("server.port");	

ApplicationEventPublisher: 具有发布事件的能力

/* 示例 */
//先定义一个自定义事件
public class UserRegiseredEvent extends ApplicationEvent{
    public UserRegisteredEvent(Object source){super(source);}
} 
//发布事件
context.publishEvent(new UserRegisteredEvent(context));

//在类中定义要接收事件的方法
@Component
public class Componenet2{
    private static final Logger log = LoggerFactory.getLogger(Component2.class);
    
    @EventListener
    public void aaa(UserRegisteredEvent event){
        log.debug("{}", event);
    }
}

3. BeanFactory的默认实现(DefaultListableBeanFactory)

BeanFactory的默认实现是DefaultListaleBeanFactory

但是DefaultListableBeanFactory是空的, 什么后置处理器都没有, 不会去解析@Configuration, ${}等等,

ApplicationContext则增加了对BeanFactory的这些流程处理

/* 示例 */

public class TestBeanFactory {
    public static void main(String[] args){
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();	//刚创建好没有任何的Bean和BeanDefinition
//要添加Bean的话必须通过添加BeanDefinition(Bean定义), 因为bean是beanFactory通过IOC控制反转创建的
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
        //注册bd到BeanFactory
        beanFactory.registerBeanDefinition("config", beanDefinition);
        //以下for循环只会打印config, 说明Config这个Bean还没有被解析(如@Configuration, @Bean等注解的解析), 是由另外的类来提供解析功能的
        for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        //给BeanFactory添加一些常用的后置处理器(BeanFactoryPostProcessor, BeanPostProcess), 就是对BeanFactory的扩展, 如解析@Configuration等注解
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
//        org.springframework.context.annotation.internalConfigurationAnnotationProcessor(BeanFactoryPostProcessor)   解析@Configuration
//        org.springframework.context.annotation.internalAutowiredAnnotationProcessor(BeanPostProcess)   解析@Autowired
//        org.springframework.context.annotation.internalCommonAnnotationProcessor(BeanPostProcess)  解析@Resource
//        org.springframework.context.event.internalEventListenerProcessor
//        org.springframework.context.event.internalEventListenerFactory
        for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        //执行beanFactory中的beanFactory后置处理器, 从而达到扩展BeanFactory功能的目的
        Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
        beanFactoryPostProcessorMap.values().stream().forEach(beanFactoryPostProcessor -> {
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        });
        System.out.println("=================");
        for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        //此时依赖注入仍然没有, 可以看打印结果, bean1中没有成功注入bean2
//        Bean1 bean = beanFactory.getBean(Bean1.class);
//        System.out.println(bean.bean2);
        //加入beanFactory中的beanFactory后置处理器, 从而达到扩展BeanFactory功能的目的
        Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);
        beanPostProcessorMap.values().forEach(beanFactory::addBeanPostProcessor);
        //再次获取Bean, getBean->doGetBean->createBean -> doCreateBean -> populateBean...会调用这些BeanPostProcessor, 完成依赖注入
        Bean2 bean2 = beanFactory.getBean(Bean1.class).bean2;
        System.out.println(bean2);
        System.out.println("==================");
        beanFactory.preInstantiateSingletons(); //准备好所有的单例Bean
    }


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

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

    static class Bean1{
        private static Logger log = LoggerFactory.getLogger(Bean1.class);
        @Autowired
        Bean2 bean2;
        public Bean1(){log.debug("构造Bean1()");}
    }

    static class Bean2{
        private static Logger log = LoggerFactory.getLogger(Bean1.class);
        public Bean2(){log.debug("构造Bean2()");}
    }
}

4. ApplicationContext的多种实现

import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebApplicationContext;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ApplicationContextImpl {
    public static void main(String[] args) throws InterruptedException {
        //testClassPathXmlApplicationContext();
        //testFileSystemXmlApplicationContext();
        //testAnnotationConfigApplicationContext();
        //testAnnotationConfigServletWebServerApplicationContext();
    }
    //经典的Spring容器, 基于XML
    private static void testClassPathXmlApplicationContext(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("aci.xml");
        for (String beanDefinitionName : context.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        System.out.println(context.getBean(Bean2.class).getBean1());
    }
    //基于磁盘路径下xml格式的配置文件来创建
    private static void testFileSystemXmlApplicationContext(){
        //FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("D:\\java\\spring-source-study\\src\\main\\resources\\aci.xml");绝对路径
        FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("src\\main\\resources\\aci.xml"); //相对路径
        for (String beanDefinitionName : context.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        System.out.println(context.getBean(Bean2.class).getBean1());
    }
    static class Bean1{}
    static class Bean2{
        private Bean1 bean1;
        public void setBean1(Bean1 bean1){
            this.bean1 = bean1;
        }
        public Bean1 getBean1(){
            return bean1;
        }
    }

    //较为经典的容器, 基于java配置类来创建
    private static void testAnnotationConfigApplicationContext(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        for (String beanDefinitionName : context.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        System.out.println(context.getBean(Bean2.class).getBean1());
    }
    @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;
        }
    }
    // 基于Java配置类来创建, 用于web环境
    private static void testAnnotationConfigServletWebServerApplicationContext(){
        AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);

    }
    //供testAnnotationConfigServletWebServerApplicationContext()测试用
    @Configuration
    static class WebConfig {
        //由这个工厂负责创建servletWebServer
        @Bean
        public ServletWebServerFactory servletWebServerFactory() {
            return new TomcatServletWebServerFactory();
        }
        //前端控制器
        @Bean
        public DispatcherServlet dispatcherServlet(){
            return new DispatcherServlet();
        }
        //servlet是需要注册在tomcat上的, 还需要绑定注册一下
        @Bean
        public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet){
            return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
        }

        //添加一个控制器测试用, 以"/"开头则会被识别为访问路径
        @Bean("/hello")
        public Controller controller1(){
            return (request, response) -> {
                response.getWriter().print("hello");
                return null;
            };
        }
    }
}

附带xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="bean1" class="com.yadong.springsourcestudy.chapter1.ApplicationContextImpl.Bean1"/>
    <bean id="bean2" class="com.yadong.springsourcestudy.chapter1.ApplicationContextImpl.Bean2">
        <property name="bean1" ref="bean1"/>
     </bean>
</beans>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浔汐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值