Spring源码学习

Spring源码学习

BeanFactory 与 ApplicationContext 的区别
  • BeanFactory 接口,典型功能有getBean()
  • ApplicationContext 接口,是 BeanFactory 的子接口。它扩展了 BeanFactory 接口的功能,如:
    • 国际化
    • 通配符方式获取一组 Resource 资源
    • 整合 Environment 环境(能通过它获取各种来源的配置信息)
    • 事件发布与监听,实现组件之间的解耦
代码演示

代码目录:
在这里插入图片描述
A01

@SpringBootApplication
@Slf4j
public class A01 {
    public static void main(String[] args) throws Exception{
        ConfigurableApplicationContext context = SpringApplication.run(A01.class);
         /*
            1. 到底什么是 BeanFactory
                - 它是 ApplicationContext 的父接口
                - 它才是 Spring 的核心容器, 主要的 ApplicationContext 实现都【组合】了它的功能
         */
        System.out.println("context:" + context);


        /*
            2. BeanFactory 能干点啥
                - 表面上只有 getBean
                - 实际上控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能, 都由它的实现类提供
         */
        Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
        singletonObjects.setAccessible(true);
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        Map<String,Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
        map.entrySet().stream().filter(e->e.getKey().startsWith("compo")).forEach((e)->{
            System.out.println(e.getKey() + "=" + e.getValue());
        });

        /*
            3. ApplicationContext 比 BeanFactory 多点啥
         */
        System.out.println(context.getMessage("hi",null, Locale.JAPANESE));
        System.out.println(context.getMessage("hi",null, Locale.ENGLISH));

        Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
        for (Resource resource : resources) {
            System.out.println(resource);
        }

        System.out.println(context.getEnvironment().getProperty("java_home"));
        System.out.println(context.getEnvironment().getProperty("server.port"));

        context.getBean(Component1.class).register();

    }
         /*
            4. 学到了什么
                a. BeanFactory 与 ApplicationContext 并不仅仅是简单接口继承的关系, ApplicationContext 组合并扩展了 BeanFactory 的功能
                b. 又新学一种代码之间解耦途径
         */
}

Component1

@Component
public class Component1 {

    @Resource
    private ApplicationEventPublisher context;

    public void register(){
        System.out.println("用户注册");
        context.publishEvent(new UserRegisteredEvent(this));
    }
}

Component2

@Component
public class Component2 {
    @EventListener
    public void aaa(UserRegisteredEvent event){
        System.out.println("event:" + event);
        System.out.println("发送短信");
    }
}

UserRegisteredEvent

public class UserRegisteredEvent extends ApplicationEvent {
    public UserRegisteredEvent(Object source) {
        super(source);
    }
}

代码看不懂 不要着急

代码详解
BeanFactory 与 ApplicationContext 类图

鼠标移动到ConfigurableApplicationContext上,shift + alt + u 打开类关系图:

在这里插入图片描述

根据类图可以看出:ApplicationContext比BeanFactory多4个继承接口,分别为:

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

在这里插入图片描述

  • 1.通过DefaultSingletonBeanRegistry(默认单例Bean注册表)反射拿到属性singletonObjects(一级缓存)

    • DefaultSingletonBeanRegistry管理者Spring中Bean的注入
    • singletonObjects为一级缓存 其与三级缓存(singletonFactoryies),二级缓存(earlySingletonObjects)是为了解决Spring循环依赖而产生
      在这里插入图片描述
  • 2.反射中暴力破解该对象,使其能够调用对应的方法,属性

  • 3.通过context调用getBeanFactory()得到beanFactory属性

    • getBeanFactory()是BeanFactory类下的一个方法
    • ApplicationContext继承BeanFactory,则通过方法名直接调用
    • ConfigurableListableBeanFactory也继承于BeanFactory
  • 4. 通过get当前beanFactory对象,从一级容器中取出对象

    • 所以此时取出的对象包含Spring容器本身自带的和我配置@Component的两个类
      在这里插入图片描述
      在这里插入图片描述
  • 5. 输出容器中名称前缀为compo的对象

    • 当前容器存在多个对象(在一级缓存中,对象注入都是以类名小写)
    • filter -> 筛选类名前缀(startsWith)是compo的 并循环打印

在这里插入图片描述

ApplicationContext

在这里插入图片描述在这里插入图片描述

在这里插入图片描述

ApplicationEventPublisher 事件发布与监听,实现组件之间的解耦

context.getBean(Component1.class).register();

@Component
public class Component1 {

    @Resource
    private ApplicationEventPublisher context;

    public void register(){
        System.out.println("用户注册");
        // 事件发布
        context.publishEvent(new UserRegisteredEvent(this));
    }
}

@Component
public class Component2 {
	// 这里的注解 表示事件监听 监听对象是UserRegisteredEvent
    @EventListener
    public void aaa(UserRegisteredEvent event){
        System.out.println("event:" + event);
        System.out.println("发送短信");
    }
}

// 这里需要继承ApplicationEvent 
public class UserRegisteredEvent extends ApplicationEvent {
    public UserRegisteredEvent(Object source) {
        super(source);
    }
}

完结撒花!愿每一位程序员少走弯路是我创作的初心!如需博客文章代码,请私信

  • 22
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 18
    评论
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

孤居自傲

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

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

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

打赏作者

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

抵扣说明:

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

余额充值