您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關 Spring5.x 中容器啟動源碼怎么寫,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。
Spring 已經是十分成熟的一個框架,此篇為開天辟地的Spring源碼分析首發。讀源碼本來就是一件十分枯燥,具有一定難度,技巧性的有重要意義的事。萬事開頭難,我會利用空余時間持續的跟進文章的連載。對于喜愛源碼的小伙伴,能夠提供一定的幫助。
最簡單的啟動spring的代碼如下:
import com.ld.test.config.AppConfig; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class TestDemo { public static void main(String[] args) { AnnotationConfigApplicationContext acac = new AnnotationConfigApplicationContext(AppConfig.class); acac.close(); } }
AnnotationConfigApplicationContext
先來看一下AnnotationConfigApplicationContext類的UML圖,留個印象。
點開AnnotationConfigApplicationContext(AppConfig.class);方法查看源碼:
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) { // 調用默認無參構造器,里面有一大堆初始化邏輯 // 開天辟地初始化兩個類 // AnnotatedBeanDefinitionReader reader; // ClassPathBeanDefinitionScanner scanner; this(); // 把傳入的Class進行注冊,Class既可以有@Configuration注解,也可以沒有@Configuration注解 // // 有@Configuration // map.put("org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass","full") // 沒有有@Configuration // map.put("org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass","lite") // // 怎么注冊? 委托給了 org.springframework.context.annotation.AnnotatedBeanDefinitionReader.register 方法進行注冊 // 傳入Class 生成 BeanDefinition , 然后通過 注冊到 BeanDefinitionRegistry register(annotatedClasses); // 刷新容器上下文 refresh(); }
該構造器允許我們傳入一個或者多個class對象。class對象可以是被@Configuration標注的,也可以是一個普通的Java 類。
有參構造器調用了無參構造器,點開源碼:
public AnnotationConfigApplicationContext() { // 隱式調用父類構造器,初始化beanFactory,具體實現類為DefaultListableBeanFactory // super(); // 創建 AnnotatedBeanDefinitionReader, // 創建時會向傳入的 BeanDefinitionRegistry 中 注冊 注解配置相關的 processors 的 BeanDefinition this.reader = new AnnotatedBeanDefinitionReader(this); // 通過后面的源碼探究也可以發現,spring并不是使用這個scanner來掃描包獲取Bean的 this.scanner = new ClassPathBeanDefinitionScanner(this); }
初始化子類時會先初始化父類,會默認調用父類無參構造器。AnnotationConfigApplicationContext繼承了GenericApplicationContext,在GenericApplicationContext的無參構造器中,創建了BeanFactory的具體實現類DefaultListableBeanFactory。spring中的BeanFactory就是在這里被實例化的,并且使用DefaultListableBeanFactory做的BeanFactory的默認實現。
public GenericApplicationContext() { this.beanFactory = new DefaultListableBeanFactory(); }
DefaultListableBeanFactory
AnnotationConfigApplicationContext的構造器中還創建了兩個對象:AnnotatedBeanDefinitionReader 和 ClassPathBeanDefinitionScanner。
ClassPathBeanDefinitionScanner scanner
先說scanner的作用,通過查看源碼可以發現,這個scanner只有在手動調用AnnotationConfigApplicationContext的一些方法的時候才會被使用(通過后面的源碼探究也可以發現,spring并不是使用這個scanner來掃描包獲取Bean的)
創建AnnotatedBeanDefinitionReader對象。spring在創建reader的時候把this當做了參數傳給了構造器。也就是說,reader對象里面包含了一個this對象,也就是AnnotationConfigApplicationContext對象。AnnotationConfigApplicationContext 實現了BeanDefinitionRegistry接口。點開this.reader = new AnnotatedBeanDefinitionReader(this);源碼:
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) { this(registry, getOrCreateEnvironment(registry)); }
從傳入的BeanDefinitionRegistry對象,也就是AnnotationConfigApplicationContext對象中獲取Environment(共用同一個Environment),然后又接著調用另一個構造器。點開源碼:
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); Assert.notNull(environment, "Environment must not be null"); this.registry = registry; this.conditionEvaluator = new ConditionEvaluator(registry, environment, null); //在 BeanDefinitionRegistry 中注冊 注解配置相關的 processors AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); }
在這個構造器中,執行了一個非常重要的方法AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); 顧名思義,spring通過這個方法注冊了解析注解配置相關的處理器。點開源碼:
第一步:設置屬性
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors( BeanDefinitionRegistry registry, @Nullable Object source) { DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry); if (beanFactory != null) { if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) { // AnnotationAwareOrderComparator是OrderComparator的子類,用來支持Spring的Ordered類、@Order注解和@Priority注解。 beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE); } if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) { // 設置依賴注入的候選處理器 // 可以看到只要不是ContextAnnotationAutowireCandidateResolver類型 直接升級為最強類型 beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); } } // 代碼省略。。。 }
注冊的是一些spring內置的PostProcessor的BeanDefinition
2.1、 ConfigurationClassPostProcessor
ConfigurationClassPostProcessor是一個BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor處理器,BeanDefinitionRegistryPostProcessor的處理方法能處理@Configuration等注解。ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry()方法內部處理@Configuration,@Import,@ImportResource和類內部的@Bean。
ConfigurationClassPostProcessor類繼承了BeanDefinitionRegistryPostProcessor。BeanDefinitionRegistryPostProcessor類繼承了BeanFactoryPostProcessor。通過BeanDefinitionRegistryPostProcessor可以創建一個特別后置處理器來將BeanDefinition添加到BeanDefinitionRegistry中。它和BeanPostProcessor不同,BeanPostProcessor只是在Bean初始化的時候有個鉤子讓我們加入一些自定義操作;而BeanDefinitionRegistryPostProcessor可以讓我們在BeanDefinition中添加一些自定義操作。在Mybatis與Spring的整合中,就利用到了BeanDefinitionRegistryPostProcessor來對Mapper的BeanDefinition進行了后置的自定義處理。
2.2、AutowiredAnnotationBeanPostProcessor
AutowiredAnnotationBeanPostProcessor是用來處理@Autowired注解和@Value注解的
2.3、RequiredAnnotationBeanPostProcessor
RequiredAnnotationBeanPostProcessor這是用來處理@Required注解
2.4、CommonAnnotationBeanPostProcessor
提供對JSR-250規范注解的支持@javax.annotation.Resource、@javax.annotation.PostConstruct和@javax.annotation.PreDestroy等的支持。
2.5、EventListenerMethodProcessor
EventListenerMethodProcessor提供@PersistenceContext的支持。
EventListenerMethodProcessor提供@ EventListener 的支持。@ EventListener實在spring4.2之后出現的,可以在一個Bean的方法上使用@EventListener注解來自動注冊一個ApplicationListener。
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors( BeanDefinitionRegistry registry, @Nullable Object source) { // 代碼省略。。。。 Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8); // 第一個問題 了解 RootBeanDefinition - > AbstractBeanDefinition // 第二個問題 了解 registerPostProcessor(); if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { //org.springframework.context.annotation.internalConfigurationAnnotationProcessor - ConfigurationClassPostProcessor.class //這個類非常的重要,它是一個 BeanDefinitionRegistryPostProcessor RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); } // 代碼省略。。。。 邏輯差不多 return beanDefs; }
我們發現:內部定義的class都是帶internal的
beanDefs">
1、該方法從傳入的BeanDefinitionRegistry對象,也就是AnnotationConfigApplicationContext對象中獲取到DefaultListableBeanFactory對象。
2、為獲取的DefaultListableBeanFactory對象設置屬性
3、往DefaultListableBeanFactory對象中注冊BeanDefinition,注冊的是一些spring內置的PostProcessor的BeanDefinition(關于BeanDefinition的介紹下期在講)。注意,此時只是注冊BeanDefinition,并沒有實例化bean。默認情況下,執行完該方法后,spring容器中所注冊的BeanDefinition為:
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
ROLE_INFRASTRUCTURE = 2 就是我這Bean是Spring自己的,和你用戶沒有一毛錢關系
private static BeanDefinitionHolder registerPostProcessor( BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) { definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registry.registerBeanDefinition(beanName, definition); return new BeanDefinitionHolder(definition, beanName); }
所謂的注冊BeanDefinition,簡單理解就是將BeanDefinition放到DefaultListableBeanFactory.registerBeanDefinition對象的beanDefinitionMap中
@Override 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"); if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName); //第一次進來existingDefinition肯定為null if (existingDefinition != null) { // 代碼省略。。。 this.beanDefinitionMap.put(beanName, beanDefinition); } else { if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; removeManualSingletonName(beanName); } } else { // Still in startup registration phase this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); removeManualSingletonName(beanName); } this.frozenBeanDefinitionNames = null; } if (existingDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
到此為止:DefaultListableBeanFactory.beanDefinitionMap 只有默認的spring beanDefinition
====下面是大家熟悉的注冊默認6大后置處理器:====
1.ConfigurationClassPostProcessor
2.AutowiredAnnotationBeanPostProcessor
3.CommonAnnotationBeanPostProcessor
4.Jpa的PersistenceAnnotationProcessor(沒導包就不會注冊)
5.EventListenerMethodProcessor
6.DefaultEventListenerFactory
public AnnotationConfigApplicationContext() { /** * 創建一個讀取注解的Bean定義讀取器 * 什么是bean定義?BeanDefinition * * 完成了spring內部BeanDefinition的注冊(主要是后置處理器) */ this.reader = new AnnotatedBeanDefinitionReader(this); /** * 創建BeanDefinition掃描器 * 可以用來掃描包或者類,繼而轉換為bd * * spring默認的掃描包不是這個scanner對象 * 而是自己new的一個ClassPathBeanDefinitionScanner * spring在執行工程后置處理器ConfigurationClassPostProcessor時,去掃描包時會new一個ClassPathBeanDefinitionScanner * * 這里的scanner僅僅是為了程序員可以手動調用AnnotationConfigApplicationContext對象的scan方法 * */ this.scanner = new ClassPathBeanDefinitionScanner(this); }
下一步
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment, @Nullable ResourceLoader resourceLoader) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); this.registry = registry; // 這個肯定成功 if (useDefaultFilters) { /** * 注冊spring掃描類過濾器 * 加了特定注解的類會被掃描到 * 帶有@Component、@Repository、@Service、@Controller、@ManagedBean、@Named */ registerDefaultFilters(); } setEnvironment(environment); setResourceLoader(resourceLoader); }
只關心最后一個構造函數的registerDefaultFilters();方法
/** * 注冊過濾器 * 帶有@Component、@Repository、@Service、@Controller、@ManagedBean、@Named * 注解的類會被spring掃描到 * * Register the default filter for {@link Component @Component}. * <p>This will implicitly register all annotations that have the * {@link Component @Component} meta-annotation including the * {@link Repository @Repository}, {@link Service @Service}, and * {@link Controller @Controller} stereotype annotations. * <p>Also supports Java EE 6's {@link javax.annotation.ManagedBean} and * JSR-330's {@link javax.inject.Named} annotations, if available. * */ @SuppressWarnings("unchecked") protected void registerDefaultFilters() { this.includeFilters.add(new AnnotationTypeFilter(Component.class)); ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader(); try { this.includeFilters.add(new AnnotationTypeFilter( ((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false)); logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning"); } catch (ClassNotFoundException ex) { // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip. } try { this.includeFilters.add(new AnnotationTypeFilter( ((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false)); logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning"); } catch (ClassNotFoundException ex) { // JSR-330 API not available - simply skip. } }
掃描過濾器includeFilters與excludeFilters
首先這里的includeFilters大家熟悉嗎,還有個excludeFilters,先看一下屬性
private final List<TypeFilter> includeFilters = new LinkedList<>(); private final List<TypeFilter> excludeFilters = new LinkedList<>();
這里提前往includeFilters里面添加需要掃描的特定注解
1.添加元注解@Component,需要注意的是@Repository、@Service、@Controller里面都標注了@Component。很好理解,掃描的時候用includeFilters 去過濾時,會找到并處理這4個注解的類。
2.下面兩個注解@ManagedBean、@Named需要有對應的jar包,否則(也就是說把這個方法走完),includeFilters里面只會有一個元素
this.reader = new AnnotatedBeanDefinitionReader(this); 完成了spring內部BeanDefinition的注冊(主要是后置處理器)
1、beanDefinitionMap存放了所有的Defintion 以 key-value
2、List<String> beanDefinitionNames 存放了所有的beanDefintion名字
this.scanner = new ClassPathBeanDefinitionScanner(this);
1、這里的scanner僅僅是為了程序員可以手動調用AnnotationConfigApplicationContext對象的scan方法
2、提供了includeFilters 和 excludeFilters 這里是一個擴展點
看完上述內容,你們對 Spring5.x 中容器啟動源碼怎么寫有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。