Spring 源碼分析(二)之 Spring IOC 容器源碼分析

spring.png

Spring 源碼分析(二)之 Spring IOC 容器源碼分析

在之前介紹了Spring IOC 容器在項(xiàng)目中的作用

  • 將對(duì)象的構(gòu)建統(tǒng)一解決
  • 并自動(dòng)維護(hù)對(duì)象的依賴關(guān)系磁椒,從而降低實(shí)現(xiàn)成本
  • ...

源碼介紹之前,看幾個(gè)問(wèn)題:

  • Bean的承載對(duì)象是什么本辐?
  • Bean的定義如何存儲(chǔ)的医增?
  • Bean工廠是如何生產(chǎn)bean的?
  • Bean的依賴關(guān)系由誰(shuí)來(lái)解決茫多?
  • Bean工廠和ApplicationContext的區(qū)別忽刽?
Bean的構(gòu)建過(guò)程

spring.xml文件中保存了我們對(duì)Bean的描述配置,BeanFactory會(huì)讀取這些配置然后生成對(duì)應(yīng)的Bean缔恳。

這些配置信息最后由BeanDefinition來(lái)承載。

BeanDefinition(Bean定義)

IOC實(shí)現(xiàn)中万细,我們?cè)趚ml中的描述的Bean信息最后都將保存至BeanDefinition對(duì)象中纸泄,其中xml bean與BeanDefinition是一對(duì)一的關(guān)系。

xml bean的屬性配置與BeanDefinition對(duì)應(yīng)關(guān)系

XML-Bean BeanDefinition
class beanClassName
scope SCOPE_SINGLETON雪营、SCOPE_PROTOTYPE
lazy-init AbstractBeanDefinition.lazyInit
constructor-arg AbstractBeanDefinition.ConstructorArgument
property AbstractBeanDefinition.propertyValues
factory-method AbstractBeanDefinition.factoryMethondName
destroy-method AbstractBeanDefinition.destroyMethodName
init-method AbstractBeanDefinition.initMethodName
autowire AbstractBeanDefinition.autowireMode
id
name

BeanDefinition.java

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
    String SCOPE_SINGLETON = "singleton";
    String SCOPE_PROTOTYPE = "prototype";
    int ROLE_APPLICATION = 0;
    int ROLE_SUPPORT = 1;
    int ROLE_INFRASTRUCTURE = 2;
    ...
}

AbstractBeanDefinition.java

public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor implements BeanDefinition, Cloneable {
    public static final String SCOPE_DEFAULT = "";
    public static final int AUTOWIRE_NO = 0;
    public static final int AUTOWIRE_BY_NAME = 1;
    public static final int AUTOWIRE_BY_TYPE = 2;
    public static final int AUTOWIRE_CONSTRUCTOR = 3;
    /** @deprecated */
    @Deprecated
    public static final int AUTOWIRE_AUTODETECT = 4;
    public static final int DEPENDENCY_CHECK_NONE = 0;
    public static final int DEPENDENCY_CHECK_OBJECTS = 1;
    public static final int DEPENDENCY_CHECK_SIMPLE = 2;
    public static final int DEPENDENCY_CHECK_ALL = 3;
    public static final String INFER_METHOD = "(inferred)";
    private volatile Object beanClass;
    private String scope;
    private boolean abstractFlag;
    private boolean lazyInit;
    private int autowireMode;
    private int dependencyCheck;
    private String[] dependsOn;
    private boolean autowireCandidate;
    private boolean primary;
    private final Map<String, AutowireCandidateQualifier> qualifiers;
    private boolean nonPublicAccessAllowed;
    private boolean lenientConstructorResolution;
    private String factoryBeanName;
    private String factoryMethodName;
    private ConstructorArgumentValues constructorArgumentValues;
    private MutablePropertyValues propertyValues;
    private MethodOverrides methodOverrides;
    private String initMethodName;
    private String destroyMethodName;
    private boolean enforceInitMethod;
    private boolean enforceDestroyMethod;
    private boolean synthetic;
    private int role;
    private String description;
    private Resource resource;
    ...
}

BeanDefinitionRegistry(Bean注冊(cè)器)
在上面沒(méi)有看到xml bean中的id献起、name屬性對(duì)應(yīng)在bean定義中,原因是id其作為當(dāng)前bean的存儲(chǔ)key注冊(cè)到BeanDefinitionRegistry注冊(cè)器中姻政。name作為別名key注冊(cè)到AliasRegistry注冊(cè)中心岂嗓。其最后都是指向?qū)ο蟮腂eanDefinition。

BeanDefinitionRegistry.java

public interface BeanDefinitionRegistry extends AliasRegistry {
    void registerBeanDefinition(String var1, BeanDefinition var2) throws BeanDefinitionStoreException;

    void removeBeanDefinition(String var1) throws NoSuchBeanDefinitionException;

    BeanDefinition getBeanDefinition(String var1) throws NoSuchBeanDefinitionException;

    boolean containsBeanDefinition(String var1);

    String[] getBeanDefinitionNames();

    int getBeanDefinitionCount();

    boolean isBeanNameInUse(String var1);
}

AliasRegistry.java

public interface AliasRegistry {
    void registerAlias(String var1, String var2);

    void removeAlias(String var1);

    boolean isAlias(String var1);

    String[] getAliases(String var1);
}

BeanDefinitionReader(Bean定義讀取)
前面知道了BeanDefinition存儲(chǔ)了xml bean信息食绿,而BeanDefinitionRegistry基于id和name保存bean的定義公罕,下面是xml bean到BeanDefinition然后注冊(cè)到BeanDefinitionRegistry整個(gè)過(guò)程。

分為3步:

1熏兄、BeanDefinitionReader讀取spring.xml

2树姨、讀取后創(chuàng)建BeanDefinition

3、創(chuàng)建好后注冊(cè)到BeanDefinitionRegister

BeanDefinitionReader.java

public interface BeanDefinitionReader {
    //獲取注冊(cè)器
    BeanDefinitionRegistry getRegistry();
    //獲取資源裝載器
    ResourceLoader getResourceLoader();
    //獲取bean類加載器
    ClassLoader getBeanClassLoader();

    BeanNameGenerator getBeanNameGenerator();
    //基于資源裝載Bean定義并注冊(cè)到注冊(cè)器
    int loadBeanDefinitions(Resource var1) throws BeanDefinitionStoreException;
    
    int loadBeanDefinitions(Resource... var1) throws BeanDefinitionStoreException;
    //基于資源路徑裝載Bean定義并注冊(cè)到注冊(cè)器
    int loadBeanDefinitions(String var1) throws BeanDefinitionStoreException;

    int loadBeanDefinitions(String... var1) throws BeanDefinitionStoreException;
}

裝載過(guò)程demo

package com.demo.spring;

import org.springframework.beans.factory.support.BeanDefinitionReader;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.SimpleBeanDefinitionRegistry;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;

import java.util.Arrays;

/**
 * com.demo.spring
 *
 * @author Zyy
 * @date 2019/2/13 11:34
 */
public class BeanDefinitionReaderTest {

    public static void main(String[] args) {
        //創(chuàng)建一個(gè)簡(jiǎn)單注冊(cè)器
        BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
        //創(chuàng)建bean定義讀取器
        BeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
        //創(chuàng)建資源讀取器
        DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
        //獲取資源
        Resource resource = resourceLoader.getResource("spring.xml");
        //裝載類定義
        reader.loadBeanDefinitions(resource);
        //打印構(gòu)建bean名稱
        System.out.println(Arrays.toString(registry.getBeanDefinitionNames()));
    }
}

運(yùn)行結(jié)果

[di, driver, com.demo.spring.HelloSpring#0, com.demo.spring.LookUpTest#0, helloSpring, com.demo.spring.DI#1, com.demo.spring.DI#0, helloByName]

如果未給bean設(shè)置id則:class+#+索引,來(lái)標(biāo)識(shí)id

com.demo.spring.HelloSpring#0

打印一下bean定義信息

spring.xml

 <bean id="di" name="di2" lazy-init="false" class="com.demo.spring.DI" scope="singleton" init-method="init" destroy-method="destroy"/>

打印語(yǔ)句:

System.out.println(registry.getBeanDefinition("di"));
System.out.println(registry.getAliases("di2"));

結(jié)果信息:

Generic bean: class [com.demo.spring.DI]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=init; destroyMethodName=destroy; defined in class path resource [spring.xml]
[Ljava.lang.String;@73a28541
BeanFactory(bean工廠)

有了Bean的定義转晰,則下面可以用BeanFactory來(lái)進(jìn)行構(gòu)建bean。

BeanFactory.java

public interface BeanFactory {

    String FACTORY_BEAN_PREFIX = "&";
    //基于id或name獲取一個(gè)bean
    Object getBean(String name) throws BeansException;
    //基于bean的類別獲取bean(如果出現(xiàn)多個(gè)該類的實(shí)例蔗崎,則會(huì)報(bào)錯(cuò))但是可以指定primary="true"調(diào)整優(yōu)先級(jí)來(lái)解決該報(bào)錯(cuò)
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;
    
    <T> T getBean(Class<T> requiredType) throws BeansException;
    //基于名詞獲取一個(gè)bean扰藕,并覆蓋默認(rèn)的構(gòu)造參數(shù)
    Object getBean(String name, Object... args) throws BeansException;

    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

    boolean containsBean(String name);

    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
    //指定bean與指定class是否匹配
    boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;


    Class<?> getType(String name) throws NoSuchBeanDefinitionException;

    String[] getAliases(String name);

}

測(cè)試demo如下:

package com.demo.spring;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.DefaultResourceLoader;

/**
 * com.demo.spring
 *
 * @author Zyy
 * @date 2019/2/13 12:19
 */
public class BeanFactoryTest {

    public static void main(String[] args) {
        //注冊(cè)中心
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        //讀取器
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        //設(shè)置資源加載器
        reader.setResourceLoader(new DefaultResourceLoader());
        //裝載構(gòu)建bean的定義
        reader.loadBeanDefinitions("spring.xml");
        //打印
        System.out.println(beanFactory.getBean("di"));
        System.out.println(beanFactory.getBean("di2"));
    }
}

當(dāng)getBean時(shí)邓深,看下堆棧信息,如下

 at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:142)
  at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:89)
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1147)
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1099)
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
  at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
  at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
  - locked <0x593> (a java.util.concurrent.ConcurrentHashMap)
  at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
  at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
  at com.demo.spring.BeanFactoryTest.main(BeanFactoryTest.java:25)

看具體調(diào)用方法

instantiateClass:142, BeanUtils (org.springframework.beans)
instantiate:89, SimpleInstantiationStrategy (org.springframework.beans.factory.support)
instantiateBean:1147, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
createBeanInstance:1099, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
doCreateBean:513, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
createBean:483, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
getObject:306, AbstractBeanFactory$1 (org.springframework.beans.factory.support)
getSingleton:230, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support)
doGetBean:302, AbstractBeanFactory (org.springframework.beans.factory.support)
getBean:197, AbstractBeanFactory (org.springframework.beans.factory.support)
main:25, BeanFactoryTest (com.demo.spring)

逐個(gè)點(diǎn)進(jìn)去查看

org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)

@Override
public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}

AbstractBeanFactory#getBean中繼續(xù)調(diào)用doGetBean冬耿,查看doGetBean亦镶,由于其中代碼太多日月,刪除檢查判斷山孔,只保留核心代碼

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

protected <T> T doGetBean(
        final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
        throws BeansException {

    final String beanName = transformedBeanName(name);
    Object bean;

    // Eagerly check singleton cache for manually registered singletons.
    //從單例緩存中獲取
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    } else {
        
        // Check if bean definition exists in this factory.
        //從父類工廠中獲取
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            // Not found -> check parent.
            String nameToLookup = originalBeanName(name);
            if (args != null) {
                // Delegation to parent with explicit args.
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else {
                // No args -> delegate to standard getBean method.
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
        }

        if (!typeCheckOnly) {
            markBeanAsCreated(beanName);
        }

        try {
            
            // Create bean instance.
            //mbd -> RootBeanDefinition
            //判斷是否單例
            if (mbd.isSingleton()) {
                sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                    @Override
                    public Object getObject() throws BeansException {
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            ...
                        }
                    }
                });
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            } else if (mbd.isPrototype()) {
                // It's a prototype -> create a new instance.
                Object prototypeInstance = null;
                try {
                    beforePrototypeCreation(beanName);
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    afterPrototypeCreation(beanName);
                }
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }

            else {
                String scopeName = mbd.getScope();
                final Scope scope = this.scopes.get(scopeName);
                if (scope == null) {
                    throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                }
                try {
                    Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                        @Override
                        public Object getObject() throws BeansException {
                            beforePrototypeCreation(beanName);
                            try {
                                return createBean(beanName, mbd, args);
                            }
                            finally {
                                afterPrototypeCreation(beanName);
                            }
                        }
                    });
                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {
                    ...
                }
            }
        }
        catch (BeansException ex) {
            ...
        }
    }

    return (T) bean;
}

其中

Object sharedInstance = getSingleton(beanName);


org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName);
        //如果取到的為null且判斷是正在創(chuàng)建
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            //則鎖住map
            synchronized (this.singletonObjects) {
                //從正在創(chuàng)建的earlySingletonObjects這個(gè)map中去取
                singletonObject = this.earlySingletonObjects.get(beanName);
                //如果還是取不到
                if (singletonObject == null && allowEarlyReference) {
                    //從工廠獲取
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                    //如果獲取到
                    if (singletonFactory != null) {
                        singletonObject = singletonFactory.getObject();
                        //獲取到則放到緩存中
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        //從工廠中移除
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return (singletonObject != NULL_OBJECT ? singletonObject : null);
    }

其中singletonObjects、earlySingletonObjects勒庄、singletonFactories均是一個(gè)map

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

private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

對(duì)于其中的

bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);

org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance

if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
        return beanInstance;
    }

其中如果是FactoryBean,則調(diào)用getObject()來(lái)獲取我們自定義的bean荡碾,例如

<!-- FactoryBean創(chuàng)建 自定義創(chuàng)建bean-->
<bean id="driver" class="com.demo.spring.DriverFactoryBean" >
   <property name="jdbcUrl" value="jdbc:mysql://192.168.5.104:3306"></property>
</bean>

其中返回的不是DriverFactoryBean局装,而是返回Driver

public Class<?> getObjectType() {
    return Driver.class;
}

總結(jié):

1、調(diào)用BeanFactory.getBean()會(huì)觸發(fā)Bean的實(shí)例化铐尚。

2、DefaultSingletonBeanRegistry中緩存了單例Bean玫膀。

3、Bean的創(chuàng)建于初始化是由AbstractAutowireCapableBeanFactory完成的帖旨。

另外:

IOC容器只存放單例Bean灵妨,IOC容器在初始化的時(shí)候,會(huì)將所以Bean初始化在singletonObjects這個(gè)ConcurrentHashMap中泌霍。
在獲取bean的時(shí)候,首先會(huì)去singletonObjects中去取碉熄,如果scope是單例則可以獲取bean,如果是多例锈津,則取不到bean,需要從mergedBeanDefinitions這個(gè)ConcurrentHashMap中獲取RootBeanDefinition琼梆,這個(gè)里面包含bean的基礎(chǔ)信息,然后判斷scope是prototype(多例)茎杂,則每次都會(huì)創(chuàng)建一個(gè)新的實(shí)例。

對(duì)于@Autowire煌往、@Resource等注解,在啟動(dòng)SpringIOC容器時(shí)羞海,容器會(huì)裝載一個(gè)AutowiredAnnotationBeanPostProcessor 后置處理器,當(dāng)容易掃描到@Autowire却邓、@Resource等注解時(shí)院水,就會(huì)在IOC容器中自動(dòng)查找需要的Bean,并裝配給該對(duì)象的屬性檬某,在使用@Autowire時(shí),首先在容器中查詢對(duì)應(yīng)類型的bean橙喘,如果查詢不止一個(gè),則根據(jù)名稱來(lái)查,如果名稱沒(méi)有則拋異常初坠,可以將required=false來(lái)解決,如果正好查詢到一個(gè)碟刺,則就將該bean裝配給@Autowire指定的變量。

對(duì)于bean之間相互引用的情況半沽,比如A依賴B,B依賴A者填,這種情況時(shí),先去實(shí)例化A心墅,然后發(fā)現(xiàn)依賴B酿矢,接著去實(shí)例化B瘫筐,如果此時(shí)發(fā)現(xiàn)B依賴A,容器會(huì)獲取A的一個(gè)早期引用(early reference)策肝,將這個(gè)早期引用的A注入給B隐绵,然后B實(shí)例化完了,則實(shí)例化A也就完成了氢橙。當(dāng)然對(duì)于這種循環(huán)引用的代碼應(yīng)該規(guī)避,這種不是正常的場(chǎng)景帘睦。

涉及的類:

BeanDefinition

DefaultResourceLoader

XmlBeanDefinitionReader

BeanDefinitionRegistry

BeanFactory

DefaultListableBeanFactory

AutowireCapableBeanFactory

AbstractAutowireCapableBeanFactory

SingletonBeanRegistry

DefaultSingletonBeanRegistry

整個(gè)流程:

run->getBean->BeanFactory->doGetBean->AbstructBeanFactory
->getSingleton(從緩存中獲取坦康,如果是單例,為空則創(chuàng)建并緩存滞欠,如果是多例則直接創(chuàng)建)
->DefaultSingleonBeanRegistry->createBean->AbstractAutowireCapableBeanFactory
->createBeanInstance->newInstance->Constructor->反射實(shí)例化Bean
BeanFactory 與 ApplicationContext區(qū)別

看下結(jié)構(gòu)圖

ApplicationContext.java

ApplicationContext.png

從圖中可以看到ApplicationContext是由BeanFactory接口派生出來(lái)的,具有BeanFactory所以功能逸绎。除此之外夭谤,還具有以下功能:

1、MessageSource朗儒,提供國(guó)際化的消息訪問(wèn)

2、資源訪問(wèn)醉锄,入url和文件

3、事件傳播恳不,實(shí)現(xiàn)了ApplicationListener接口的bean

4、載入多個(gè)上下文(有繼承關(guān)系)识啦,使每個(gè)上下文都專注于一個(gè)特定的層次负蚊,比如應(yīng)用web層

類似的

DefaultListableBeanFactory.java

DefaultListableBeanFactory.png

github地址 : https://github.com/zhaoyybalabala/spring-test

如有問(wèn)題家妆,歡迎提問(wèn):)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末冕茅,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子哨坪,更是在濱河造成了極大的恐慌,老刑警劉巖乍楚,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件当编,死亡現(xiàn)場(chǎng)離奇詭異徒溪,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)臊泌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門鲤桥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)茶凳,“玉大人,你說(shuō)我怎么就攤上這事贮喧〖羯郑” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)运挫。 經(jīng)常有香客問(wèn)我,道長(zhǎng)谁帕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任碾牌,我火速辦了婚禮康愤,結(jié)果婚禮上征冷,老公的妹妹穿的比我還像新娘。我一直安慰自己检激,他們只是感情好腹侣,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著饺律,像睡著了一般。 火紅的嫁衣襯著肌膚如雪复濒。 梳的紋絲不亂的頭發(fā)上帖鸦,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音作儿,去河邊找鬼。 笑死晾嘶,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的垒迂。 我是一名探鬼主播妒蛇,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼吏奸!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起奋蔚,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎坤按,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體臭脓,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡沉桌,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了佃扼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蔼夜。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖求冷,靈堂內(nèi)的尸體忽然破棺而出瘤运,到底是詐尸還是另有隱情拯坟,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布郁季,位于F島的核電站钱磅,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏盖淡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一冗恨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧味赃,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)吠谢。三九已至,卻和暖如春工坊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背王污。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留昭齐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓就谜,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親丧荐。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

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

  • 2.1 我們的理念是:讓別人為你服務(wù) IoC是隨著近年來(lái)輕量級(jí)容器(Lightweight Container)的...
    好好學(xué)習(xí)Sun閱讀 2,700評(píng)論 0 11
  • Spring 最重要的概念是 IOC 和 AOP,本篇文章其實(shí)就是要帶領(lǐng)大家來(lái)分析下 Spring 的 IOC 容...
    程序猿天璇閱讀 804評(píng)論 0 5
  • 1割去、概述 ????spring的兩大核心:IOC(依賴注入)和AOP(面向切面),IOC本質(zhì)上就是一個(gè)線程安全的h...
    ALivn_3cf3閱讀 584評(píng)論 0 3
  • 1.Spring整體架構(gòu) 1)核心容器(Core Container) Core模塊夸赫,主要包含了Spring框架基...
    Sponge1128閱讀 1,051評(píng)論 0 1
  • 昨日妹妹說(shuō)小姑問(wèn)起我對(duì)象咖城,問(wèn)他對(duì)我好不好茬腿,聽不聽我的話切平。 妹妹說(shuō),好呀悴品,姐姐走到哪他跟到哪,每天在我們家干活到十二...
    張小汝閱讀 280評(píng)論 12 8