复习盘点-源码导读-IOC原理-创建Bean容器-1

在springBoot大行其道的今天,我们似乎可以无脑使用Spring全家桶,但是我们对于Spring还是要知道其原理的。下面和小胖一起去探寻下Spring IOC的原理去吧。

idea快捷键:
查找接口的实现类:
ctrl + alt +B

查看类或接口的继承关系:
ctrl + h

小胖十分推荐的两篇博客:
小胖墙裂推荐1——idea整合SSM框架步骤
小胖墙裂推荐2——IOC源码导读


1. 测试代码

测试代码:

public class MessageMapperTest {
    private ApplicationContext applicationContext;
    @Before
    public void setUp() throws Exception {
        // 加载spring配置文件
        applicationContext = new ClassPathXmlApplicationContext("classpath:spring/applicationContext.xml");
    }
    @After
    public void tearDown() throws Exception {
    }
    @Test
    public void TestIOC() {
        MessageService messageService = applicationContext.getBean(MessageService.class);
        System.out.println("-->" + messageService.getMessage());
    }

}

spring.xml代码

 
    
    

service接口

public interface MessageService {
    String getMessage();
}

service接口实现类

public class MessageServiceImpl implements MessageService {
    public String getMessage() {
        return "hello world";
    }
}

2. 源码导读

在启动类中,有着ApplicationContext context=new ClassPathXmlApplicationContext(...)就是在ClassPath中寻找xml配置文件,根据xml文件内容来构建ApplicationContext,当然我们还有ClassPathXmlApplicationContext以外,还有其他的方案可以构建ApplicationContext

ApplicationContext继承图
  • ClassPathXmlApplicationContext:默认情况下会去ClassPath路径下寻找配置文件,Classpath可以省略,路径就是编译后的classes目录。如果是绝对路径,需要加上file:前缀,不可省略。

  • FileSystemXmlApplicationContext:默认情况下在项目路径下加载,可以使用相对路径,也可以使用绝对路径,绝对路径下file:可省略。

  • AnnotationConfigApplicationContext:基于注解使用,不需要配置文件。

ApplicationContext在启动过程中,会负责创建实例Bean,往各个bean中注入依赖。


2.1 图解BeanFactory

BeanFactory,和中文一样,就是生产bean的工厂,负责生产管理各个bean实例。

BeanFactory继承图

正如图上所见,我们的ApplicationContext本质上就是一个BeanFactory对象。

可能看到这个图的时候,大家有点想放弃的冲动了,但是,我们无须全部关注,先关注特殊重点的几个实现类或接口。

  • ApplicationContext继承了ListableBeanFactory,这个ListableFactory的作用是可以获取多个bean,而FactoryBean接口虽然是最顶层接口,但是只是获取一个Bean的。

  • ApplicationContext继承了HierarchicalBeanFactory,(注:
    [ˌhaɪəˈrɑ:kɪkl]] 分层的,分等级的),也就是我们在应用程序中,可以起多个BeanFactory,然后后将各个BeanFactory设置为父子关系。

  • AutowireCapableBeanFactory [ˈkeɪpəbl] 能胜任的大家看到Autowire会十分的熟悉,他就是自动装配Bean用的,但是ApplicationContext并没有继承它,但是我们在实际中还是可以使用到注解的方式注入到容器中的,没有继承,但是不代表没有组合,我们可以看到ApplicationContext里面的最后一个方法:getAutowireCapableBeanfactory()就知道了。

  • ConfigurableListableBeanFactory也是一个特殊的接口,原因就是他继承了第二层的三个接口。

  • DefaultListableBeanFactory 最底层的类,包含即基本所有的功能。

接口ApplicationContext继承的接口或者实现类:

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
        MessageSource, ApplicationEventPublisher, ResourcePatternResolver {

HierarchicalBeanFactory源码:

public interface HierarchicalBeanFactory extends BeanFactory {

    /**
     * Return the parent bean factory, or {@code null} if there is none.
     */
    BeanFactory getParentBeanFactory();

    /**
     * Return whether the local bean factory contains a bean of the given name,
     * ignoring beans defined in ancestor contexts.
     * 

This is an alternative to {@code containsBean}, ignoring a bean * of the given name from an ancestor bean factory. * @param name the name of the bean to query * @return whether a bean with the given name is defined in the local factory * @see BeanFactory#containsBean */ boolean containsLocalBean(String name); }

2.2 BeanFactory源码分析

1. 点击进入ClassPathXmlApplicationContext的构造函数中

ApplicationContext applicationContext = 
new ClassPathXmlApplicationContext("classpath:spring/applicationContext.xml");

2. ClassPathXmlApplicationContext类的82行

//进入重构的构造方法中
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[] {configLocation}, true, null);
    }

//如果已经有ApplicationContext并且需要配置为父子关系。(HierarchicalBeanFactory)
public ClassPathXmlApplicationContext(ApplicationContext parent) {
    super(parent);
}


public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
        throws BeansException {
        super(parent);
        //根据配置文件,处理成配置文件数组
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();  //核心方法【翻新】(点击进入)
        }
    }

我们创建Factory工厂,为什么不是init()类型的方法,而是refresh()方法,因为ApplicationContext建立之后,其实是可以通过refresh()这个方法重建的,refresh()会将原来的ApplicationContext销毁,然后重新执行一次初始化操作。

AbstractApplicationContext中的504行:

    @Override
    public void refresh() throws BeansException, IllegalStateException {
【1. 加锁,否则refresh()重建还没结束,又来重建了,可怕...】
      synchronized (this.startupShutdownMonitor) {
    
【2. 准备容器的重建。容器启动时间,标记“已启动”状态,处理配置文件的占位符】
            prepareRefresh();

【3. (关键:)这步执行完毕,配置文件会被解析成一个个的Bean定义,注册到了BeanFactory中。
* 当然这里说的Bean还没有初始化,只是配置信息都提取出来了
* 注册也只是将这些信息保存到注册中心(敲黑板,划重点)
* 说到底核心就是:XML配置(beanName)-->beanDefinition的map中。
* (这个比较重要,下一章单独讲!!!)
】
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

【4. 设置BeanFactory,添加实现BeanPostProcessor接口的bean(后处理的bean),忽略几个特殊接口的bean】
            prepareBeanFactory(beanFactory);

【PS:提一下BeanFactoryPostProcessor,若是Bean实现了该接口,那么在容器初始化之后,
spring会负责调用里面的postProcessBeanFactory()方法。其实就是后处理方法,针对于BeanFactory的】

            try {
                 【---->注意:到达此处,所有的bean已经被加载注册完毕。但是还没初始化。】
【(就是后处理加点东西),具体的子类到这步的时候,可以添加一些特殊的BeanFactoryPostProcessor的实现类或者做一些其他的事情。】
          
                postProcessBeanFactory(beanFactory);

                invokeBeanFactoryPostProcessors(beanFactory);

                registerBeanPostProcessors(beanFactory);

【---------------------分界线--------------------】
【上面这么多,就是将XML解析为BeanDefinition对象,然后处理实现BeanFactoryPostProcessor或者
BeanPostProcessor接口的bean,其实就是后处理】

【一次性分析太多,看着就烦了,咱们直接先看postProcessBeanFactory到底是干啥的。直接看下一个标题去吧】

【下一章:重心在于分析obtainFreshBeanFactory方法。】

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }

2.2.1 BeanPostProcessor和BeanFactoryPostProcessor的作用以及区别

上面这么大篇幅讲BeanPostProcessorBeanFactoryPostProcessor是不是大家已经蒙了,反正小胖晕了...下面讲一下他们的作用。[ˈprəʊsesə(r)] 处理
Spring的BeanPostProcessor和BeanFactoryPostProcessor区别

Spring提供了两种后处理bean的扩展接口,分别是BeanPostProcessorBeanFactoryPostProcessor。这两者还是有区别的。

2.2.1.1 BeanPostProcessor的使用

BeanPostProcessor:Bean级别的处理,针对某个具体的Bean进行处理。

接口提供了两个方法,分别是初始化前初始化后执行的方法,那啥叫初始化前呀?

public interface BeanPostProcessor 
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

类似于定义Bean的时候,定义init-method所指定的方法上面这两个方法分别在init方法前后执行,需要注意的是,我们定义的实现了BeanPostProcessor接口,默认是对整个Spring容器中所有的bean进行处理。

等等,不是说可以针对于某个具体的bean吗?你咋又对所有的进行默认处理呢?

不要急,看到方法上的两个参数了吗?类型分别是ObjectString,第一个参数是bean的实例,第二个参数是bean的id或者name属性,我们可以根据第二个参数,来确定我们要处理的具体的bean。

(PS:在上面的refresh()源码中可知,这个处理,是发生在obtainFreshBeanFactory()之后,也就是发生在Spring容器实例化和依赖注入之后,但是还没初始化呀...)

2.2.1.2 BeanFactoryPostProcessor的使用

public interface BeanFactoryPostProcessor 
    void postProcessBeanFactory(ConfigurableListableBeanFactory 
                                                beanFactory) throws BeansException;
}

正如其名,BeanFactoryXXX,BeanFactory级别的处理,是针对整个Bean工厂进行处理。

这个接口只有一个方法,但是参数是ConfigurableListableBeanFactory,这个名字是不是有那么一点熟悉...

对的,在咱们的2.1 图解BeanFactory中,ConfigurableListableBeanFactory是一个特殊的接口,原因是它继承了第二层的所有接口。

咱们想进去,研究下ConfigurableListableBeanFactory这个接口的源码。

public interface ConfigurableListableBeanFactory
        extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory {
    //重点看下这个方法,获取BeanDefinition对象,通过beanName名字
    BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

}

那么,BeanDefinition对象又是啥呢?这个咱们下面有篇幅讲到的,这里先提一下。

BeanDefinition 源码:

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;


    int ROLE_APPLICATION = 0;

    int ROLE_SUPPORT = 1;

    int ROLE_INFRASTRUCTURE = 2;


    /**
     * Return the name of the parent definition of this bean definition, if any.
     */
    String getParentName();

    /**
     * Set the name of the parent definition of this bean definition, if any.
     */
    void setParentName(String parentName);

    String getBeanClassName();

    void setBeanClassName(String beanClassName);

    String getFactoryBeanName();

    void setFactoryBeanName(String factoryBeanName);

    String getFactoryMethodName();

    void setFactoryMethodName(String factoryMethodName);

    String getScope();

    void setScope(String scope);

    boolean isLazyInit();

    void setLazyInit(boolean lazyInit);

    String[] getDependsOn();

    void setDependsOn(String... dependsOn);

    boolean isAutowireCandidate();

    void setAutowireCandidate(boolean autowireCandidate);

    boolean isPrimary();

    void setPrimary(boolean primary);

    MutablePropertyValues getPropertyValues();

    boolean isSingleton();

    boolean isPrototype();

    boolean isAbstract();

    int getRole();

    String getDescription();

    String getResourceDescription();

    BeanDefinition getOriginatingBeanDefinition();

}

看上去,好像就是一个entity 实体类呀,而且,这个类长得好像里面定义的属性呀。真聪明,就是这样的。

当我们在XML中定义了Bean标签时,Spring会把这些标签解析为一个个的javaBean,这个JavaBean就是BeanDefinition对象。

又回到我们的refresh()方法,此时,我们知道调用postProcessBeanFactory()方法时,bean刚刚被解析成BeanDefinition对象,还没有被实例化呢。

我们调用postProcessBeanFactory()方法,可以拿到BeanDefinition对象,手动的修改里面的属性值。

Spring容器初始化Bean的大致过程:
1. 定义Bean标签;
2. 将Bean标签解析为BeanDefinition对象;
3. 调用构造方法实例化(IOC);
4. 属性值依赖注入;

postProcessBeanFactory方法的执行是在2,3步之间。即解析为BeanDefinition对象之后,但是初始化之前。

BeanPostProcess是在初始化之前和初始化之后均可处理。

其实都是Spring提供的Bean后处理接口。

2.2.2 prepareBeanFactory(beanFactory);的作用

refresh()方法中,此时Spring把我们配置在XML中的bean都注册之后,会执行prepareBeanFactory(beanFactory);方法,手动注册一些“特殊”的方法。

类加载器的工作原理
反正小胖不知道什么是类加载器。于是,读下面源码之前先科普一波。


prepareBeanFactory()源码导读:

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // Tell the internal bean factory to use the context's class loader etc.
        beanFactory.setBeanClassLoader(getClassLoader());
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

        // Configure the bean factory with context callbacks.
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
        beanFactory.ignoreDependencyInterface(EnvironmentAware.class);

        // BeanFactory interface not registered as resolvable type in a plain factory.
        // MessageSource registered (and found for autowiring) as a bean.
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);

        // Detect a LoadTimeWeaver and prepare for weaving, if found.
        if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            // Set a temporary ClassLoader for type matching.
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }

        // Register default environment beans.
        if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
        }
        if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
        }
        if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
        }
    }

你可能感兴趣的:(复习盘点-源码导读-IOC原理-创建Bean容器-1)