资讯详情

黑马程序员Spring视频教程,全面深度讲解spring5底层原理 学习笔记

介绍

代码仓库地址:https://gitee.com/CandyWall/spring-source-study 跟着做学习笔记,这个笔记和视频内容的项目名称和代码略有不同。我把49个代码的每个代码拆分成独立的springboot项目,项目名称尽可能知名,是基于我自己的考虑,代码已经验证,仅供参考。

视频教程地址:https://www.bilibili.com/video/BV1P44y1N7QG

注:

1. 每个对应一个二级标题,每个三级标题都是用子项目名命名的,与我的代码仓库项目一一对应; 2. 使用代码lombok插件来简化了Bean中的get()、set()使用方法和日志记录lombok的@Slf4j注解。

每个子项目对应的视频链接和一些重要内容的笔记

第一讲 BeanFactoryApplicationContext区别与联系

spring_01_beanfactory_applicationcontext_differences_connections

p1 000-Spring高级49讲-导学

p2 001-第一讲-BeanFactory与ApplicationContext_1

测试代码:

@SpringBootApplication @Slf4j public class A01Application { 
             public static void main(String[] args) { 
                 ConfigurableApplicationContext context = SpringApplication.run(A01Application.class, args);         // class org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext         System.out.println(context.getClass());     } } 

到底什么是BeanFactory

  • 它是ApplicationContext的父接口

    鼠标选中ConfigurableApplicationContext,按Ctrl Shift U或者Ctrl Alt U打开类图,可以看到ApplicationContext父接口是BeanFactory

    image-20220323144102451

  • 它才是 Spring 主要的核心容器 ApplicationContext 实现都 [组合]他的功能

    打印context.getClass(),可以看到SpringBoot返回启动程序ConfigurableApplicationContext具体实现类是AnnotationConfigServletWebServerApplicationContext

    ConfigurableApplicationContext context = SpringApplication.run(A01Application.class, args); // org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext System.out.println/span>(context.getClass()); 

    按图索骥,AnnotationConfigServletWebServerApplicationContext又间接继承了GenericApplicationContext,在这个类里面可以找到beanFactory作为成员变量出现。

p3 002-第一讲-BeanFactory功能

BeanFactory接口中的方法

查看springboot默认的ConfigurableApplicationContext类中的BeanFactory的实际类型

ConfigurableApplicationContext context = SpringApplication.run(A01Application.class, args);
// org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 查看实际类型
// class org.springframework.beans.factory.support.DefaultListableBeanFactory
System.out.println(beanFactory.getClass());

从打印结果可以了解到实际类型为DefaultListableBeanFactory,所以这里以BeanFactory的一个实现类DefaultListableBeanFactory作为出发点,进行分析。

它的类图如下:

这里我们暂且不细看DefaultListableBeanFactory,先看DefaultListableBeanFactory的父类DefaultSingletonBeanFactory,先选中它,然后按F12,可以跳转到对应的源码,可以看到有个私有的成员变量singletonObjects

这里通过反射的方法来获取该成员变量,进行分析

先补充一下反射获取某个类的成员变量的步骤:

获取成员变量,步骤如下:

  1. 获取Class对象

  2. 获取构造方法

  3. 通过构造方法,创建对象

  4. 获取指定的成员变量(私有成员变量,通过(boolean flag)方法暴力访问)

  5. 通过方法,给指定对象的指定成员变量赋值或者获取值

public void set(Object obj, Object value)

​ 在指定对象obj中,将此 Field 对象表示的成员变量设置为指定的新值

​ public Object get(Object obj)

​ 返回指定对象obj中,此 Field 对象表示的成员变量的值

代码如下:

Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
// 设置私有变量可以被访问
singletonObjects.setAccessible(true);
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
// 查看实际类型
// class org.springframework.beans.factory.support.DefaultListableBeanFactory
System.out.println(beanFactory.getClass());
map.entrySet().stream().filter(entry -> entry.getKey().startsWith("component")).forEach(System.out::println);

这里singletonObjects.get(beanFactory)为什么要传一个ConfigurableListableBeanFactory的变量进去呢?打印了这个beanFactory的实际类型为DefaultListableBeanFactory,查看其类图,可以了解到该类也实现了DefaultSingletonBeanRegistry接口,所以这里反射获取某个类的成员变量的get()方法中可以作为参数传进来。

p4 003-第一讲-ApplicationContext功能1

ApplicationContextBeanFactory 多点啥?

多实现了四个接口:

  • MessageSource: 国际化功能,支持多种语言
  • ResourcePatternResolver: 通配符匹配资源路径
  • EnvironmentCapable: 环境信息,系统环境变量,*.properties*.application.yml等配置文件中的值
  • ApplicationEventPublisher: 发布事件对象

  1. MessageSource

    resources目录下创建四个文件messages.propertesmessages_en.propertiesmessages_ja.propertiesmessages_zh.properties,然后分别在四个文件里面定义同名的key,比如在message_en.properties中定义hi=hello,在messages_ja.propertes中定义hi=こんにちは,在messages_zh中定义hi=你好,这样在代码中就可以根据这个**key hi语言类型**获取不同的value了。

    System.out.println(context.getMessage("hi", null, Locale.CHINA));
    System.out.println(context.getMessage("hi", null, Locale.ENGLISH));
    System.out.println(context.getMessage("hi", null, Locale.JAPANESE));
    

    运行结果如下:

p5 004-第一讲-ApplicationContext功能2,3

  1. ResourcePatternResolver

    例1:获取类路径下的messages开头的配置文件

    Resource[] resources = context.getResources("classpath:messages*.properties");
    for (Resource resource : resources) { 
              
        System.out.println(resource);
    }
    

    例2:获取spring相关jar包中的spring.factories配置文件

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

  2. EnvironmentCapable

    获取系统环境变量中的java_home和项目的application.yml中的server.port属性

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

p6 005-第一讲-ApplicationContext功能4

  1. ApplicationEventPublisher

    定义一个类,继承自ApplicationEvent

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

    再定义一个类,用于监听用户注册事件,类头上需要加@Component注解,将该类交给spring管理,定义一个处理事件的方法,参数类型为件类的对象,方法头上需要加上@EventListener注解

    @Component
    @Slf4j
    public class UserRegisteredListener { 
              
        @EventListener
        public void userRegist(UserRegisteredEvent event) { 
              
            System.out.println("UserRegisteredEvent...");
            log.debug("{}", event);
        }
    }
    

    接着再定义一个类,里面有个register(String username, String password)方法可以完成用户的注册,注册完毕后发布一下

    @Component
    @Slf4j
    public class UserService { 
              
        @Autowired
        private ApplicationEventPublisher context;
        public void register(String username, String password) { 
              
            log.debug("新用户注册,账号:" + username + ",密码:" + password);
            context.publishEvent(new UserRegisteredEvent(this));
        }
    }
    

    最后在Springboot启动类中调用一下UserService里面的register()方法注册一个新用户,UserRegisteredListener中就能处理这个用户注册完毕的事件,实现了UserService类和UserRegisteredListener类的解耦。

    UserService userService = context.getBean(UserService.class);
    userService.register("张三", "123456");
    

p7 006-第一讲-小结

第二讲 BeanFactoryApplicationContext 类的重要实现类

spring_02_01_beanfactory_impl

p8 007-第二讲-BeanFactory实现

p9 008-第二讲-BeanFactory实现

p10 009-第二讲-BeanFactory实现-后处理器排序

DefaultListableBeanFactory

接着第一讲中的内容,执行以下代码,可以了解到

ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
// org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 查看实际类型
// class org.springframework.beans.factory.support.DefaultListableBeanFactory
System.out.println(beanFactory.getClass());

ConfigurableApplicationContext类内部组合的BeanFactory实际类型为DefaultListableBeanFactoryspring底层创建实体类就是依赖于这个类,所以它是BeanFactory接口最重要的一个实现类,下面使用这个类,模拟一下spring使用DefaultListableBeanFactory类创建其他实体类对象的过程。

测试代码如下:

package top.jacktgq.spring_02_beanfactory_impl;

import lombok.extern.slf4j.Slf4j;
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;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.stream.Collectors;

/** * @Author CandyWall * @Date 2022/3/24--21:20 * @Description */
public class TestBeanFactory { 
        
    public static void main(String[] args) { 
        
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        // bean 的定义(即bean的一些描述信息,包含class:bean是哪个类,scope:单例还是多例,初始化、销毁方法等)
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
        beanFactory.registerBeanDefinition("config", beanDefinition);
        // 给 BeanFactory添加一些常用的后处理器,让它具备解析@Configuration、@Bean等注解的能力
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
        // 从bean工厂中取出BeanFactory的后处理器,并且执行这些后处理器
        // BeanFactory 后处理器主要功能,补充了一些 bean 的定义
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> { 
        
            System.out.println(beanFactoryPostProcessor);
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        });
        // 打印BeanFactory中Bean
        for (String name : beanFactory.getBeanDefinitionNames()) { 
        
            System.out.println(name);
        }

        // 从BeanFactory中取出Bean1,然后再从Bean1中取出它依赖的Bean2
        // 可以看到结果为null,所以@Autowired注解并没有被解析
        // Bean1 bean1 = beanFactory.getBean(Bean1.class);
        // System.out.println(bean1.getBean2());

        // 要想@Autowired、@Resource等注解被解析,还要添加Bean的后处理器,可以针对Bean的生命周期的各个阶段提供扩展
        // 从bean工厂中取出Bean的后处理器,并且执行这些后处理器
        // BeanFactory 后处理器主要功能,补充了一些 bean 的定义
        // beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);
        // beanFactory.addBeanPostProcessors(beanFactory.getBeansOfType(BeanPostProcessor.class).values());
        // 改变Bean后处理器加入BeanFactory的顺序
        // 写法1:
        // ArrayList<BeanPostProcessor> list = new ArrayList<>(beanFactory.getBeansOfType(BeanPostProcessor.class).values());
        // Collections.reverse(list);
        // beanFactory.addBeanPostProcessors(list);
        // 写法2:
        beanFactory.addBeanPostProcessors(beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream().sorted(beanFactory.getDependencyComparator()).collect(Collectors.toCollection(ArrayList::new)));

        // 准备好所有单例,get()前就把对象初始化好
        beanFactory.preInstantiateSingletons();
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        Bean1 bean1 = beanFactory.getBean(Bean1.class);
        System.out.println(bean1.getBean2());

        /** * 学到了什么: * a. beanFactory 不会做的事 * 1. 不会主动调用BeanFactory的后处理器 * 2. 不会主动添加Bean的后处理器 * 3. 不会主动初始化单例 * 4. 不会解析BeanFactory,还不会解析 ${}, #{} * * b. Bean后处理器会有排序的逻辑 */
        System.out.println(bean1.getInter());
    }

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

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

        @Bean
        public Bean3 bean3() { 
        
            return new Bean3();
        }

        @Bean
        public Bean4 bean4() { 
        
            return new Bean4();
        }
    }

    @Slf4j
    static class Bean1 { 
        
        @Autowired
        private Bean2 bean2;

        public Bean2 getBean2() { 
        
            return bean2;
        }

        @Autowired
        @Resource(name = "bean4")
        private Inter bean3;

        public Inter getInter() { 
        
            return bean3;
        }

        public Bean1() { 
        
            log.debug("构造 Bean1()");
        }
    }

    @Slf4j
    static class Bean2 { 
        
        public Bean2() { 
        
            log.debug("构造 Bean2()");
        }
    }

    interface Inter { 
        

    }

    @Slf4j
    static class Bean3 implements Inter { 
        
        public Bean3() { 
        
            log.debug("构造 Bean3()");
        }
    }

    @Slf4j
    static class Bean4 implements Inter { 
        
        public Bean4() { 
        
            log.debug("构造 Bean4()");
        }
    }
}

总结:

  • beanFactory 不会做的事

    • 不会主动调用BeanFactory的后处理器

    • 不会主动添加Bean的后处理器

    • 不会主动初始化单例

    • 不会解析BeanFactory,还不会解析 ${}, #{}

  • Bean后处理器会有排序的逻辑

    先定义一个接口Inter,再定义两个Bean,名称分别为Bean3和Bean4,都继承Inter,接着在Config中通过@Bean注解将Bean3和Bean4都加进Bean工厂中,然后在Bean1中定义一个Inter对象,通过@Autowired注解将实现类注入进来。

    @Configuration
    static class Config { 
              
        @Bean
        public Bean1 bean1() { 
              
            return new Bean1();
        }
    
        @Bean
        public Bean2 bean2() { 
              
            return new Bean2();
        }
    
        @Bean
        public Bean3 bean3() { 
              
            return new Bean3();
        }
    
        @Bean
        public Bean4 bean4() { 
              
            return new Bean4();
        }
    }
    
    @Slf4j
    static class Bean1 { 
              
        @Autowired
        private Bean2 bean2;
    
        public Bean2 getBean2() { 
              
            return bean2;
        }
    
        @Autowired
        @Resource(name = "bean4")
        private Inter bean3;
    
        public Inter getInter() { 
              
            return bean3;
        }
    
        public Bean1() { 
              
            log.debug("构造 Bean1()");
        }
    }
    
    @Slf4j
    static class Bean2 { 
              
        public Bean2() { 
              
            log.debug("构造 Bean2()");
        }
    }
    
    interface Inter { 
              
    
    }
    
    @Slf4j
    static class Bean3 implements Inter { 
              
        public Bean3() { 
              
            log.debug("构造 Bean3()");
        }
    }
    
    @Slf4j
    static class Bean4 implements Inter { 
              
        public Bean4() { 
              
            log.debug("构造 Bean4()");
        }
    }
    

    如果把以Inter接口声明的变量名定义为inter@Autowired注解首先会**根据名称(byName)根据类型(byType)**进行匹配,发现Bean3和Bean4都实现了Inter接口,会报无法自动装配的错误。

    所以为了避免这种错误,以Inter接口声明的变量名只能为bean3或者bean4,这里把以Inter接口声明的变量名定义为bean3

标签: p150光电传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台