经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring » 查看文章
Spring IOC基于注解启动示例详析
来源:jb51  时间:2019/3/4 8:40:37  对本文有异议

Spring 基于注解启动

主要有两个Class实现注解启动

  • AnnotationConfigApplicationContext
  • AnnotationConfigWebApplicationContext

我们以AnnotationConfigApplicationContext 为研究对象


AnnotationConfigApplicationContext.png

引入Spring 最小依赖

  1. <dependency>
  2. <groupId>org.springframework</groupId>
  3. <artifactId>spring-context</artifactId>
  4. <version>${spring.version}</version>
  5. </dependency>

编写器启动代码

  1. public static void main(String[] args) {
  2. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  3. applicationContext.register(BeanConfig.class);
  4. applicationContext.refresh();
  5. Date date = applicationContext.getBean("date",Date.class);
  6. System.out.println(date);
  7. }

AnnotationConfigApplicationContext 构造函数

  1. public AnnotationConfigApplicationContext() {
  2. //负责注册Class ,读取器
  3. this.reader = new AnnotatedBeanDefinitionReader(this);
  4. //负责扫描指定类路径下的Class,注册bean
  5. this.scanner = new ClassPathBeanDefinitionScanner(this);
  6. }

AnnotatedBeanDefinitionReader 构造方法

  1. public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
  2. this(registry, getOrCreateEnvironment(registry));
  3. }
  4.  
  5. public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
  6. Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
  7. Assert.notNull(environment, "Environment must not be null");
  8. this.registry = registry;
  9. //初始化ConditionEvaluator
  10. this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
  11. /** 在給定的注册表中註冊所有相关的post processors
  12. * 判断容器是否已经存在给定注册表的bean,如果没有注册bean,并将bean放入容器中
  13. * 把所有的处理处理器列出来
  14. * ConfigurationClassPostProcessor 內部管理的配置注解处理器
  15. * AutowiredAnnotationBeanPostProcessor 内部管理@Autowired 的处理器
  16. * RequiredAnnotationBeanPostProcessor @Required的处理器
  17. * CommonAnnotationBeanPostProcessor JSR-250注解处理器 ,先判断是否支持jsr,如果支持注册
  18. * PersistenceAnnotationBeanPostProcessor JPA管理 先使用类加载器查找是否存在,如果有这个包则注册
  19. * EventListenerMethodProcessor @EventListener的处理器
  20. * DefaultEventListenerFactory 管理EventListenerFactory处理器
  21. */
  22. AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
  23. }

ConditionEvaluator 这个对象干什么,点击进去

  1. public ConditionEvaluator(@Nullable BeanDefinitionRegistry registry,
  2. @Nullable Environment environment, @Nullable ResourceLoader resourceLoader) {
  3.  
  4. this.context = new ConditionContextImpl(registry, environment, resourceLoader);
  5. }
  6. //ConditionContextImpl 实现了ConditionContext接口,ConditionEvaluator静态内部类
  7. public ConditionContextImpl(@Nullable BeanDefinitionRegistry registry,
  8. @Nullable Environment environment, @Nullable ResourceLoader resourceLoader) {
  9.  
  10. this.registry = registry;
  11. this.beanFactory = deduceBeanFactory(registry);
  12. this.environment = (environment != null ? environment : deduceEnvironment(registry));
  13. this.resourceLoader = (resourceLoader != null ? resourceLoader : deduceResourceLoader(registry));
  14. this.classLoader = deduceClassLoader(resourceLoader, this.beanFactory);
  15. }

可以知道ConditionEvaluator使用外部传参的方法初始化了Spring容器顶级对象
BeanFactory,Environment,ResourceLoader,ClassLoader。在将这些传给ConditionContextImpl为接下来的解析@Conditional注解做好准备

ClassPathBeanDefinitionScanner构造函数

  1. public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
  2. this(registry, true);
  3. }
  4.  
  5. public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
  6. this(registry, useDefaultFilters, getOrCreateEnvironment(registry));
  7. }
  8.  
  9. public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
  10. Environment environment) {
  11. this(registry, useDefaultFilters, environment,
  12. (registry instanceof ResourceLoader ? (ResourceLoader) registry : null));
  13. }
  14.  
  15. public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
  16. Environment environment, @Nullable ResourceLoader resourceLoader) {
  17. Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
  18. this.registry = registry;
  19. if (useDefaultFilters) {
  20. registerDefaultFilters();
  21. }
  22. setEnvironment(environment);
  23. setResourceLoader(resourceLoader);
  24. }
  25.  
  26. protected void registerDefaultFilters() {
  27. this.includeFilters.add(new AnnotationTypeFilter(Component.class));
  28. ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
  29. try {
  30. this.includeFilters.add(new AnnotationTypeFilter(
  31. ((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
  32. logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
  33. }
  34. catch (ClassNotFoundException ex) {
  35. }
  36. try {
  37. this.includeFilters.add(new AnnotationTypeFilter(
  38. ((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
  39. logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
  40. }
  41. catch (ClassNotFoundException ex) {
  42. // JSR-330 API not available - simply skip.
  43. }
  44. }

绕了地球几圈了,其实就是将Spring 顶级接口 Environment,ResourceLoader赋值,使用默认注解过滤器,首先将@Component加入List中,判断当前环境是否支持JSR-250,JSR-330,相应加入过滤器中。也就是这个扫描器默认只扫描@Component或者JSR-250,JSR-330的标记的Class。

applicationContext.register(BeanConfig.class)

  1. public void register(Class<?>... annotatedClasses) {
  2. Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
  3. this.reader.register(annotatedClasses); //调用 刚刚初始化读取器
  4. }
  5. |
  6. ============================AnnotatedBeanDefinitionReader 读取器代码======================================================================================================
  7. public void register(Class<?>... annotatedClasses) {
  8. for (Class<?> annotatedClass : annotatedClasses) {
  9. registerBean(annotatedClass);
  10. }
  11. }
  12.  
  13. public void registerBean(Class<?> annotatedClass) {
  14. doRegisterBean(annotatedClass, null, null, null);
  15. }
  16. /**
  17. *从给定的bean解析Class给定的注解,执行相应的初始化,保存到Spring容器中
  18. */
  19. <T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
  20. @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
  21.  
  22. //根据Class的Annotated 得出元数据 AnnotationMetadata
  23. AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
  24. /**
  25. * 判断注册的Class 是否包含@Conditional注解,如果有获取全部value,放入List中
  26. * 排序后,遍历所有的Conditiion的实现,使用反射获取对象,执行matches方法,
  27. * 如果发现有返回false,中断循环直接返回true,
  28. */
  29. if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) { //如果 @Conditional条件不满足,不进行注册
  30. return;
  31. }
  32.  
  33. abd.setInstanceSupplier(instanceSupplier);
  34. //解析Class是否有@Scope,解析@Scope注解返回ScopeMetadata对象,没有直接返回空
  35. ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
  36. abd.setScope(scopeMetadata.getScopeName());
  37. //判断注解上Value是否有值,有就使用这个作为BeanName,没有则取类名
  38. String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
  39. //继续解析AnnotationMetadata的@Lazy,@Primary,@DependsOn,@Role,@Description的注解,放入结果放入对象的属性中
  40. AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
  41. //这个类只是BeanDefinition 包装类
  42. BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
  43. //是否需要代理类,如果是则修改内部属性,重新生成BeanDefinition 对象
  44. definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
  45. //调用DefaultListableBeanFactory.registerBeanDefinition的方法,做一些安全性校验再,将definitionHolder 放入register容器中
  46. BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
  47. }

这个方法就是将注册的Bean,解析Class上的注解,初始化注解数据,做相应处理,转化成BeanDefinition ,放入Spring 容器中保存起来。

我们看下BeanDefinition是怎么实现注册到Spring的容器中,主要由DefaultListableBeanFactory.registerBeanDefinition来实现

  1. public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
  2. throws BeanDefinitionStoreException {
  3.  
  4. Assert.hasText(beanName, "Bean name must not be empty");
  5. Assert.notNull(beanDefinition, "BeanDefinition must not be null");
  6.  
  7. if (beanDefinition instanceof AbstractBeanDefinition) {
  8. try {
  9. //对beanDefinition 进行校验判断MethodOverrides不能为空,必须拥有工厂方法
  10. ((AbstractBeanDefinition) beanDefinition).validate();
  11. }
  12. catch (BeanDefinitionValidationException ex) {
  13. throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
  14. "Validation of bean definition failed", ex);
  15. }
  16. }
  17.  
  18. BeanDefinition oldBeanDefinition;
  19.  
  20. oldBeanDefinition = this.beanDefinitionMap.get(beanName);
  21. if (oldBeanDefinition != null) {
  22. //这个方法是判断是否允许出现重名bean,并且是不同的定义bean,是否可以覆盖前者
  23. if (!isAllowBeanDefinitionOverriding()) {
  24. throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
  25. "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
  26. "': There is already [" + oldBeanDefinition + "] bound.");
  27. }
  28. else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
  29. // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
  30. if (this.logger.isWarnEnabled()) {
  31. this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
  32. "' with a framework-generated bean definition: replacing [" +
  33. oldBeanDefinition + "] with [" + beanDefinition + "]");
  34. }
  35. }
  36. else if (!beanDefinition.equals(oldBeanDefinition)) {
  37. if (this.logger.isInfoEnabled()) {
  38. this.logger.info("Overriding bean definition for bean '" + beanName +
  39. "' with a different definition: replacing [" + oldBeanDefinition +
  40. "] with [" + beanDefinition + "]");
  41. }
  42. }
  43. else {
  44. if (this.logger.isDebugEnabled()) {
  45. this.logger.debug("Overriding bean definition for bean '" + beanName +
  46. "' with an equivalent definition: replacing [" + oldBeanDefinition +
  47. "] with [" + beanDefinition + "]");
  48. }
  49. }
  50. this.beanDefinitionMap.put(beanName, beanDefinition);
  51. }
  52. else {
  53. //调用alreadyCreated.isEmpty(),alreadyCreated Set对象,保存已经创建beanName
  54. //文档中表示created,跟这里注册应该不是同一个行为,这个要看到后面才知道什么意思
  55. if (hasBeanCreationStarted()) {
  56. synchronized (this.beanDefinitionMap) {//更新数据
  57. this.beanDefinitionMap.put(beanName, beanDefinition);
  58. List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
  59. updatedDefinitions.addAll(this.beanDefinitionNames);
  60. updatedDefinitions.add(beanName);
  61. this.beanDefinitionNames = updatedDefinitions;
  62. if (this.manualSingletonNames.contains(beanName)) {
  63. Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
  64. updatedSingletons.remove(beanName);
  65. this.manualSingletonNames = updatedSingletons;
  66. }
  67. }
  68. }
  69. else {
  70. //Spring beanDefinition 容器,一个Map转载
  71. this.beanDefinitionMap.put(beanName, beanDefinition);
  72. //保存beanName,主要用于记录每个bean注册顺序
  73. this.beanDefinitionNames.add(beanName);
  74. //删除单例,注册成一个普通bean
  75. this.manualSingletonNames.remove(beanName);
  76. }
  77. this.frozenBeanDefinitionNames = null;
  78. }
  79.  
  80. if (oldBeanDefinition != null || containsSingleton(beanName)) {
  81. //更新Spring容器里beanName
  82. resetBeanDefinition(beanName);
  83. }
  84. }

将beanDefinition注册到Spring容器中,并没有太多复杂的逻辑,只是做一些安全性的检查。

BeanDefinition

一个BeanDefinition描述了一个bean的实例,包括属性值,构造方法参数值和继承自它的类的更多信息。BeanDefinition仅仅是一个最简单的接口,主要功能是允许BeanFactoryPostProcessor 例如PropertyPlaceHolderConfigure 能够检索并修改属性值和别的bean的元数据(译注)

Spring 容器beanDefinition主要分为RootBeanDefinition,AnnotatedGenericBeanDefinition这两种

  • RootBeanDefinition     Spring Factory中的特定bean
  • AnnotatedGenericBeanDefinition      用户自定义bean

Spring 启动流程总结

AnnotationConfigApplicationContext 初始化.png

这些BeanDefinition只是放入到Spirng 容器中,并没有进行任何初始化对象的操作,真正的IOC操作都在refresh(),这个方法有空再进行分析。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对w3xue的支持。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号