Spring底层分析-1.ApplicationContext

一.ApplicationContext和BeanFactory

 1. ApplicationContext是BeanFactory的子接口,

实现了BeanFactory的一些方法,例如getBean()

b76f3b60472d4d6cb883093681b51409.png

 

ConfigureableApplicationContext继承了ApplicationContext

88010d02bb5c41bebbffda3a9114cb48.png

2.BeanFactory的功能

1.BeanFactory才是Bean的核心容器

2.ApplicationContext是BeanFactory的组合

BeanFactory的功能很少,他的一个主要实现类DefaultListenableBeanFactory实现了大量方法

9dfbcf221b3c4c5bbbdfbb964c28f0f4.png

可以看到这里有很多实现类和接口,他们实现了大量的Spring容器中的方法

我们主要看一下DefaultSingletonBeanRegistry

3.DefaultSingletonBeanRegistry

5f7f232bd2754a70bd018a218fd4019e.png

这里的singletonObjects是Bean的底层集合,里面装着被Spring容器管理的Bean对象

我们来获取一下这个map:

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

        Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
        //暴力破解
        singletonObjects.setAccessible(true);
        //获取beanFactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //获取bean的map集合
        Map<String,Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
        //遍历map集合
        map.forEach((k,v)->{
            System.out.println(k+"="+v);
        });

因为bean太多了,我们这里仅将我们自己写的@Compont组件遍历出来

@Component
public class Component1 {

    private String name;

}


@Component
public class Component2 {

    private String name;

}
map.entrySet().stream().filter(e->e.getKey().startsWith("component"))
                .forEach(e->{
                    System.out.println(e.getKey()+"="+e.getValue());
                });

运行结果:

component1=com.example.springioc.component.Component1@25c5e994
component2=com.example.springioc.component.Component2@ 

 这样就能看到我们自己定义的Bean了!

二.ApplicationContext的功能

看一下它继承图

614a6550162b4753817ccdad652948d1.png

 1.MessageSource接口

该接口主要是用来实现国际化,为不同语言翻译

先准备三份不同语言的配置文件

messages_zh.properties

hi=你好

messages_en.properties

hi=hello

messages_ja.properties

hi=こんにちは


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

这样就可以获取到配置文件中不同语言的值

2.RscourcePatternReslover接口

该接口提供的方法getResources()获取资源文件

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

获取所有的spring.factories文件

URL [jar:file:/C:/Users/JJH/.m2/repository/org/springframework/boot/spring-boot/2.6.13/spring-boot-2.6.13.jar!/META-INF/spring.factories]
URL [jar:file:/C:/Users/JJH/.m2/repository/org/springframework/spring-beans/5.3.23/spring-beans-5.3.23.jar!/META-INF/spring.factories]
URL [jar:file:/C:/Users/JJH/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.6.13/spring-boot-autoconfigure-2.6.13.jar!/META-INF/spring.factories]
 

3.EnvironmentCapable接口

 该接口提供getEnvironment()方法获取环境变量以及配置文件中的值

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

E:\java
8081

 4.ApplicationEventPublisher接口

该接口提供了发布事件的功能

1.先写一个用户注册功能,需要继承ApplicationEvent

public class UserRegisterEvent extends ApplicationEvent {


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

2.发布事件

  context.publishEvent(new UserRegisterEvent(context));

3.监听事件

@Component
public class Component2 {
    private final static Logger log = (Logger) LoggerFactory.getLogger(Component2.class);

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

运行结果:

2023-09-17 20:15:31.090  INFO 12308 --- [           main] c.e.springioc.component.Component2       : com.example.springioc.component.UserRegisterEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@7f0d96f2, started on Sun Sep 17 20:15:30 CST 2023]

可以看到,context发布了UserRegister事件,Component2接受到了该事件

下面模拟用户注册完发送短信功能:

1.定义用户注册功能

@Component
public class Component1 {

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

    @Autowired
    private ApplicationEventPublisher publisher;

    public void register(){
        log.info("用户注册!");
       publisher.publishEvent(new UserRegisterEvent(this));
    }


}

2.实现发送短信功能

@Component
public class Component2 {
    private final static Logger log = (Logger) LoggerFactory.getLogger(Component2.class);

    @EventListener
    public void getEvent(UserRegisterEvent event){

        log.info("发送短信");
    }
}

4.调用注册方法

context.getBean(Component1.class).register();

5.运行结果

2023-09-17 20:29:18.311  INFO 4984 --- [           main] c.e.springioc.component.Component1       : 用户注册!
2023-09-17 20:29:18.311  INFO 4984 --- [           main] c.e.springioc.component.Component2       : 发送短信

实现了用户注册完发送短信的功能

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值