当前位置: 移动技术网 > IT编程>开发语言>Java > Spring多种加载Bean方式解析

Spring多种加载Bean方式解析

2019年07月22日  | 移动技术网IT编程  | 我要评论

1 定义bean的方式

常见的定义bean的方式有:

通过xml的方式,例如:

<bean id="dictionaryrelmap" class="java.util.hashmap"/>

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

@component
public class xxxservicer{
 ....
}

通过在@configuration类下的@bean的方式,例如

@configuration
public class xxxconfiguration{
 @bean
 public mybean mybean(){
   return new mybean();
 }
}

虽然这三种定义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;
}

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());
}

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);
      }
    }
  }
}

通过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,
    invokeinitmethods(beanname, wrappedbean, mbd);
  }
  catch (throwable ex) {
    throw new beancreationexception(
        (mbd != null ? mbd.getresourcedescription() : null),
        beanname, "invocation of init method failed", ex);
  }
  if (mbd == null || !mbd.issynthetic()) {
    // 调用beanpostprocessors#postprocessafterinitialization
    wrappedbean = applybeanpostprocessorsafterinitialization(wrappedbean, beanname);
  }
  return wrappedbean;
}

从上面初始化可以看出,initializebean和beanpostprocessors的调用顺序

7 总结

综上分析,spring加载bean其实大的思想都是一样的,先读取相关信息生成beandefinition,然后通过beandefinition初始化bean。如果知道了上面了套路以后,就可以清楚怎么自定义xml标签或者自定义注解向spring中注入bean。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网