Spring IOC解决的问题

IOC主要解决的问题,就是层与层之间的耦合问题
举个简单的例子,例如原先有A,B,C三个类,A类依赖于C类实现其中的功能,假设有一天,需要将依赖的C类替换成B类,则需要修改A类的代码,可能会造成一些不必要的风险。
解决方法:B,C类实现D接口,A类依赖于D接口,具体的实现细节由B,C实现,此时修改,不会造成A类的修改,大大减少了风险。(这也就是开发中常常写到的,Controller依赖于Service,具体的Service实现由ServiceImpl去完成)
而Spring中,解决层与层的耦合问题,是通过DI(控制翻转)来实现的
将对象的创建,交由Spring来完成,需要东西时,只需要往容器中喊一声(@Autowired),就能够取到相应的依赖。但是这种方式,又引申出来了两个问题。 循环依赖 以及 Spring如何创建对象的

Spring 如何创建对象的

在使用最基础的Spring时都知道,只需要创建一个ApplicationContext,然后调用ApplicationContext中的getBean方法,就能取得这个Bean。
在AbstractApplicationContext中,调用getBeanFactory() 获取到 Bean工厂,然后通过Bean工厂进行bean的创建。所以我们可以得出,Spring是通过 BeanFactory 来创建生产Bean的。

  1. @Override
  2. public Object getBean(String name) throws BeansException {
  3. assertBeanFactoryActive();
  4. return getBeanFactory().getBean(name);
  5. }

ApplicationContext读取配置类/配置文件,将其中的内容,读取为BeanDefinition。
BeanDefinition中大致包含如下的信息,用来描述这个Bean的信息。

  1. // 这个Bean所对应的类型
  2. private volatile Object beanClass;
  3. // 这个Bean的作用域。单例还是原型
  4. private String scope = SCOPE_DEFAULT;
  5. // 这个Bean是否为抽象的
  6. private boolean abstractFlag = false;
  7. // 这个Bean是否懒加载
  8. private boolean lazyInit = false;
  9. // 这个Bean的自动注入类型
  10. private int autowireMode = AUTOWIRE_NO;
  11. // 这个Bean的依赖检查类型,默认不检查
  12. private int dependencyCheck = DEPENDENCY_CHECK_NONE;
  13. // 这个Bean所依赖的其他Bean
  14. private String[] dependsOn;
  15. // 自动装配候选
  16. private boolean autowireCandidate = true;
  17. // 当有多个同名的Bean时,是否优先加载这个Bean
  18. private boolean primary = false;

而BeanFactory创建Bean,就是通过BeanDefinition中所包含的这些信息,通过反射(beanClass)来创建出这个Bean实例,然后放入 singleObjects(大名鼎鼎的单例缓存池)中,供后续的使用。
而ApplicationContext中如何将配置类/配置文件读取成BeanDefinition呢?
通过BeanDefinitionReader 读取已经配置的Bean
通过BeanDefinitionScanner来扫描配置的 ComponentScan所对应的包路径
通过BeanDefinitionRegistery 来将这些BeanDefinition保存到BeanDefinitionMap中

Spring中提供的一系列扩展点

BeanFactoryPostProcessor Bean工厂的后置处理器

用于对BeanDefinition进行修改,类比于生活即对生产的图纸进行修改

  1. @FunctionalInterface
  2. public interface BeanFactoryPostProcessor {
  3. void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
  4. }

可以通过实现这个类,通过传入的 BeanFactory,获取到想要修改的BeanDefinition,修改上述BeanDefinition中的一切值,例如BeanClass等

// (Mybatis与Spring整合就是用的修改BeanClass,详见 Spring 源码分析之Spring/Spring Boot整合Mybatis原理 ),实现偷龙转凤。

BeanPostProcessor Bean的后置处理器

用于对Bean的修改,类比于生活即车出厂之后,对车进行改装。

  1. public interface BeanPostProcessor {
  2. @Nullable
  3. default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  4. return bean;
  5. }
  6. @Nullable
  7. default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  8. return bean;
  9. }
  10. }

postProcessBeforeInitialization 在对象初始化之前调用
postProcessAfterInitialization 在对象初始化之后调用
BeanPostProcessor的常见应用为AOP以及事务, 用其生成代理对象。详情可以参见 AOP原理分析事务原理分析

XXXAware接口

XXXAware接口,就是Spring提供的一个,用于给自己定义的Bean中注入Spring自有组件的功能
例如:
EnvironmentAware: 实现了这个接口,在IOC容器启动的时候,将会调用setEnvironment方法,把Environment传入
ResourceLoaderAware: 传入资源加载器
ApplicationEventPublisherAware: 传入事件的发布器
ApplicationContextAware: 传入当前的IOC容器
BeanClassLoaderAware: 传入当前bean的类加载器
将会在IOC容器初始化的时候(initializeBean方法中去invokeAwareMethods()调用实现了Aware接口的那些Bean)

InitializingBean Bean的初始化方法

可以在afterPropertiesSet方法中,自定义当前Bean的初始化逻辑,实际应用中可以在网关(Gateway)中的Filter实现这个方法,向认证中心请求PublicKey

  1. public interface InitializingBean {
  2. void afterPropertiesSet() throws Exception;
  3. }

上面两个扩展点的方法,将会在 initializeBean 方法中 invokeInitMethods,调用实现了 InitializingBean的afterPropertiesSet方法

DisposableBean Bean的销毁方法

可以在destroy方法中,自定义当前Bean的销毁逻辑,实际应用中,可以在Bean销毁时,进行一些资源的回收等操作

  1. public interface DisposableBean {
  2. void destroy() throws Exception;
  3. }

FactoryBean 工厂Bean

实现了该接口的类,不会再被当做一个普通的Bean,当调用getBean的时候,判断实现了FactoryBean的话,将会调用其中的getObject方法,来获取真正的Bean。MyBatis中就是通过自定义了FactoryBean,将扫描进入的Mapper接口替换成FactoryBean,在FactoryBean中实现代理

  1. public interface FactoryBean<T> {
  2. @Nullable
  3. T getObject() throws Exception;
  4. @Nullable
  5. Class<?> getObjectType();
  6. default boolean isSingleton() {
  7. return true;
  8. }
  9. }