Spring底层原理... 持续更新中

69 阅读4分钟

快捷键

Ctrl+Alt+U 类图, Ctrl+Alt+B 跳转到方法的实现,Ctrl+Shift+T 根据文件名搜索文件,Ctrl+O 显示一个类的所有方法

Ctrl+H 根据文件内容搜索文件

1. 容器接口

BeanFactory能做哪些事情?

ApplicationContext有哪些扩展功能?

事件解耦(ApplicationContext提供的)

到底什么是BeanFactory

它是ApplicationContext的父接口

它才是Spring的核心容器,主要的ApplicationContext实现都组合了它的功能。换句话说,ApplicationContext包含了一个BeanFactory变量,默认的实现类是DefaultListableBeanFactory,单例Bean(singletonObjects)

在SpringBoot Web中,context使用的是AnnotationConfigServletWebServerApplicationContext

BeanFactory能干点啥

表面上只有getBean

实际上控制反转,基本的依赖注入,直至Bean的生命周期的各种功能,都有它的实现类提供

主要实现类DefaultListableBeanFactory

2.png

单例Bean:DefaultSingletonBeanRegistry,重要属性 singletonObjects,包含所有的单例Bean,key是Bean的名字,value是Bean实例

private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

获取所有单例对象

先建2个类

package com.gjy.spring.a01;

import org.springframework.stereotype.Component;

@Component
public class Component1 {
}
package com.gjy.spring.a01;

import org.springframework.stereotype.Component;

@Component
public class Component2 {
}
package com.gjy.spring.a01;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultSingletonBeanRegistry;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

import java.lang.reflect.Field;
import java.util.Map;

@SpringBootApplication
public class A01App {

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

    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext context = SpringApplication.run(A01App.class, args);
        System.out.println(context);
// 主要是以下代码
        Field field = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
        field.setAccessible(true);
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        Map<String, Object> map = (Map<String, Object>) field.get(beanFactory);
        map.entrySet().stream().filter(e -> e.getKey().startsWith("component"))
                .forEach(e -> System.out.println(e.getKey() + "=" + e.getValue()));
    }
}

输出结果,省略掉其他内容了。

component1=com.gjy.spring.a01.Component1@1a891add
component2=com.gjy.spring.a01.Component2@5176d279

ApplicationContext比BeanFactory多了点啥

1.png

MessageSource:国际化资源能力

在 resources 目录下新建三个文件,注意文件名必须一致

// messages.properties
hi=hi
// messages_en.properties
hi=Hello
// messages_zh.properties
hi=你好
public static void main(String[] args) throws Exception {

    ConfigurableApplicationContext context = SpringApplication.run(A01App.class, args);

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

ResourcePatternResolver:通配符匹配资源能力,(磁盘路径、类路径)

多个资源:context.getResources(""); 单个资源:context.getResource("");

在 resources 目录下新建application.yml

spring:
  application:
    name: spring-theroy
// 类路径 classpath:   包含jar包 classpath*:
// 磁盘路径 file:
Resource[] resources = context.getResources("classpath:application.yml"); // "classpath*:META-INF/spring.factories"
System.out.println(Arrays.toString(resources));

ApplicationEventPublisher:发布事件对象

一种解耦方式,分离变与不变。如发短信,邮件,APP功能,不在代码层面写死,功能完成时,调用publishEvent方法。

会自动调用参数为自定义的Event类,可以编写多个@EventListener,实现不同的功能。

编写一个类实现ApplicationEvent类

package com.gjy.spring.a01;

import org.springframework.context.ApplicationEvent;

public class UserRegisterEvent extends ApplicationEvent {

    public UserRegisterEvent(Object source) {
        super(source);
    }
    
}

发送的代码

@SpringBootApplication
public class A01App {

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

    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext context = SpringApplication.run(A01App.class, args);
        //UserRegisterEvent里的值任意 
        context.publishEvent(new UserRegisterEvent(context));
    }
}

接受的代码

@Component
public class Component2 {

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

    @EventListener
    public void listener(UserRegisterEvent event) {
        log.info("event {}", event);
    }
}

EnvironmentCapable:Spring环境信息,(系统环境变量、.properties、.yml、环境信息)

// 不区分大小写
System.out.println(context.getEnvironment().getProperty("java_home"));
System.out.println(context.getEnvironment().getProperty("spring.application.name"));

学到了什么

BeanFactory和ApplicationContext不仅仅是简单的继承关系,ApplicationContext组合并扩展了BeanFactory功能。

一种新的功能解耦方式,注入ApplicationEventPublisher对象,完成事件发送功能,继承ApplicationEvent类,完成功能,给方法添加@EventListener完成事件的接受。

2. 容器实现

BeanFactory实现的特点

ApplicationContext常见实现和方法

内嵌容器和DispatcherServlet

BeanFactory实现

beanFactory不会做的事

  1. 不会主动调用BeanFactory后处理器
  2. 不会主动添加Bean后处理器
  3. 不会主动初始化单例
  4. 不会解析beanFactory,还不会解析 ${} 与 #{}
package com.gjy.spring.a01;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

public class BeanFactoryTest {

    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        // 添加一些 Bean 的定义(class,scope,初始化,销毁)
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class)
                .setScope("singleton").getBeanDefinition();
        beanFactory.registerBeanDefinition("config", beanDefinition);

        // 给 beanFactory 添加一些常用的后处理器,扩展。只是添加到Bean工厂
        // ConfigurationAnnotationProcessor,AutowiredAnnotationProcessor,CommonAnnotationProcessor,EventListenerProcessor,EventListenerFactory
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);

        // 执行上面注册的后处理器。
        // BeanFactory后处理器主要补充了一些bean定义  ConfigurationAnnotationProcessor
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values()
                .forEach(processor -> processor.postProcessBeanFactory(beanFactory));

        // bean后处理器, 针对bean生命周期的各个阶段提供扩展, 例如 @Autowired @Resource
        // AutowiredAnnotationProcessor,CommonAnnotationProcessor  建立与BeanFactory的联系
        beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);

        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        // 准备好所有单例
        beanFactory.preInstantiateSingletons();
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        System.out.println(beanFactory.getBean(Bean1.class).getBean2());
    }

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

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

    static class Bean1 {
        public Bean1() {
            System.out.println("构造器 Bean1");
        }

        @Autowired
        private Bean2 bean2;

        public Bean2 getBean2() {
            return bean2;
        }
    }

    static class Bean2 {
        public Bean2() {
            System.out.println("构造器 Bean2");
        }
    }
}

bean后处理器会有排序的逻辑

同一个对象既加了@Autowired又加了@Resource,@Autowired会生效。

与加入后处理器的顺序有关

AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
    def.setSource(source);
    beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}

// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
    def.setSource(source);
    beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}

ApplicationContext实现

classPathXmlApplicationContext

fileSystemXmlApplicationContext

annotationConfigApplicationContext

annotationConfigServletWebServerApplicationContext

b01.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 name="bean1" class="com.gjy.spring.a02.A02App.Bean1"/>

    <bean name="bean2" class="com.gjy.spring.a02.A02App.Bean2">
        <property name="bean1" ref="bean1"/>
    </bean>

</beans>
package com.gjy.spring.a02;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
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.mvc.Controller;

public class A02App {

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

    public static void main(String[] args) {
        // classPathXmlApplicationContext();
        // fileSystemXmlApplicationContext();

        /*DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        // reader.loadBeanDefinitions(new FileSystemResource(""));
        reader.loadBeanDefinitions(new ClassPathResource("b01.xml"));
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }*/

        // annotationConfigApplicationContext();
        annotationConfigServletWebServerApplicationContext();
    }

    private static void classPathXmlApplicationContext() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("b01.xml");
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }

    private static void fileSystemXmlApplicationContext() {
        String s = "D:\\code\\java\\microservice_spc\\spring5_theroy\\src\\main\\resources\\b01.xml";
        FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext(s);
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }

    private static void annotationConfigApplicationContext() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }

    private static void annotationConfigServletWebServerApplicationContext() {
        AnnotationConfigServletWebServerApplicationContext context =
                new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
    }

    @Configuration
    static class WebConfig {
        @Bean
        public ServletWebServerFactory servletWebServerFactory() {
            return new TomcatServletWebServerFactory();
        }

        @Bean
        public DispatcherServlet dispatcherServlet() {
            return new DispatcherServlet();
        }

        @Bean
        public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
            return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
        }

        @Bean("/hello")
        public Controller c() {
            return ((request, response) -> {
                response.getWriter().println("hello spring");
                return null;
            });
        }
    }

    @Configuration
    static class Config {

        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }
    }

    static class Bean1 {
    }

    static class Bean2 {
        private Bean1 bean1;

        public Bean1 getBean1() {
            return bean1;
        }

        public void setBean1(Bean1 bean1) {
            this.bean1 = bean1;
        }
    }
}