Spring源码学习

Spring源码学习

BeanFactory 与 ApplicationContext 的区别

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

代码演示

代码目录:
Spring源码学习_第1张图片
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 打开类关系图:

Spring源码学习_第2张图片

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

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

Spring源码学习_第3张图片

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

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

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

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

    • 所以此时取出的对象包含Spring容器本身自带的和我配置@Component的两个类
      Spring源码学习_第5张图片
      Spring源码学习_第6张图片
  • 5. 输出容器中名称前缀为compo的对象

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

在这里插入图片描述

ApplicationContext

Spring源码学习_第7张图片Spring源码学习_第8张图片

在这里插入图片描述

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);
    }
}

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

你可能感兴趣的:(Spring,Boot,spring,学习,java)