Spring源碼分析之IOC

IOC(Inversion of Control)极谊,即控制反轉(zhuǎn)什荣,是面向?qū)ο缶幊讨械囊环N設(shè)計(jì)原則,可以用來減低代碼之間的耦合度怀酷。在Spring中,IOC意味著對(duì)象和資源的創(chuàng)建和獲取統(tǒng)一交給了容器嗜闻,由容器控制對(duì)象的生命周期和對(duì)象間的依賴關(guān)系蜕依。

而DI(Dependency Injection),即依賴注入琉雳,是實(shí)現(xiàn)IOC的一種手段样眠。DI意味著組件之間依賴關(guān)系由容器在運(yùn)行期決定,形象的說翠肘,即由容器動(dòng)態(tài)的將某個(gè)依賴關(guān)系注入到組件之中檐束。

要理解Spring IOC的實(shí)現(xiàn),首先需要了解下面兩個(gè)接口:BeanFactory和ApplicationContext束倍。

1. BeanFactory

BeanFactory是Spring中的Bean工廠, 用于Spring中Bean的生命周期管理绪妹。它的主要接口如下:

public interface BeanFactory {
    /*
     * 四個(gè)不同形式的getBean方法甥桂,獲取實(shí)例
     */
    Object getBean(String name) throws BeansException;

    <T> T getBean(String name, Class<T> requiredType) throws BeansException;

    <T> T getBean(Class<T> requiredType) throws BeansException;

    Object getBean(String name, Object... args) throws BeansException;

    boolean containsBean(String name); // 是否存在

    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;// 是否為單例

    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;// 是否為原型(多實(shí)例)

    boolean isTypeMatch(String name, Class<?> targetType)
            throws NoSuchBeanDefinitionException;// 名稱、類型是否匹配

    Class<?> getType(String name) throws NoSuchBeanDefinitionException; // 獲取類型

    String[] getAliases(String name);// 根據(jù)實(shí)例的名字獲取實(shí)例的別名
    
    //......
}

2. ApplicationContext

ApplicationContext是BeanFactory的子接口邮旷,在擁有所有BeanFactory功能的基礎(chǔ)上黄选,它還繼承了一些其他接口:


ApplicationContext.jpg

因此,ApplicationContext擁有一些高階功能婶肩,例如:

  • HierarchicalBeanFactory 是一個(gè)具有層級(jí)關(guān)系的 BeanFactory办陷,擁有屬性 parentBeanFactory。ListableBeanFactory 實(shí)現(xiàn)了枚舉方法可以列舉出當(dāng)前 BeanFactory 中所有的 bean 對(duì)象而不必根據(jù) name 一個(gè)一個(gè)的獲取律歼。
  • MessageSource接口提供國際化功能
  • ApplicationEventPublisher提供事件發(fā)布訂閱功能
  • ResourceLoader提供資源加載功能
  • EnvironmentCapable用于獲取 Environment 的功能

ApplicationContext常用實(shí)現(xiàn)類包括:ClassPathXMLApplicationContext民镜, FileSystemXmlApplicationContext,AnnotationConfigApplicationContext和WebApplicationContext苗膝。

3. 容器入口

我們以ClassPathXmlApplicationContext為例殃恒,下面是其構(gòu)造函數(shù):

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {

        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }

Spring首先讀取Config文件位置,然后調(diào)用refresh方法進(jìn)行BeanFactory的構(gòu)建辱揭。

4. 容器構(gòu)建流程

下面是AbstractApplicationContext中refresh方法的實(shí)現(xiàn):

public void refresh() throws BeansException, IllegalStateException {
  // refresh過程只能一個(gè)線程處理离唐,不允許并發(fā)執(zhí)行
  synchronized (this.startupShutdownMonitor) {
    prepareRefresh();
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    prepareBeanFactory(beanFactory);
    try {
      postProcessBeanFactory(beanFactory);
      invokeBeanFactoryPostProcessors(beanFactory);
      registerBeanPostProcessors(beanFactory);
      initMessageSource();
      initApplicationEventMulticaster();
      onRefresh();
      registerListeners();
      finishBeanFactoryInitialization(beanFactory);
      finishRefresh();
    }
    catch (BeansException ex) {
      if (logger.isWarnEnabled()) {
        logger.warn("Exception encountered during context initialization - " +
            "cancelling refresh attempt: " + ex);
      }
      destroyBeans();
      cancelRefresh(ex);
      throw ex;
    }
    finally {
      resetCommonCaches();
    }
  }
}

主要的流程圖如下:


ApplicationContext refresh.png

4.1 prepareRefresh

執(zhí)行一些初始化操作丙躏,包括記錄當(dāng)前時(shí)間舅世,初始化變量等嫩码。其源碼如下:

protected void prepareRefresh() {
        this.startupDate = System.currentTimeMillis();
        this.closed.set(false);
        this.active.set(true);

        if (logger.isInfoEnabled()) {
            logger.info("Refreshing " + this);
        }

        // Initialize any placeholder property sources in the context environment
        initPropertySources();

        // Validate that all properties marked as required are resolvable
        // see ConfigurablePropertyResolver#setRequiredProperties
        getEnvironment().validateRequiredProperties();

        // Allow for the collection of early ApplicationEvents,
        // to be published once the multicaster is available...
        this.earlyApplicationEvents = new LinkedHashSet<>();
}

4.2 obtainFreshBeanFactory

創(chuàng)建一個(gè)BeanFactory鳍寂。此方法會(huì)調(diào)用refreshBeanFactory方法饮怯,其源碼如下:

protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            customizeBeanFactory(beanFactory);
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
}

從源碼上看,refreshBeanFactory方法的主要流程如下:

  1. 若已經(jīng)存在beanFactory则披,銷毀它
  2. 創(chuàng)建新的beanFactory(new DefaultListableBeanFactory(getInternalParentBeanFactory()))
  3. 通過customizeBeanFactory定制BeanFactory的屬性搂誉;
  4. 加載BeanDefinition到當(dāng)前BeanFactory中(對(duì)于ClassPathXmlApplicationContext來說,會(huì)調(diào)用XmlBeanDefinitionReader讀取所有的Bean定義熟呛,封裝為BeanDefinition注冊到BeanFactory中)宽档;

ApplicationContext實(shí)現(xiàn)了BeanFactory接口,其內(nèi)部是通過聚合一個(gè)DefaultListableBeanFactory來實(shí)現(xiàn)所有的BeanFactory功能的庵朝。

下面時(shí)BeanDefinition接口的主要定義:

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
    //單例作用域
    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

    //原型作用域
    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

    String getParentName();
    void setParentName(String parentName);

    String getBeanClassName();
    void setBeanClassName(String beanClassName);

    String getScope();
    void setScope(String scope);

    boolean isLazyInit();
    void setLazyInit(boolean lazyInit);

    boolean isPrimary();
    void setPrimary(boolean primary);

    boolean isSingleton();
    boolean isPrototype();
    //......
}

DefaultListableBeanFactory中維護(hù)了一個(gè)Map用于存儲(chǔ)所有的BeanDefinition:

/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

另外吗冤,DefaultSingletonBeanRegistryDefaultListableBeanFactory的父類)中維護(hù)了一個(gè)Map用于存儲(chǔ)所有的Bean:

/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

4.3 prepareBeanFactory

在BeanFactory已經(jīng)創(chuàng)建成功后,Spring會(huì)調(diào)用prepareBeanFactory(beanFactory)來向已經(jīng)創(chuàng)建的BeanFactory注冊一些特定的Bean九府,包括environment等:

   // 如果沒有定義 "environment" 這個(gè) bean椎瘟,那么 Spring 會(huì) "手動(dòng)" 注冊一個(gè)
   if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
   }
   // 如果沒有定義 "systemProperties" 這個(gè) bean,那么 Spring 會(huì) "手動(dòng)" 注冊一個(gè)
   if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
   }
   // 如果沒有定義 "systemEnvironment" 這個(gè) bean侄旬,那么 Spring 會(huì) "手動(dòng)" 注冊一個(gè)
   if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
   }

另外肺蔚,還會(huì)注冊一些BeanPostProcessor,包括ApplicationContextAwareProcessor儡羔,ApplicationListenerDetector等:

   // 添加一個(gè) BeanPostProcessor宣羊,這個(gè) processor 比較簡單,
   // 實(shí)現(xiàn)了 Aware 接口的幾個(gè)特殊的 beans 在初始化的時(shí)候汰蜘,這個(gè) processor 負(fù)責(zé)回調(diào)
   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

   // 這個(gè) BeanPostProcessor 也很簡單段只,在 bean 實(shí)例化后,如果是 ApplicationListener 的子類鉴扫,
   // 那么將其添加到 listener 列表中赞枕,可以理解成:注冊事件監(jiān)聽器
   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

4.3 postProcessBeanFactory

在BeanFactory基本完成后,Spring調(diào)用postProcessBeanFactory(beanFactory)來進(jìn)行后續(xù)的針對(duì)BeanFactory的操作坪创。AbstractApplicationContext中的默認(rèn)實(shí)現(xiàn)為空炕婶。而其子類AnnotationConfigEmbeddedWebApplicationContext對(duì)應(yīng)的postProcessBeanFactory方法則會(huì)掃描basePackage下的bean并注冊到BeanFactory中。

4.4 invokeBeanFactoryPostProcessors

在BeanFactory創(chuàng)建完畢后莱预,Spring調(diào)用invokeBeanFactoryPostProcessors(beanFactory)來運(yùn)行所有已經(jīng)注冊的BeanFactoryPostProcessor柠掂,從而進(jìn)行修改BeanFactory或修改BeanFactory中已經(jīng)存在的BeanDefinition。

public interface BeanFactoryPostProcessor {

    /**
     * Modify the application context's internal bean factory after its standard
     * initialization. All bean definitions will have been loaded, but no beans
     * will have been instantiated yet. This allows for overriding or adding
     * properties even to eager-initializing beans.
     * @param beanFactory the bean factory used by the application context
     * @throws org.springframework.beans.BeansException in case of errors
     */
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

常見的BeanFactoryPostProcessor包括ConfigurationClassPostProcessor依沮,PropertyPlaceholderConfigurer等涯贞。

ConfigurationClassPostProcessor用于讀取所有已經(jīng)注冊的Configuration類型的Bean,然后注入Configuration類中定義的Bean危喉,最后判斷該Configuration是否擁有ComponentScan注解宋渔,如果擁有則掃描basePackage下的所有bean并注冊到BeanFactory中。

如果spring配置文件中包含了<context:annotation-config/> 或 <context:component-scan/>辜限,spring則會(huì)自動(dòng)啟用ConfigurationClassPostProcessor皇拣。

invokeBeanFactoryPostProcessors(beanFactory)方法內(nèi)部首先對(duì)所有的BeanFactoryPostProcessor進(jìn)行排序,然后依次調(diào)用。

4.5 registerBeanPostProcessors

registerBeanPostProcessors方法會(huì)對(duì)所有BeanFactory內(nèi)的BeanPostProcessor類型的Bean進(jìn)行排序氧急,然后調(diào)用registerBeanPostProcessors注冊這些BeanPostProcessor颗胡,最終在createBean時(shí)會(huì)依次調(diào)用這些BeanPostProcessor來customize最終生成的Bean。BeanPostProcessorBeanFactoryPostProcessor的區(qū)別在于吩坝,BeanPostProcessor用于實(shí)例化bean后再customize bean毒姨,而BeanFactoryPostProcessor則用于BeanFactory創(chuàng)建完成后customize BeanFactory。

BeanPostProcessor接口如下:

public interface BeanPostProcessor {
    // inti方法調(diào)用之前的操作
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    // init方法調(diào)用之后的操作
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

BeanPostProcessor調(diào)用時(shí)bean已經(jīng)被實(shí)例化钉寝,并且所有該注入的屬性都已經(jīng)被注入手素,是一個(gè)完整的Bean。下面是postProcessBeforeInitializationpostProcessAfterInitialization的調(diào)用時(shí)間:

  1. 在Bean實(shí)例化完成后調(diào)用BeanPostProcessor.postProcessBeforeInitialization
  2. 如果Bean實(shí)現(xiàn)了InitializingBean接口瘩蚪,則調(diào)用InitializingBean.afterPropertiesSet方法
  3. 如果Bean中配置了init-method,則調(diào)用init-method
  4. 調(diào)用BeanPostProcessor.postProcessAfterInitialization

InitializingBean接口的定義如下:

public interface InitializingBean {

    /**
     * Invoked by a BeanFactory after it has set all bean properties supplied
     * (and satisfied BeanFactoryAware and ApplicationContextAware).
     * <p>This method allows the bean instance to perform initialization only
     * possible when all bean properties have been set and to throw an
     * exception in the event of misconfiguration.
     * @throws Exception in the event of misconfiguration (such
     * as failure to set an essential property) or if initialization fails.
     */
    void afterPropertiesSet() throws Exception;

}

常見的BeanPostProcessor包括ApplicationContextAwareProcessor稿黍,ApplicationListenerDetector疹瘦,AutowiredAnnotationBeanPostProcessor等。

ApplicationContextAwareProcessor用于調(diào)用Bean的Aware的接口(包括ApplicationContextAware巡球,MessageSourceAware言沐,ApplicationEventPublisherAware等)。例如如果Bean實(shí)現(xiàn)了ApplicationContextAware接口酣栈,在Bean實(shí)例化結(jié)束后险胰,會(huì)調(diào)用ApplicationContextAware接口的setApplicationContext(ApplicationContext applicationContext)方法來cutomize實(shí)例化后的Bean。

ApplicationListenerDetector用于如果Bean實(shí)現(xiàn)了ApplicationListener接口矿筝,那么它會(huì)將這個(gè)Bean加入ApplicationEventMulticaster的listener列表中起便。

AutowiredAnnotationBeanPostProcessor用于注入所有使用了@Autowired注解的屬性。

4.6 initMessageSource

MessageSource是Spring提供國際化的接口窖维。ApplicationContext實(shí)現(xiàn)了MessageSource接口榆综,其內(nèi)部是通過聚合一個(gè)MessageSource對(duì)象來實(shí)現(xiàn)的。initMessageSource方法主要是為了初始化ApplicationContext內(nèi)部的MessageSource對(duì)象铸史。如果BeanFactory中存在一個(gè)MessageSource Bean鼻疮,那么直接將這個(gè)Bean賦值給ApplicationContext內(nèi)部的MessageSource對(duì)象。如果沒有琳轿,則會(huì)構(gòu)造一個(gè)new DelegatingMessageSource()對(duì)象判沟。

4.7 initApplicationEventMulticaster

initApplicationEventMulticaster顧名思義,是為了初始化ApplicationEventMulticaster崭篡。ApplicationContext實(shí)現(xiàn)了ApplicationEventPublisher接口挪哄,從而具備了事件發(fā)布功能。其內(nèi)部是通過聚合一個(gè)ApplicationEventMulticaster實(shí)現(xiàn)的琉闪。下面是初始化代碼:

protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
            this.applicationEventMulticaster =
                    beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
            if (logger.isDebugEnabled()) {
                logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
            }
        }
        else {
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
            if (logger.isDebugEnabled()) {
                logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
                        APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
                        "': using default [" + this.applicationEventMulticaster + "]");
            }
        }
    }

initMessageSource方法類似中燥,如果BeanFactory中存在一個(gè)名為applicationEventMulticaster的對(duì)象,則將其賦值給內(nèi)部的this.applicationEventMulticaster塘偎。否則疗涉,直接通過new SimpleApplicationEventMulticaster(beanFactory)實(shí)例化一個(gè)ApplicationEventMulticaster拿霉。之后ApplicationContext所有事件發(fā)布功能都會(huì)轉(zhuǎn)交給內(nèi)部的applicationEventMulticaster對(duì)象。

ApplicationEventMulticaster主要負(fù)責(zé)事件的發(fā)布和監(jiān)聽者的注冊咱扣。主要接口如下:

// 注冊監(jiān)聽者
void addApplicationListener(ApplicationListener<?> listener);
//發(fā)布事件
void multicastEvent(ApplicationEvent event);
//......

ApplicationEventMulticaster的實(shí)現(xiàn)類內(nèi)部擁有一個(gè)Set<ApplicationListener<?>> applicationListeners監(jiān)聽者集合绽淘。在掃描出所有實(shí)現(xiàn)了ApplicationListener接口的類后,通過以下方法創(chuàng)建一個(gè)ApplicationListener<?>對(duì)象闹伪,然后添加到Set<ApplicationListener<?>> applicationListeners監(jiān)聽者集合中沪铭。

public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
   return new ApplicationListenerMethodAdapter(beanName, type, method);
}

4.8 onRefresh

擴(kuò)展方法,由子類實(shí)現(xiàn)用于初始化其他的特殊Bean偏瓤。AbstractApplicationContext默認(rèn)實(shí)現(xiàn)為空杀怠。

4.9 registerListeners

注冊事件監(jiān)聽器。將BeanFactory中存在的ApplicationListener類型的Bean注冊到ApplicationContext內(nèi)部的ApplicationEventMulticaster中厅克。

4.10 finishBeanFactoryInitialization

通過調(diào)用beanFactory.preInstantiateSingletons()實(shí)例化所有非懶加載的單例Bean赔退。beanFactory.preInstantiateSingletons()則會(huì)遍歷所有的Bean并調(diào)用getBean(beanName)方法。

下面是getBean(beanName)方法的流程:

  1. 首先通過getSingleton(beanName)從signleton緩存池中獲取Bean
  2. 如果獲取不到证舟,則根據(jù)當(dāng)前的beanfactory獲取父一級(jí)的beanfactory硕旗,然后逐級(jí)遞歸的查找我們需要的bean
  3. 獲取仍然不到則根據(jù)final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName)拿到BeanDefinition,然后通過createBean(beanName, mbd, args)進(jìn)行Bean的創(chuàng)建女责。
  4. createBean(beanName, mbd, args)方法調(diào)用doCreateBean(beanName, mbdToUse, args)方法來創(chuàng)建Bean漆枚。
  5. doCreateBean(beanName, mbdToUse, args)方法主要分為四步:
    (1) instanceWrapper = createBeanInstance(beanName, mbd, args) 通過反射創(chuàng)建出一個(gè)Bean實(shí)例
    (2)applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName) 調(diào)用所有的MergedBeanDefinitionPostProcessor來customize創(chuàng)建出的Bean。
    (3) populateBean(beanName, mbd, instanceWrapper) 填充所有的屬性
    (4) exposedObject = initializeBean(beanName, exposedObject, mbd) 調(diào)用applyBeanPostProcessorsBeforeInitialization(即BeanPostProcessor.beforeInitialization)抵知,invokeInitMethods(即配置文件中配置的init-method)和applyBeanPostProcessorsAfterInitialization(即BeanPostProcessor.afterInitialization)

上文中我們提到的AutowiredAnnotationBeanPostProcessor是一種BeanPostProcessor(然而它的beforeInitialization和afterInitialization都為空)墙基,它還實(shí)現(xiàn)了MergedBeanDefinitionPostProcessor接口。因此上述第(2)步會(huì)調(diào)用AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition方法刷喜,然而這個(gè)方法并不會(huì)直接向Bean中注入所有的@Autowired屬性碘橘。下面是這個(gè)方法的實(shí)現(xiàn):

@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    if (beanType != null) {
        InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
        metadata.checkConfigMembers(beanDefinition);
    }
}

AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition的作用僅僅是緩存此Bean的所有@Autowired屬性信息。

在執(zhí)行第(3)步populateBean(beanName, mbd, instanceWrapper) 時(shí)吱肌,會(huì)調(diào)用其AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues方法痘拆,從而完成了所有@Autowired屬性的注入:

@Override
    public PropertyValues postProcessPropertyValues(
            PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {

        InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
        try {
            metadata.inject(bean, beanName, pvs);
        }
        catch (BeanCreationException ex) {
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
        }
        return pvs;
    }

更多Bean初始化流程,請參考:https://www.shangyang.me/2017/04/01/spring-core-container-sourcecode-analysis-beans-instantiating-process/

4.11 finishRefresh

執(zhí)行refresh收尾工作氮墨。包括初始化LifecycleProcessor纺蛆,發(fā)布ContextRefreshedEvent事件等。其源碼如下:

protected void finishRefresh() {
        // Clear context-level resource caches (such as ASM metadata from scanning).
        clearResourceCaches();

        // Initialize lifecycle processor for this context.
        initLifecycleProcessor();

        // Propagate refresh to lifecycle processor first.
        getLifecycleProcessor().onRefresh();

        // Publish the final event.
        publishEvent(new ContextRefreshedEvent(this));

        // Participate in LiveBeansView MBean, if active.
        LiveBeansView.registerApplicationContext(this);
}

參考文章:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末规揪,一起剝皮案震驚了整個(gè)濱河市桥氏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌猛铅,老刑警劉巖字支,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡堕伪,警方通過查閱死者的電腦和手機(jī)揖庄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來欠雌,“玉大人蹄梢,你說我怎么就攤上這事「欢恚” “怎么了禁炒?”我有些...
    開封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長霍比。 經(jīng)常有香客問我幕袱,道長,這世上最難降的妖魔是什么悠瞬? 我笑而不...
    開封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任们豌,我火速辦了婚禮,結(jié)果婚禮上阁危,老公的妹妹穿的比我還像新娘。我一直安慰自己汰瘫,他們只是感情好狂打,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著混弥,像睡著了一般趴乡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蝗拿,一...
    開封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天晾捏,我揣著相機(jī)與錄音,去河邊找鬼哀托。 笑死惦辛,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的仓手。 我是一名探鬼主播胖齐,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼嗽冒!你這毒婦竟也來了呀伙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤添坊,失蹤者是張志新(化名)和其女友劉穎剿另,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡雨女,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年谚攒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片戚篙。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡五鲫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出岔擂,到底是詐尸還是另有隱情位喂,我是刑警寧澤,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布乱灵,位于F島的核電站塑崖,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏痛倚。R本人自食惡果不足惜规婆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蝉稳。 院中可真熱鬧抒蚜,春花似錦、人聲如沸耘戚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽收津。三九已至饿这,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間撞秋,已是汗流浹背长捧。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吻贿,地道東北人串结。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像舅列,于是被迫代替她去往敵國和親奉芦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容