栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

spring进阶学习记录

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

spring进阶学习记录

1.第一讲:BeanFactory与ApplicationContext的区别与联系
@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 + Alt + U打开类图,可以看到ApplicationContext的有个父接口是BeanFactory

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

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

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

2.第一讲:BeanFactory的功能

BeanFactory可以做什么?

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

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,他能管理所有的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 对象表示的成员变量的值

Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
// 设置私有变量可以被访问
singletonObjects.setAccessible(true);
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
Map map = (Map) 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()方法中可以作为参数传进来。

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

 3.第一讲:ApplicationContext功能1

ApplicationContext 比 BeanFactory 多点啥?

多实现了四个接口:

  • 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了

使用:

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

运行结果:

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

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

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

 

3.EnvironmentCapable

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

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

5.第一讲:ApplicationContext功能4 4.ApplicationEventPublisher

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

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

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

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

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

@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");

6.第一讲小结

Spring学习记录

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1024886.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号