Spring源码01

175 阅读2分钟

是根据黑马Spring源码课程总结的

第一讲、容器初步

1、容器接口

Spring容器的接口主要有两个,一个是BeanFactory,一个是ApplicationContext。

实际上BeanFactory是Spring的核心容器,ApplicationContext是它的子接口,也实现了更多的功能。

2、BeanFactory初步

类的继承图如下:

image-20220514090950828

当使用到getBean()方法的时候,实际上就是使用的BeanFactory的getBean()方法:

context.getBean("aa");

Ctrl + Alt + 鼠标左键,查看源码是:

public Object getBean(String name) throws BeansException {
    this.assertBeanFactoryActive();
    return this.getBeanFactory().getBean(name);
}

也就可以看出先getBeanFactory()后,用BeanFactory的getBean()方法。

进入BeanFactory,使用Ctrl + F12查看所有方法:

image-20220514091315073

BeanFactory的重要实现类是DefaultListableBeanFactory:

image-20220514092457895

DefaultSingletonBeanRegistry实现了单例bean,点击类图中的该类,然后按F4进入该类,这个参数就是保存了单例,key是String类型的名字,value是Object类型的实例:

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

可以使用debug的方式或者反射的方式:

Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
singletonObjects.setAccessible(true);
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
map.entrySet().stream().filter(e -> e.getKey().startsWith("component"))
    .forEach(e -> {
        System.out.println(e.getKey() + "=" + e.getValue());
    });

总而言之,控制反转、依赖注入、Bean的生命周期都是由BeanFactory提供的。

3、ApplicationContext初步

还是上面的类图,ApplicationContext有几个比较关键的继承接口:

  • MessageSource:具备处理国际化资源的能力,但是注意要做i8n
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));
  • ResourcePatternResolver:具有通配符匹配资源的能力

下面的代码可以处理上面两个功能:

//classpath*:是可以找到jar包里的文件的,下面的这个可以找到多个文件
Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
for (Resource resource : resources) {
    System.out.println(resource);
}
  • EnvironmentCapable:具有可以读取环境信息的能力
System.out.println(context.getEnvironment().getProperty("java_home"));
System.out.println(context.getEnvironment().getProperty("server.port"));
  • ApplicationEventPublisher:具备发布事件对象的功能

组件1:

@Component
public class Component1 {
    private static final Logger log = LoggerFactory.getLogger(Component1.class);
​
    @Autowired
    private ApplicationEventPublisher context;
​
    public void register() {
        log.debug("用户注册");
        context.publishEvent(new UserRegisteredEvent(this));
    }
}

组件2:

@Component
public class Component2 {
    private static final Logger log = LoggerFactory.getLogger(Component2.class);
​
    @EventListener
    public void aaa(UserRegisteredEvent event) {
        log.debug("{}", event);
        log.debug("发送短信");
    }
}

测试类:

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