• spring进阶学习记录


    1.第一讲:BeanFactory与ApplicationContext的区别与联系

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

    什么是BeanFactory?

    • 它是ApplicationContext的父接口

    鼠标选中ConfigurableApplicationContext,按Ctrl + Alt + U打开类图,可以看到ApplicationContext的有个父接口是BeanFactory

    • 是Spring的核心容器,主要的ApplicationContext实现都组合了它的功能(继承了BeanFactory和其它)

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

    image-20220404140925587

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

    image-20220404141152288

    2.第一讲:BeanFactory的功能

    BeanFactory可以做什么?

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

    BeanFactory接口中的方法

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

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

    从打印结果可以了解到实际类型为DefaultListableBeanFactory,他能管理所有的bean,其中,继承的类或接口有1.注册单例,2.父子容器,3. 列出容器中的所有bean,4.注册新的bean

    DefaultListableBeanFactory的父类DefaultSingletonBeanFactory是单例对象的管理

     此属性存放了所有的单例集合,利用反射获取查看这个属性。

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

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

    获取Class对象

    获取构造方法

    通过构造方法,创建对象

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

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

    public void set(Object obj, Object value)

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

    ​ public Object get(Object obj)

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

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

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

    singletonObjects存储了单例的map集合,ConfigurableListableBeanFactory是对所有bean对象的管理

    image-20220324003636506

     3.第一讲:ApplicationContext功能1

    ApplicationContext 比 BeanFactory 多点啥?

    image-20220324115647260

    多实现了四个接口:

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

    1.MessageSource的应用

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

    使用:

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

    运行结果:

    image-20220324181409040

    4.第一讲:ApplicationContext功能2,3

    2.ResourcePatternResolver

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

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

    image-20220324182456169

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

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

     image-20220324183236048

    3.EnvironmentCapable

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

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

    image-20220324191740825

    5.第一讲:ApplicationContext功能4

    4.ApplicationEventPublisher

    定义一个用户注册事件类,继承自ApplicationEvent类

    1. public class UserRegisteredEvent extends ApplicationEvent {
    2. public UserRegisteredEvent(Object source) {
    3. super(source);
    4. }
    5. }

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

    1. @Component
    2. @Slf4j
    3. public class UserRegisteredListener {
    4. @EventListener
    5. public void userRegist(UserRegisteredEvent event) {
    6. System.out.println("UserRegisteredEvent...");
    7. log.debug("{}", event);
    8. }
    9. }

    再定义一个用户服务类,用于注册后的一些操作,注册完成后,发布用户注册事件。

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

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

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

    image-20220324210306704

    6.第一讲小结

    Spring学习记录

  • 相关阅读:
    Go 语言运算符
    Java线程安全问题
    STM32外部复位IC与看门狗冲突,无法复位问题解决方案
    报错:Error: The project seems to require yarn but it‘s not installed解决方案
    数据库备份与恢复
    主机jvisualvm连接到tomcat服务器查看jvm状态
    20 行为型模式-策略模式
    [附源码]Python计算机毕业设计SSM开放式实验室预约系统(程序+LW)
    电容笔和触控笔有什么区别?值得入手电容笔品牌推荐
    卖不动的 iPhone 16?苹果被曝销量不达预期,甚至旧 iPhone 也能体验 Apple Intelligence!...
  • 原文地址:https://blog.csdn.net/m0_53077601/article/details/125848433