• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >Java > Spring多种加载Bean方式解析

Spring多种加载Bean方式解析

作者:atheva 字体:[增加 减小] 来源:互联网 时间:2017-05-28

atheva 通过本文主要向大家介绍了spring bean注入方式,spring bean配置方式,spring获取bean的方式,spring 加载bean,spring加载bean顺序等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

1 定义bean的方式

常见的定义Bean的方式有:

通过xml的方式,例如:

<bean id="dictionaryRelMap" class="java.util.HashMap"/>
</div>

通过注解的方式,在Class上使用@Component等注解,例如

@Component
public class xxxServicer{
 ....
}
</div>

通过在@Configuration类下的@Bean的方式,例如

@Configuration
public class xxxConfiguration{
 @Bean
 public myBean myBean(){
   return new myBean();
 }
}
</div>

虽然这三种定义Bean的方式不一样,对应的处理细节也不一样,但是从大的逻辑上来看,都是一样。主要的流程如下图: 最关键的就是问题就是这么去找到定义Bean的方式,然后生成BeanDefinition后注册到Spring上下文中,由Spring自动创建Bean的实例。

2 BeanDefinition

BeanDefinition是一个接口,用来描述一个Bean实例,例如是SINGLETON还是PROTOTYPE,属性的值是什么,构造函数的参数是什么等。简单来说,通过一个BeanDefinition我们就可以完成一个Bean实例化。 BeanDefinition及其主要的子类:

下面简单说一下各个子类:

  1. RootBeanDefinition和ChildBeanDefinition: 这2个BeanDefinition是相对的关系,自Spring 2.5 出来以后,已经被GenericBeanDefinition代替。因为这样强迫我们在编写代码的时候就必须知道他们之间的关系。
  2. GenericBeanDefinition: 相比于RootBeanDefinition和ChildBeanDefinition在定义的时候就必须硬编码,GenericBeanDefinition的优点可以动态的为GenericBeanDefinition设置parent。
  3. AnnotatedBeanDefinition:看名字就是知道是用来读取通过注解定义Bean。

3 通过xml文件定义Bean

通过xml定义Bean是最早的Spring定义Bean的方式。因此,怎么把xml标签解析为BeanDefinition(), 入口是在org.springframework.beans.factory.xml.XmlBeanDefinitionReader这个类,但是实际干活的是在org.springframework.beans.factory.xml.BeanDefinitionParserDelegate。代码很多,但实际逻辑很简单,就是解析Spring定义的<bean> <property> 等标签 。

4 通过@Component等Spring支持的注解加载Bean

如果要使用@Component等注解定义Bean,一个前提条件是:有<context:component-scan/>或者@ComponentScan注解。但这2个方式还是有一点点区别:

4.1 <context:component-scan/>

由于<context:component-scan/>是一个xml标签,因此是在解析xml,生成的类org.springframework.context.annotation.ComponentScanBeanDefinitionParser,关键代码:

@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
    //获取base-package标签
  String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
  basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
  String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
      ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

  // 实际处理类是ClassPathBeanDefinitionScanner 
  ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
  //扫描basePackage下所有的类,如果有@Component等标签就是注册到Spring中
  Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
  registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
  return null;
}

</div>

4.2 @ComponentScan

注解对应生成的类是org.springframework.context.annotation.ComponentScanAnnotationParser 其实最后实际干活的还是ClassPathBeanDefinitionScanner这个。ComponentScanAnnotationParser类的生成是伴随着@Configuration这个注解处理过程中(意思说@ComponentScan必须和@Configuration一起使用)。而处理@Configuration其实是org.springframework.context.annotation.ConfigurationClassPostProcessor。是不是感觉有点绕。

其实简单来说,在处理@Configuration的时候发现有@ComponentScan注解,就会生成ComponentScanAnnotationParser去扫描@Component注解

4.3 ClassPathBeanDefinitionScanner

上面说到了,无论注解还是标签的方式,最后都会交给ClassPathBeanDefinitionScanner这个类来处理,这个类做的就是1.扫描basePackage下所有class,如果有@Component等注解,读取@Component相关属性,生成ScannedGenericBeanDefinition,注册到Spring中。

5 通过@Bean方式

前面说了@ComponentScan是在@Configuration处理过程中的一环,既然@Bean注解也是必须和@Configuration一起使用,那么说明@Bean的处理也是在@Configuration中,其实最后是交给ConfigurationClassBeanDefinitionReader这个类来处理的,关键代码:

private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,
    TrackedConditionEvaluator trackedConditionEvaluator) {

    //如果自己是通过@Import注解定义的,那么需要把自己注册到Spring中
  if (configClass.isImported()) {
    registerBeanDefinitionForImportedConfigurationClass(configClass);
  }
  //这里就是处理方法上的@Bean
  for (BeanMethod beanMethod : configClass.getBeanMethods()) {
    loadBeanDefinitionsForBeanMethod(beanMethod);
  }
  //处理@ImportResource,里面解析xml就是上面说到的解析xml的XmlBeanDefinitionReader
  loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
  loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
</div>

6 把BeanDefinition实例化

前面分别说了怎么把不同定义Bean的方式转换为BeanDefinition加入到Spring中去(确切来说是保持在BeanFactory的BeanDefinitionMap中),实例是在ApplicationContext最后阶段,关键代码在DefaultListableBeanFactory中

 @Override
 public void preInstantiateSingletons() throws BeansException {
   for (String beanName : beanNames) {
    RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
    if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
      if (isFactoryBean(beanName)) {
        final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
        boolean isEagerInit;
        if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
          isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
            @Override
            public Boolean run() {
              return ((SmartFactoryBean<?>) factory).isEagerInit();
            }
          }, getAccessControlContext());
        }
        else {
          isEagerInit = (factory instanceof SmartFactoryBean &&
                ((SmartFactoryBean<?>) factory).isEagerInit());
        }
        if (isEagerInit) {
          getBean(beanName);
        }
      }
      else {
        getBean(beanName);
      }
    }
  }
}
</div>

通过getBean最后最后实例的代码,在AbstractAutowireCapableBeanFactory中

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
  //处理xxAware接口
  if (System.getSecurityManager() != null) {
    AccessController.doPrivileged(new PrivilegedAction<Object>() {
      @Override
      public Object run() {
        invokeAwareMethods(beanName, bean);
        return null;
      }
    }, getAccessControlContext());
  }
  else {
    invokeAwareMethods(beanName, bean);
  }
  Object wrappedBean = bean;
  if (mbd == null || !mbd.isSynthetic()) {
    // 调用BeanPostProcessors#postProcessBeforeInitialization
    wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
  }
  try {
    //初始化,先判断是否是InitializingBean,
    i



 
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • Spring多种加载Bean方式解析
  • Spring多种加载Bean方式解析

相关文章

  • 2017-05-28Java高级特性(基础)
  • 2017-05-28浅谈Java中几个常用集合添加元素的效率
  • 2017-08-27Java8高级新特性_NIO_JUC
  • 2017-05-28spring boot整合Swagger2的示例代码
  • 2017-05-28Java方法重写_动力节点Java学院整理
  • 2017-05-28详解在Spring Boot中使用数据库事务
  • 2017-05-28Java 利用dom方式读取、创建xml详解及实例代码
  • 2017-05-28javaweb中mysql数据库连接步骤方法及其实例
  • 2017-05-28C#创建Web应用程序代码实例
  • 2017-05-28java实现上传图片并压缩图片大小功能

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • Java Timezone类常见问题_动力节点Java学院整理
    • Java创建内部类对象实例详解
    • 详解用Kotlin写一个基于Spring Boot的RESTful服务
    • java导出大批量(百万以上)数据的excel文件
    • Java中的InputStreamReader和OutputStreamWriter源码分析_动力节点Java学院整理
    • java 中使用maven shade plugin 打可执行Jar包
    • Java集合之HashMap用法详解
    • struts2如何使用拦截器进行用户权限控制实例
    • spring的几个重要类和接口(详解)
    • javaWeb项目部署到阿里云服务器步骤详解

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有