国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

追蹤解析Spring ioc啟動源碼(1)

Cheng_Gang / 3133人閱讀

摘要:主要過程為調用自身的另一個有參構造器此處的即為本身此處的最終返回一個調用無參構造器創建出來的對象參數非空效驗保存創建一個用于注解解析器,后面會用到注冊需要用到的顧名思義,即為所處的環境,包括配置的讀取等。

零 前期準備 0 FBI WARNING

文章異常啰嗦且繞彎。

1 版本

spring版本 : spring 5.1.2.RELEASE

IDE : idea 2018.3

2 Bean Demo
package ioc;

/**
 * java bean
 */
public class Person {

    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}
3 Config Demo
package ioc;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 配置類
 */
@Configuration
public class IocConfig {

    /**
        * 用代碼配置方式注入一個bean
        */
    @Bean(name = "person")
    public Person getPerson(){
        Person person = new Person();
        person.setAge(100);
        person.setName("張三");
        return person;
    }
}
4 main方法
package ioc;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class IocTest {

    public static void main(String[] args){
        ApplicationContext context = new AnnotationConfigApplicationContext(IocConfig.class);
        Person person = (Person) context.getBean("person");
        System.out.println(person.getName() + " , " + person.getAge());
    }
}
一 項目的啟動和Bean的注入 1 總覽

Spring 的初始化被封裝在這行代碼中:

ApplicationContext context = new AnnotationConfigApplicationContext(IocConfig.class);

這個構造器方法內部有三行代碼:

public AnnotationConfigApplicationContext(Class... annotatedClasses) {
    this();                            // 2 無參構造器
    register(annotatedClasses);        // 3 reader 注冊配置類
    refresh();                        // 4 在 bean factory 中創造 bean
}
2 無參構造器

該 part 的起點為 AnnotationConfigApplicationContext 調用自身的無參構造器:

//AnnotationConfigApplicationContext.class
public AnnotationConfigApplicationContext(Class... annotatedClasses) {
    this();                            // 2 無參構造器
    register(annotatedClasses);
    refresh();
}

追蹤無參構造器:

//AnnotationConfigApplicationContext.class
public AnnotationConfigApplicationContext() {
    this.reader = new AnnotatedBeanDefinitionReader(this); //2.1
    this.scanner = new ClassPathBeanDefinitionScanner(this); //2.5
}

AnnotatedBeanDefinitionReader 創建的過程中會將 Spring 自身需要的 bean 和配置用的 bean 注冊到 bean factory 中。

【ClassPathBeanDefinitionScanner 本例中暫時用不到,不做詳細分析,只簡單看一下構造方法】

AnnotationConfigApplicationContext 的父類 GenericApplicationContext 會在無參構造器中創建一個 DefaultListableBeanFactory ,也就是本例中的 bean factory:

//GenericApplicationContext.class
public GenericApplicationContext() {
    this.beanFactory = new DefaultListableBeanFactory();
}

DefaultListableBeanFactory 內部會維護了多個 ConcurrentHashMap 對象,用于分門別類地保存 bean。

最主要的一個 map 對象是 singletonObjects。這個對象被定義在 DefaultSingletonBeanRegistry 中,用于存放所有的單例 bean:

//DefaultSingletonBeanRegistry.class
private final Map singletonObjects = new ConcurrentHashMap<>(256);
2.1

AnnotatedBeanDefinitionReader 創建的過程中將 spring 需要的幾個 processor bean 注冊到 DefaultListableBeanFactory 中。主要過程為:

//AnnotatedBeanDefinitionReader.class
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
    //調用自身的另一個有參構造器
    //此處的 registry 即為 AnnotationConfigApplicationContext 本身
    //此處的 getOrCreateEnvironment(registry) 最終返回一個調用 StandardEnvironment 無參構造器創建出來的對象
    this(registry, getOrCreateEnvironment(registry));
}

//AnnotatedBeanDefinitionReader.class
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
    //參數非空效驗
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    Assert.notNull(environment, "Environment must not be null");
    
    //保存 AnnotationConfigApplicationContext
    this.registry = registry;
    //創建一個用于注解解析器,后面會用到
    this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);

    //注冊 Spring 需要用到的 processor bean
    AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

Environment 顧名思義,即為 Spring 所處的環境,包括 properties 配置的讀取等。本例中暫時沒有用到,按下不表。

上述代碼的核心是調用 AnnotationConfigUtils 的 registerAnnotationConfigProcessors(...) 方法,繼續追蹤:

//AnnotationConfigUtils.class
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
    registerAnnotationConfigProcessors(registry, null);
}

//AnnotationConfigUtils.class
public static Set registerAnnotationConfigProcessors(
        BeanDefinitionRegistry registry, @Nullable Object source) {

    //獲取 bean factory
    DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
    
    //以下代碼設置了 beanFactory 的兩個內部對象,暫時不展開
    if (beanFactory != null) {
        if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
            beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
        }
        if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
            beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        }
    }

    //新建一個集合,用于在方法末尾返回所有注冊的 bean 的包裝類,但是實際上本例中沒有接收返回值,所以可以忽略
    Set beanDefs = new LinkedHashSet<>(8);

    //判斷 bean factory 中是否存在這個名稱的 bean,如果不存在就注冊一個,以下雷同
    if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        //將要注冊的 processor class 包裝成一個 BeanDefinition
        RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
        //本例中 source 為 null
        def.setSource(source);
        //注冊 bean,并添加到集合中
        beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    //jsr250Present 與 jpaPresent 均為 boolean 類型的變量
    //jsr250Present 的意思是檢查是否對 JSR-250 標準進行支持,jpaPresent 的意思是檢查是否對 JPA 標準進行支持
    //目前 Spring 支持 JSR-250 標準,不支持 JPA 標準
    if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition();
        try {
            def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
                    AnnotationConfigUtils.class.getClassLoader()));
        }catch (ClassNotFoundException ex) {
            throw new IllegalStateException(
                    "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
        }
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
    }

    if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
    }

    //返回上述的集合
    return beanDefs;
}

該方法中主體代碼都是雷同的,即為:

if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    //將要注冊的 processor class 包裝成一個 BeanDefinition
    RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
    //本例中 source 為 null
    def.setSource(source);
    //注冊 bean ,并添加到集合中
    beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME : org.springframework.context.annotation.internalConfigurationAnnotationProcessor
CONFIGURATION_BEAN_NAME_GENERATOR : org.springframework.context.annotation.internalConfigurationBeanNameGenerator
AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME : org.springframework.context.annotation.internalAutowiredAnnotationProcessor
COMMON_ANNOTATION_PROCESSOR_BEAN_NAME : org.springframework.context.annotation.internalCommonAnnotationProcessor
PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME : org.springframework.context.annotation.internalPersistenceAnnotationProcessor
PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME : org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor
EVENT_LISTENER_PROCESSOR_BEAN_NAME : org.springframework.context.event.internalEventListenerProcessor
EVENT_LISTENER_FACTORY_BEAN_NAME : org.springframework.context.event.internalEventListenerFactory

這些常量都是 spring 中類的路徑和名稱。

registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)

此行代碼會通過 AnnotationConfigApplicationContext 調用到 DefaultListableBeanFactory 內部的 beanDefinitionMap 對象,最終查詢到這個 bean 對象是否已經被注冊。如果不存在,則執行下方的注冊操作。

beanDefinitionMap 是 DefaultListableBeanFactory 內部存放所有已經注冊了的 bean 的信息的 ConcurrentHashMap 對象,后面會經常提到。

RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);

RootBeanDefinition 是 BeanDefinition 的實現類。BeanDefinition 是 Spring 中 bean 的描述包裝接口,用于保存 bean 的各類信息,包括且不限于 bean 的名稱、父類、注解、是否惰性加載等屬性。

Set beanDefs = new LinkedHashSet<>(8);

BeanDefinitionHolder 是 BeanDefinition 的支持類,內部存儲了 BeanDefinition 、bean name 、bean aliases(別名)。

【在 Spring 的 bean 注冊過程中,有多次 BeanDefinition 和 BeanDefinitionHolder 的包裝和解包裝操作,具體有待學習】

registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)

起主要作用的是上面這行代碼。追蹤這個方法的實現:

//AnnotationConfigUtils.class
private static BeanDefinitionHolder registerPostProcessor(
            BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {

    //bean 的角色定義
    //BeanDefinition.ROLE_INFRASTRUCTURE = 2
    definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

    //調用 AnnotationConfigApplicationContext 的 registerBeanDefinition 方法
    registry.registerBeanDefinition(beanName, definition);

    //返回一個封裝類
    return new BeanDefinitionHolder(definition, beanName);
}

BeanDefinition 的 role 是指該 bean 在 Spring 中的角色定義。對于 Spring 注冊進去的 processor bean,定義值均為 2,意思是 infrastructure(基礎設施)。

除此以外角色定義還有 application(應用) 和 support(支持)。

AnnotationConfigApplicationContext 內部其實沒有 registerBeanDefinition(...) 這個方法,而是繼承自 GenericApplicationContext:

//GenericApplicationContext.class
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {
    //2.2
    this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}

此方法實際上調用了 DefaultListableBeanFactory 的 registerBeanDefinition(...) 方法進行 bean 的注冊。

2.2

繼續追蹤方法的內部實現:

//DefaultListableBeanFactory.class
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
        throws BeanDefinitionStoreException {

    //參數非空驗證
    Assert.hasText(beanName, "Bean name must not be empty");
    Assert.notNull(beanDefinition, "BeanDefinition must not be null");

    //bean 的有效性驗證
    if (beanDefinition instanceof AbstractBeanDefinition) {
        try {
            ((AbstractBeanDefinition) beanDefinition).validate();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                    "Validation of bean definition failed", ex);
        }
    }

    //beanDefinitionMap 為存儲所有注冊 bean 信息的 map 對象
    //正常情況下此處獲取的應該是 null 值,即該 bean 的信息還未注冊
    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);

    if (existingDefinition != null) {

        //如果 bean 已經存在于 map 中,則需要判斷是否允許重寫 bean definition
        if (!isAllowBeanDefinitionOverriding()) { //不允許,拋出異常
            throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
        }else if (existingDefinition.getRole() < beanDefinition.getRole()) {
            if (logger.isInfoEnabled()) {
                logger.info("Overriding user-defined bean definition for bean "" + beanName +
                        "" with a framework-generated bean definition: replacing [" +
                        existingDefinition + "] with [" + beanDefinition + "]");
            }
        }else if (!beanDefinition.equals(existingDefinition)) {
            if (logger.isDebugEnabled()) {
                logger.debug("Overriding bean definition for bean "" + beanName +
                        "" with a different definition: replacing [" + existingDefinition +
                        "] with [" + beanDefinition + "]");
            }
        }else {
            if (logger.isTraceEnabled()) {
                logger.trace("Overriding bean definition for bean "" + beanName +
                        "" with an equivalent definition: replacing [" + existingDefinition +
                        "] with [" + beanDefinition + "]");
            }
        }
        //只要設置為允許重寫,就會在最后更新 map,只是記錄的 log 內容會不同
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }else { //正常情況下
        if (hasBeanCreationStarted()) { //2.3
            synchronized (this.beanDefinitionMap) {
                this.beanDefinitionMap.put(beanName, beanDefinition);
                List updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                updatedDefinitions.addAll(this.beanDefinitionNames);
                updatedDefinitions.add(beanName);
                this.beanDefinitionNames = updatedDefinitions;
                if (this.manualSingletonNames.contains(beanName)) {
                    Set updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
                    updatedSingletons.remove(beanName);
                    this.manualSingletonNames = updatedSingletons;
                }
            }
        }else {
            //將 bean 注冊入 beanDefinitionMap 中
            this.beanDefinitionMap.put(beanName, beanDefinition);
            //將 bean name 添加入 beanDefinitionNames 中
            this.beanDefinitionNames.add(beanName);
            //將 bean name 從 manualSingletonNames 中刪除
            this.manualSingletonNames.remove(beanName);
        }
        //清空數組
        this.frozenBeanDefinitionNames = null;
    }

    //2.4
    if (existingDefinition != null || containsSingleton(beanName)) {
        resetBeanDefinition(beanName);
    }
}

先來關注這行代碼:

((AbstractBeanDefinition) beanDefinition).validate();

追蹤一下這行代碼:

//AbstractBeanDefinition.class
public void validate() throws BeanDefinitionValidationException {
    if (hasMethodOverrides() && getFactoryMethodName() != null) {
        throw new BeanDefinitionValidationException(
                "Cannot combine static factory method with method overrides: " +
                "the static factory method must create the instance");
    }

    if (hasBeanClass()) {
        //此方法內部也主要用到了 hasMethodOverrides() ,這里暫時忽略該方法
        prepareMethodOverrides();
    }
}

這個方法內部使用了 AbstractBeanDefinition 內定義的 hasMethodOverrides() 和 getFactoryMethodName() 方法去判斷 beanDefinition 是否有效。同時滿足這兩個條件則會拋出異常。

根據官方文檔的描述,hasMethodOverrides() 為如果 bean factory 重寫了 bean 內的方法,就會返回 true;getFactoryMethodName() 為如果存在工廠方法就會返回該方法的名稱。

【沒有特別理解這幾個方法的應用場景,根據網上資料來看,應該和 bean 的反射創建有一些關系】

再來關注這行代碼:

this.frozenBeanDefinitionNames = null;

frozenBeanDefinitionNames 是定義在 DefaultListableBeanFactory 中的一個字符串數組,Spring 在完成 bean 注冊之后會將 beanDefinitionNames 轉成一個數組,并賦值給 frozenBeanDefinitionNames。

【此為 Spring 的一個內存優化操作】

2.3

看一下上述方法的片段:

if (hasBeanCreationStarted()) {
    synchronized (this.beanDefinitionMap) { //線程鎖

        //執行注冊操作
        this.beanDefinitionMap.put(beanName, beanDefinition);

        //用一個新的 list 去替換原來的
        List updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
        updatedDefinitions.addAll(this.beanDefinitionNames);
        updatedDefinitions.add(beanName);
        this.beanDefinitionNames = updatedDefinitions;

        //檢查單例 bean 名稱集合
        if (this.manualSingletonNames.contains(beanName)) {
            Set updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
            updatedSingletons.remove(beanName);
            this.manualSingletonNames = updatedSingletons;
        }
    }
}

先來追蹤一下 hasBeanCreationStarted() 這個方法的內部實現:

//AbstractBeanFactory.class
protected boolean hasBeanCreationStarted() {
    return !this.alreadyCreated.isEmpty();
}

alreadyCreated 是一個定義在 AbstractBeanFactory 中的集合,用于存放所有已經被創建(不是注冊,是創建)的 bean 的名字。在創建和獲取 bean 的時候都會去檢查該集合。

在 processors bean 和 iocConfig bean 的注冊階段,該集合為空,此方法返回 false。但是要注意,在 person bean 的注冊階段,此時 iocConfig bean 已經被創建出來了,所以此集合是非空的,此方法返回 true。

//創建新列表
List updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
//老列表被整個添加到新列表中
updatedDefinitions.addAll(this.beanDefinitionNames);
//添加 beanName 到新列表中
updatedDefinitions.add(beanName);
//替換
this.beanDefinitionNames = updatedDefinitions;

beanDefinitionNames 是一個定義在 DefaultListableBeanFactory 中的列表,用來存放所有注冊的 bean 的名字。

if (this.manualSingletonNames.contains(beanName)) {
    //新建一個集合,并且將 manualSingletonNames 集合放入新集合中
    Set updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
    //刪除這個 bean name
    updatedSingletons.remove(beanName);
    //替換
    this.manualSingletonNames = updatedSingletons;
}

manualSingletonNames 是一個定義在 DefaultListableBeanFactory 中的集合,用來存放已經被創建的單例 bean 的名字。因為是單例的,所以不允許重名 bean 的存在,這可能也是 Spring 這里使用集合的原因。

【Spring 的對于內存的優化精確到了每一個列表和集合的容量大小】

進入這個 if 判斷條件的情況下,必然是這個 bean 還沒有被創建,所以如果這個 bean 已經被放在在這個集合里,就需要刪除。正常情況下 bean 的注冊過程應該都不會進入執行這個代碼片段。

2.4

看一下上述方法的片段:

if (existingDefinition != null || containsSingleton(beanName)) {
    resetBeanDefinition(beanName);
}

判斷條件中的 existingDefinition 是上方定義的一個 BeanDefinition :

BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);

一般來說等于 null。

而 containsSingleton(...) 方法具體的實現是在 DefaultSingletonBeanRegistry 中:

//DefaultSingletonBeanRegistry.class
public boolean containsSingleton(String beanName) {
    return this.singletonObjects.containsKey(beanName);
}

上面文章中提到過,singletonObjects 是最終保存單例 bean 的 map 對象。

綜合來看就是此判斷條件可以理解為:如果該 bean 已經注冊或者已經被創建,則返回 true,若均未則返回 false。所以一般正常的注冊流程是不會執行 resetBeanDefinition(...) 方法的。

關于 resetBeanDefinition(...) 方法,不展開講了,大致來說就是此方法內部會重新去創建該 bean。

到此為止,reader 已經創建完畢,并且 Spring 使用到的 processors 也已經注冊完畢。DefaultListableBeanFactory.registerBeanDefinition 方法非常重要,后面 config bean 和 person bean 的注冊也是使用這個方法。

2.5

回到原點:

//AnnotationConfigApplicationContext.class
public AnnotationConfigApplicationContext() {
    this.reader = new AnnotatedBeanDefinitionReader(this);
    this.scanner = new ClassPathBeanDefinitionScanner(this); //2.4
}

本例中暫時沒有用到 ClassPathBeanDefinitionScanner,因為沒有掃描包路徑的方式去獲取 bean。所以此處略講一下 ClassPathBeanDefinitionScanner 的創建。

其構造方法有多層調用,最終的邏輯代碼如下:

//ClassPathBeanDefinitionScanner.class
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
            Environment environment, @Nullable ResourceLoader resourceLoader) {
    //參數非空效驗
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

    //此處的 registry 是 AnnotationConfigApplicationContext
    this.registry = registry;

    //Spring 掃描包路徑的過濾策略
    //useDefaultFilters = true
    if (useDefaultFilters) {
        registerDefaultFilters();
    }
    //存入環境對象,此處一個使用無參構造器創建出來的 StandardEnvironment 對象
    setEnvironment(environment);
    //存入 resourceLoader,此處為 AnnotationConfigApplicationContext
    setResourceLoader(resourceLoader);
}

【暫時不展開了】

To Be Continued ...

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/72608.html

相關文章

  • 追蹤解析Spring ioc啟動源碼(2)

    摘要:顧名思義,其主要作用是解析標簽。本例中沒有用到上述的注解,所以均為。繼續追蹤這行代碼的內部實現獲取的名稱調用的方法注冊過程見處理的別名,本例中沒有別名,不進入循環的具體內容有待研究,不展開。到此為止,已經被注冊到中。 接上篇 3 reader 注冊配置類 該 part 的起點: public AnnotationConfigApplicationContext(Class... ann...

    funnyZhang 評論0 收藏0
  • 重拾-Spring-IOC

    摘要:為何重拾使用了多年,但是對其底層的一些實現還是一知半解,一些概念比較模糊故決定重新拾起,加深對的認識。小結是在完成創建后對其進行后置處理的接口是在完成實例化對其進行的后置處理接口是框架底層的核心接口,其提供了創建,獲取等核心功能。 為何重拾 使用了 Spring 多年,但是對其底層的一些實現還是一知半解,一些概念比較模糊;故決定重新拾起,加深對 Spring 的認識。 重拾計劃 spr...

    GraphQuery 評論0 收藏0
  • Spring AOP從零單排-織入時期源碼分析

    摘要:何為簡單點來定義就是切面,是一種編程范式。定義一個切面的載體定義一個切點定義一個為,并指定對應的切點一個注冊配置類,啟動容器,初始化時期獲取對象,獲取對象時期,并進行打印好了,這樣我們整體的代理就已經完成。 問題:Spring AOP代理中的運行時期,是在初始化時期織入還是獲取對象時期織入? 織入就是代理的過程,指目標對象進行封裝轉換成代理,實現了代理,就可以運用各種代理的場景模式。 ...

    honmaple 評論0 收藏0
  • Spring專題之IOC源碼分析

    摘要:前言以下源碼基于版本解析。實現源碼分析對于的實現,總結來說就是定位加載和注冊。定位就是需要定位配置文件的位置,加載就是將配置文件加載進內存注冊就是通過解析配置文件注冊。下面我們從其中的一種使用的方式一步一步的分析的實現源碼。 前言 以下源碼基于Spring 5.0.2版本解析。 什么是IOC容器? 容器,顧名思義可以用來容納一切事物。我們平常所說的Spring IOC容器就是一個可以容...

    不知名網友 評論0 收藏0
  • SpringBoot 中 @SpringBootApplication注解背后的三體結構探秘

    摘要:概述約定大于配置的功力讓我們如沐春風,在我之前寫的文章從到也對比過和這兩個框架,不過最終以超高的代碼信噪比和易上手性讓我們映像頗深。至于,我想在非時代大家應該不陌生吧,作用是配置容器,也即形式的容器的配置類所使用。 showImg(https://segmentfault.com/img/remote/1460000015822144); 概 述 SpringBoot 約定大于配置...

    Tecode 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<