Spring源码(一)-Bean的定义-BeanDefinition

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 在 Spring 容器中,我们广泛使用的是一个一个的 Bean,那在Spring 中,我们可以如何去定义一个Bean?
日积月累,水滴石穿 😄

BeanDefinition

Spring 容器中,我们使用的是一个一个的 Bean,那在Spring中,我们可以如何去定义一个 Bean?

  • bean标签
  • @Bean注解
  • @Component(@Service、@Controller)

除上述方式外,还有就是可以通过BeanDefinition这个类,定义 Bean 对象。

比如,我们可以通过定义一个BeanDefinition对象来表示定义了一个Bean,然后通过容器进行获取。

首先项目中添加 spring-context 依赖,如下:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.6.RELEASE</version>
</dependency>

然后在创建User 类

public class User {
    private Long id;
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public void init(){
        System.out.println("初始化");
    }
}

启动类

public static void main(String[] args) {
  // 定义了一个BeanDefinition
  AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition()
    .getBeanDefinition();
  // 当前Bean对象的类型
  beanDefinition.setBeanClass(User.class);
  // 将BeanDefinition注册到BeanFactory中
  DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
  beanFactory.registerBeanDefinition("user", beanDefinition);
  // 获取Bean
  System.out.println(beanFactory.getBean("user"));
}
结果:com.gongj.entity.User@70177ecd

我们还可以通过BeanDefinition设置一个Bean的其他属性

// 设置作用域
beanDefinition.setScope("prototype");
// 设置初始化方法
beanDefinition.setInitMethodName("init");
// 设置自动装配模型
beanDefinition.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE); 
结果:
初始化
com.gongj.entity.User@1e88b3c

注:User类中需要添加初始化方法 init()

总之,我们通过<bean/>,@Bean@Component等方式所定义的Bean,最终都会被解析为BeanDefinition对象。要理解 BeanDefinition,我们先从 BeanDefinition 的继承关系开始看起:

image.png

可以看到 BeanDefinition 是一个接口,继承自 BeanMetadataElementAttributeAccessor 接口。

  • AttributeAccessor:定义用于附加和访问元数据的通用协定的接口,可以是任意对象。具体的实现则是 AttributeAccessorSupport,采用 LinkedHashMap 进行存储。
public interface AttributeAccessor {
 
    //设置属性的值(名称唯一)
    void setAttribute(String name, Object value);
 
    //获得指定属性名称的值,如果不存在返回null
    Object getAttribute(String name);
 
    //删除指定的name的属性,如果不存在则返回null
    Object removeAttribute(String name);
 
      //判断指定的属性名称是否存在
    boolean hasAttribute(String name);
 
    //返回所有属性的名称
    String[] attributeNames();
}
  • BeanMetadataElement:该接口只有一个方法 getSource,该方法返回 Bean 的来源。

这是 BeanDefinition 所继承的两个接口。接下来我们来看下 BeanDefinition本身。

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

// 单例Bean还是原型Bean
 String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
 String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

// Bean角色
 int ROLE_APPLICATION = 0;  //用户自己定义的 Bean
 int ROLE_SUPPORT = 1;  //来源于配置文件的 Bean
 int ROLE_INFRASTRUCTURE = 2;//Spring 内部的 Bean

//配置 /获取父BeanDefinition的名称   XML中的 <bean parent="">
 void setParentName(@Nullable String parentName);
 @Nullable
 String getParentName();

//配置/获取 Bean 的 Class 全路径  XML 中的 <bean class="">
 void setBeanClassName(@Nullable String beanClassName);
 @Nullable
 String getBeanClassName();

//配置/获取  Bean 的作用域  XML中的 <bean scope=""> 配置。
 void setScope(@Nullable String scope);
 @Nullable
 String getScope();

//配置 / 获取 Bean 是否懒加载(默认false,立马加载)
// XML 中的 <bean lazy-init="">
 void setLazyInit(boolean lazyInit);
 boolean isLazyInit();

//配置/获取 Bean 的依赖对象  XML中的 <bean depends-on="">
 void setDependsOn(@Nullable String... dependsOn);
 @Nullable
 String[] getDependsOn();

//配置/获取 Bean 是否是自动装配的候选者 默认为 true XML中的 <bean autowire-candidate="">
 void setAutowireCandidate(boolean autowireCandidate);
 boolean isAutowireCandidate();

//如果找到了多个可注入bean,那么则选择被Primary标记的bean/获取当
//前 Bean 是否为首选的 Bean  XML中的 <bean primary="">
 void setPrimary(boolean primary);
 boolean isPrimary();

// 配置/获取 FactoryBean 的名字  XML中的<bean factory-bean="">
 void setFactoryBeanName(@Nullable String factoryBeanName);
 @Nullable
 String getFactoryBeanName();

//配置/获取 FactoryMethod 的名字,可以是某个实例的方法(和factoryBean配合使用)
//也可以是静态方法。 XML 中的<bean factory-method=""> 
 void setFactoryMethodName(@Nullable String factoryMethodName);
 @Nullable
 String getFactoryMethodName();

//返回该 Bean 构造方法的参数值
 ConstructorArgumentValues getConstructorArgumentValues();

//判断 getConstructorArgumentValues 是否是空对象。
 default boolean hasConstructorArgumentValues() {
  return !getConstructorArgumentValues().isEmpty();
 }

//获取普通属性的集合
 MutablePropertyValues getPropertyValues();

//判断 getPropertyValues 是否为空对象
 default boolean hasPropertyValues() {
  return !getPropertyValues().isEmpty();
 }

// 配置/获取 Bean 的初始化方法 XML中的<bean init-method="">
 void setInitMethodName(@Nullable String initMethodName);
 @Nullable
 String getInitMethodName();

// 配置/获取 Bean 的销毁方法  XML中的<bean destroy-method="">
 void setDestroyMethodName(@Nullable String destroyMethodName);
 @Nullable
 String getDestroyMethodName();

//配置/获取 Bean的角色
 void setRole(int role);
 int getRole();

//配置/获取 Bean 的描述
 void setDescription(@Nullable String description);
 @Nullable
 String getDescription();

//用来解析一个Bean对应的类型上的各种信息,比如泛型
 ResolvableType getResolvableType();

//是否为单例
 boolean isSingleton();

// 是否为原型
 boolean isPrototype();

//是否抽象  XML 中的<bean abstract="true">
 boolean isAbstract();

//返回定义 Bean 的资源描述
 @Nullable
 String getResourceDescription();

// 如果当前 BeanDefinition 是一个代理对象,那么该方法可以用来返回原始的 BeanDefinition
 @Nullable
 BeanDefinition getOriginatingBeanDefinition();
}

BeanDefinition 实现类

BeanDefinition 是一个接口,它有多个实现类,这些实现类分别描述不同类型的 Bean。大致分为两种:

  • 抽象实现:AbstractBeanDefinition
  • 子接口:AnnotatedBeanDefinition

BeanDefinition子类图

再来看一张继承关系图:
image.png
删除了一些无关的继承关系,最终形成了上面那副图。

抽象实现:AbstractBeanDefinition

AbstractBeanDefinition 是一个抽象类,BeanDefinition 中只是定义了一系列的 get/set 方法,并没有提供对应的属性,在 AbstractBeanDefinition 中将所有的属性定义出来了。该抽象类下有个三个子类:GenericBeanDefinitionRootBeanDefinitionChildBeanDefinition。我们先来看 AbstractBeanDefinition本身的一些方法与属性。

public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {

  //默认作用域名称的常量:等效于单例
  public static final String SCOPE_DEFAULT = "";
  
  //自动装配的一些常量
  // autowireMode  = 0,默认值,未激活Autowiring。
  // bean 标签的 autowire 属性值为 no
  // 1、在xml中需要手动指定依赖注入对象 配置 property标签或者 constructor-arg标签
  // 2、使用 @Autowired 注解,autowireMode 的值也是 0
  public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;
  
  //autowireMode  = 1,根据set方法的的名称作为Bean名称进行依赖查找
  //(去掉set,并尝试将首字母变为小写),并将对象设置到该set方法的参数上
  // bean 标签的 autowire 属性值配置为 byName
  public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
  
  //autowireMode  = 2,根据set方法参数的类型作为Bean类型进行依赖查找
  //并将对象设置到该set方法的参数上
  // bean 标签的 autowire 属性值配置为 byType
  public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
  
  //autowireMode  = 3,构造器注入
  // bean 标签的 autowire 属性值配置为 constructor
  public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
  
  //表明通过Bean的class的内部来自动装配 Spring3.0被弃用。
  // bean 标签的 autowire 属性值配置为 autodetect
  @Deprecated
  public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;
  
  //检查依赖是否合法,在本类中,默认不进行依赖检查
  //不进行检查
  public static final int DEPENDENCY_CHECK_NONE = 0;
  
  //对对象引用进行依赖性检查
  public static final int DEPENDENCY_CHECK_OBJECTS = 1;
  
  //对“简单”属性进行依赖性检查
  public static final int DEPENDENCY_CHECK_SIMPLE = 2;
  
  //对所有属性进行依赖检查
  public static final int DEPENDENCY_CHECK_ALL = 3;
  
  //若Bean未指定销毁方法,容器应该尝试推断Bean的销毁方法的名字,
  //目前,推断的销毁方法的名字一般为close或是shutdown
  public static final String INFER_METHOD = "(inferred)";
  
  //Bean的class对象或是类的全限定名
  @Nullable
  private volatile Object beanClass;
  
  //默认的scope是单例,对应bean属性scope
  //@Scope
  @Nullable
  private String scope = SCOPE_DEFAULT;
  
  //是否是抽象,对应bean属性abstract
  private boolean abstractFlag = false;
  
  //是否懒加载,对应bean属性lazy-init,默认不是懒加载
  //@Lazy
  @Nullable
  private Boolean lazyInit;
  
  //自动注入模式,对应bean属性autowire,默认不进行自动装配
  private int autowireMode = AUTOWIRE_NO;
  
  //是否进行依赖检查,默认不进行依赖检查
  private int dependencyCheck = DEPENDENCY_CHECK_NONE;
  
  //用来表示一个bean的实例化是否依靠另一个bean的实例化,先加载dependsOn的bean,
  //对应bean属性depend-on
  //@DependsOn
  @Nullable
  private String[] dependsOn;
  
  /**
   * autowire-candidate属性设置为false,这样容器在查找自动装配对象时,
   * 将不考虑该bean,即它不会被考虑作为其他bean自动装配的候选者,
   * 但是该bean本身还是可以使用自动装配来注入其他bean的
   */
  private boolean autowireCandidate = true;
  
  /**
   * 自动装配时出现多个bean候选者时,将作为首选者,对应bean属性primary,默认不是首选的
   * @Primary
   */
  private boolean primary = false;
  
  /**
   * 用于记录Qualifier,对应子元素qualifier <bean><qualifier></qualifier></bean>
   * 如果容器中有多个相同类型的 bean,这时我们就可以使用qualifier属性来设置加载指定Bean名称的bean
   * @Qualifier
   */
  private final Map < String, AutowireCandidateQualifier > qualifiers = new LinkedHashMap <>();
  
  //java8的函数式接口,创建bean实例的方式之一
  @Nullable
  private Supplier <? > instanceSupplier;
  
  //是否允许访问非public方法和属性, 默认是true
  private boolean nonPublicAccessAllowed = true;
  
  /**
   * 是否以一种宽松的模式解析构造函数,默认为true,
   * 如果为false,则在以下情况
   * interface ITest{}
   * class ITestImpl implements ITest{};
   * class Main {
   *     Main(ITest i) {}
   *     Main(ITestImpl i) {}
   * }
   * 抛出异常,因为Spring无法准确定位哪个构造函数程序设置
   */
  private boolean lenientConstructorResolution = true;
  
  //工厂类名,对应bean属性factory-bean
  @Nullable
  private String factoryBeanName;
  
  //工厂方法名,对应bean属性factory-method
  @Nullable
  private String factoryMethodName;
  
  //记录构造函数注入属性,对应bean属性constructor-arg
  @Nullable
  private ConstructorArgumentValues constructorArgumentValues;
  
  //Bean属性的名称以及对应的值,这里不会存放构造函数相关的参数值,只会存放通过setter注入的值
  @Nullable
  private MutablePropertyValues propertyValues;
  
  //方法重写的持有者,记录lookup-method、replaced-method元素  @Lookup
  private MethodOverrides methodOverrides = new MethodOverrides();
  
  //初始化方法,对应bean属性init-method
  @Nullable
  private String initMethodName;
  
  //销毁方法,对应bean属性destroy-method
  @Nullable
  private String destroyMethodName;
  
  //是否执行init-method,默认为true
  private boolean enforceInitMethod = true;
  
  //是否执行destroy-method,默认为true
  private boolean enforceDestroyMethod = true;
  
  //是否是用户定义的而不是应用程序本身定义的,创建AOP时候为true
  private boolean synthetic = false;
  
  //Bean的角色,为用户自定义Bean
  private int role = BeanDefinition.ROLE_APPLICATION;
  
  //Bean的描述信息
  @Nullable
  private String description;
  
  //这个bean定义的资源
  @Nullable
  private Resource resource;
  //...
}

RootBeanDefinition

这是一个最常用的实现类,Spirng 去创建 Bean 时是基于RootBeanDefinition去创建的!

RootBeanDefinition继承了AbstractBeanDefinition,在AbstractBeanDefinition的基础上扩展了一些之外的功能,并且RootBeanDefinition是没有父BeanDefinition的。

public class RootBeanDefinition extends AbstractBeanDefinition {
  // BeanDefinitionHolder 存储 Bean 的名称、别名、BeanDefinition
  @Nullable
  private BeanDefinitionHolder decoratedDefinition;
  // AnnotatedElement 是java反射包的接口,通过它可以查看 Bean 的注解信息
  @Nullable
  private AnnotatedElement qualifiedElement;
  // 决定了什么时候 BeanDefinition 需要重新合并
  volatile Boolean stale;
  // 允许缓存
  Boolean allowCaching = true;
  // 工厂方法是否唯一
  Boolean isFactoryMethodUnique = false;
  //封装了 java.lang.reflect.Type,提供了泛型相关的操作
  @Nullable
  volatile ResolvableType targetType;
  //用于缓存给定bean定义中确定的类
  // 表示 RootBeanDefinition 存储哪个类的信息
  @Nullable
  volatile Class<?> resolvedTargetType;
  //如果bean是FactoryBean,则用于缓存
  @Nullable
  volatile Boolean isFactoryBean;
  //用于缓存泛型类型工厂方法的返回类型
  @Nullable
  volatile ResolvableType factoryMethodReturnType;
  //用于缓存唯一的工厂方法
  @Nullable
  volatile Method factoryMethodToIntrospect;
  
  //下面四个构造函数字段的公共锁
  final Object constructorArgumentLock = new Object();
  // 用用于缓存已解析的构造函数或工厂方法
  @Nullable
  Executable resolvedConstructorOrFactoryMethod;
  //将构造函数参数标记为已解析
  Boolean constructorArgumentsResolved = false;
  //用于缓存完全解析的构造函数参数
  @Nullable
  Object[] resolvedConstructorArguments;
  //用于缓存部分准备好的构造函数参数
  @Nullable
  Object[] preparedConstructorArguments;
  
  //下面两个后处理字段的通用锁
  final Object postProcessingLock = new Object();
  //这表明已经应用了MergedBeanDefinitionPostProcessor
  Boolean postProcessed = false;
  //表明一个实例化前的后处理器已经启动
  @Nullable
  volatile Boolean beforeInstantiationResolved;
  //实际缓存的类型是 Constructor、Field、Method 类型
  @Nullable
  private Set<Member> externallyManagedConfigMembers;
  // InitializingBean中 的 init 回调函数名 afterPropertiesSet 会在这里记录,以便进行生命周期回调
  @Nullable
  private Set<String> externallyManagedInitMethods;
  // DisposableBean 的 destroy 回调函数名 destroy 会在这里记录,以便进生命周期回调
  @Nullable
  private Set<String> externallyManagedDestroyMethods;
  
  //===========贴一个方法
  // 很明显,RootBeanDefiniiton是没有父BeanDefinition
  @Override
  public String getParentName() {
    return null;
  }
  // 并且还不能进行set
  @Override
  public void setParentName(@Nullable String parentName) {
    if (parentName != null) {
      throw new IllegalArgumentException("Root bean cannot be changed into a 
                                         child bean with parent reference");
    }
  }
}

实践

复用开篇就用到的 User 类,在其中添加toString方法。

public static void main(String[]args){
  //容器
  DefaultListableBeanFactory context = new DefaultListableBeanFactory();
  //属性的集合  在其父类 AbstractBeanDefinition 已经提到过了
  MutablePropertyValues mpvs = new MutablePropertyValues();
  mpvs.add("id",4L);
  mpvs.add("name","gongj");
  //BeanDefinition
  RootBeanDefinition rootBeanDefinition =new RootBeanDefinition(User.class,null,mpvs);
  //注册到Spring容器中
  context.registerBeanDefinition("user",rootBeanDefinition);
  User user=(User)context.getBean("user");
  System.out.println(user);
}

结果:User{id=4, name='gongj'}

ChildBeanDefinition

该类继承自 AbstractBeanDefinition。其相当于一个子类,不可以单独存在,必须依赖一个父 BeanDetintion,构造 ChildBeanDefinition 时,通过构造方法传入父 BeanDetintion 的名称或通过 setParentName 设置父名称。它可以从父类继承方法参数、属性值,并可以重写父类的方法,同时也可以增加新的属性或者方法。

从 Spring 2.5 开始,以编程方式注册 Bean 定义的首选方法是 GenericBeanDefinition,GenericBeanDefinition 可以有效替代 ChildBeanDefinition 的绝大分部使用场合。

实践

新建一个 Person 类,Person 类在 User 类的基础上增加一个 address属性。

public class Person {

  private Long id;
  private String name;
  private String address;

  public Long getId() {
    return id;
  }

  public void setId(Long id) {
    this.id = id;
  }

  public String getName() {
    return name;
  }

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

  public String getAddress() {
    return address;
  }

  public void setAddress(String address) {
    this.address = address;
  }

  @Override
  public String toString() {
    return "Person{" +
            "id=" + id +
            ", name='" + name + '\'' +
            ", address='" + address + '\'' +
            '}';
  }
}

启动

public static void main(String[] args) {
  //容器
  DefaultListableBeanFactory context = new DefaultListableBeanFactory();
  //普通属性的集合  在其父类 AbstractBeanDefinition 已经提到过了
  MutablePropertyValues mpvs = new MutablePropertyValues();
  mpvs.add("id",4L);
  mpvs.add("name","gongj");
  //RootBeanDefinition
  RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(User.class,null,mpvs);
  //注册到Spring容器中
  context.registerBeanDefinition("user",rootBeanDefinition);
  
  // ChildBeanDefinition 开始
  MutablePropertyValues childValues = new MutablePropertyValues();
  childValues.add("address","上海市");
  //通过构造方法传入父 BeanDetintion 的名称
  ChildBeanDefinition childBeanDefinition  = new ChildBeanDefinition("user", Person.class,null,childValues);
  //注册
  context.registerBeanDefinition("person", childBeanDefinition);
  User user = context.getBean(User.class);
  Person person = context.getBean(Person.class);
  System.out.println("user = " + user);
  System.out.println("person = " + person);
}

结果:
user = User{id=4, name='gongj'}
person = Person{id=4, name='gongj', address='上海市'}

GenericBeanDefinition

GenericBeanDefinition 是从 Spring2.5 以后新加入的 bean 文件配置属性定义类,是一站式服务类。GenericBeanDefinition 可以动态设置父 Bean,同时兼具 RootBeanDefinitionChildBeanDefinition 的功能。

GenericBeanDefinition 的实现比较简单,在 AbstractBeanDefinition 的基础上只增加了parentName的功能,其余的实现都在父类 AbstractBeanDefinition 里。
注:若你是xml配置,会解析所有属性并统一封装至 GenericBeanDefinition 类型的实例中,之后再逐渐解析的。

实践

public static void main(String[] args) {
    //容器
    DefaultListableBeanFactory ctx = new DefaultListableBeanFactory();
    //普通属性的集合  在其父类 AbstractBeanDefinition 已经提到过了
    MutablePropertyValues mpvs = new MutablePropertyValues();
    mpvs.add("id",4L);
    mpvs.add("name","gongj");
    GenericBeanDefinition parentGenericBeanDefinition = new GenericBeanDefinition();
    parentGenericBeanDefinition.setBeanClass(User.class);
    parentGenericBeanDefinition.setPropertyValues(mpvs);
    //注册到Spring容器中
    ctx.registerBeanDefinition("user",parentGenericBeanDefinition);

    GenericBeanDefinition childGenericBeanDefinition = new GenericBeanDefinition();
    //设置父BeanDefinition的名称
    childGenericBeanDefinition.setParentName("user");
    childGenericBeanDefinition.setBeanClass(Person.class);
    childGenericBeanDefinition.getPropertyValues().add("address", "上海市");
    //注册到Spring容器中
    ctx.registerBeanDefinition("person", childGenericBeanDefinition);
    User user = ctx.getBean(User.class);
    Person person = ctx.getBean(Person.class);
    System.out.println("user = " + user);
    System.out.println("person = " + person);
}
结果:
user = User{id=4, name='gongj'}
person = Person{id=4, name='gongj', address='上海市'}

子接口:AnnotatedBeanDefinition

//关于其bean类-无需加载该类。
public interface AnnotatedBeanDefinition extends BeanDefinition {
    //获取此bean定义注解的元数据
    AnnotationMetadata getMetadata();

//获取此bean定义的工厂方法的元数据,如果没有,则为null
    @Nullable
    MethodMetadata getFactoryMethodMetadata();
}

该接口可以返回两个元数据的类:

  • AnnotationMetadata:主要对 Bean 的注解信息进行操作,如:获取当前 Bean 标注的所有注解、判断是否包含指定注解。
public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata {

    //获取所有注解完全限定类名
    default Set<String> getAnnotationTypes() {
        return getAnnotations().stream()
                .filter(MergedAnnotation::isDirectlyPresent)
                .map(annotation -> annotation.getType().getName())
                .collect(Collectors.toCollection(LinkedHashSet::new));
    }

    //获得annottationName对应的元注解的类全限定名
    default Set<String> getMetaAnnotationTypes(String annotationName) {
        MergedAnnotation<?> annotation = getAnnotations().get(annotationName, MergedAnnotation::isDirectlyPresent);
        if (!annotation.isPresent()) {
            return Collections.emptySet();
        }
        return MergedAnnotations.from(annotation.getType(), SearchStrategy.INHERITED_ANNOTATIONS).stream()
                .map(mergedAnnotation -> mergedAnnotation.getType().getName())
                .collect(Collectors.toCollection(LinkedHashSet::new));
    }

    //是否包含指定注解 
    default boolean hasAnnotation(String annotationName) {
        return getAnnotations().isDirectlyPresent(annotationName);
    }

    //确定是否含有某个元注解
    default boolean hasMetaAnnotation(String metaAnnotationName) {
        return getAnnotations().get(metaAnnotationName,
                MergedAnnotation::isMetaPresent).isPresent();
    }

    //类里面只要有一个方法标注有指定注解,就返回true
    default boolean hasAnnotatedMethods(String annotationName) {
        return !getAnnotatedMethods(annotationName).isEmpty();
    }
      // 返回所有的标注有指定注解的方法元信息
    Set<MethodMetadata> getAnnotatedMethods(String annotationName);

    //工厂方法来使用标准反射为给定的类创建一个新的AnnotationMetadata实例
    static AnnotationMetadata introspect(Class<?> type) {
        return StandardAnnotationMetadata.from(type);
    }
}
  • MethodMetadata:方法的元数据类。提供获取方法名称、此方法所属类的全类名、是否是抽象方法、判断是否是静态方法、判断是否是final方法等。
public interface MethodMetadata extends AnnotatedTypeMetadata {

    //返回方法的名字
    String getMethodName();

    //返回该方法所属的类的全限定名
    String getDeclaringClassName();

    //返回该方法返回类型的全限定名
    String getReturnTypeName();

    //方法是否是有效的抽象方法:即在类上标记为抽象的或声明为规则的,
    //接口中的非默认方法。
    boolean isAbstract();

    //方法是否声明为'static'。
    boolean isStatic();

    //方法是否标记为'final'。
    boolean isFinal();

    //方法是否可重写:即没有标记为static、final或private。
    boolean isOverridable();

}

该接口下有三大子类: ScannedGenericBeanDefinitionConfigurationClassBeanDefinitionAnnotatedGenericBeanDefinition

ScannedGenericBeanDefinition

实现了 AnnotatedBeanDefinition 也继承了 GenericBeanDefinition。这个 BeanDefinition 用来描述标注@Component、@Service、@Controller等注解标记的类会解析为 ScannedGenericBeanDefinition

它的源码很简单,就是多了一个属性:metadata 用来存储扫描进来的Bean的一些注解信息。

public class ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {

    private final AnnotationMetadata metadata;

    /**
     * 鉴于MetadataReader描述,为类创建一个新的ScannedGenericBeanDefinition
     */
    public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
        Assert.notNull(metadataReader, "MetadataReader must not be null");
        this.metadata = metadataReader.getAnnotationMetadata();
        setBeanClassName(this.metadata.getClassName());
    }


    @Override
    public final AnnotationMetadata getMetadata() {
        return this.metadata;
    }

    @Override
    @Nullable
    public MethodMetadata getFactoryMethodMetadata() {
        return null;
    }
}

验证

@Component、@Service、@Controller等注解标记的类是否会解析为 ScannedGenericBeanDefinition

新建 AppConfig

@ComponentScan("com.gongj")
public class AppConfig {

}

然后再创建HelloController

@Controller
public class HelloController {
}

启动

public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    BeanDefinition helloController = context.getBeanFactory().getBeanDefinition("helloController");
}

image.png

AnnotatedGenericBeanDefinition

该类继承自 GenericBeanDefinition ,并实现了AnnotatedBeanDefinition 接口。这个 BeanDefinition 用来描述标注使用了 @Configuration 注解标记配置类会解析为 AnnotatedGenericBeanDefinition

public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {

    // 注解元数据
    private final AnnotationMetadata metadata;

    @Nullable
    private MethodMetadata factoryMethodMetadata;


    /**
     * 为给定的bean类创建一个新的AnnotatedGenericBeanDefinition
     * @param beanClass the loaded bean class:加载的bean类
     */
    public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
        setBeanClass(beanClass);
        // 当前类上有哪些注解
        this.metadata = AnnotationMetadata.introspect(beanClass);
    }

    /**
     * 
     * 为给定的注释元数据创建一个新AnnotatedGenericBeanDefinition,传入AnnotationMetadata
     */
    public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) {
        Assert.notNull(metadata, "AnnotationMetadata must not be null");
        if (metadata instanceof StandardAnnotationMetadata) {
            setBeanClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
        }
        else {
            setBeanClassName(metadata.getClassName());
        }
        this.metadata = metadata;
    }

    /**
     * 
     * 基于一个带注解的类和该类上的工厂方法。,为给定的注释元数据创建一个新的AnnotatedGenericBeanDefinition,
     */
    public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata, MethodMetadata factoryMethodMetadata) {
        this(metadata);
        Assert.notNull(factoryMethodMetadata, "MethodMetadata must not be null");
        setFactoryMethodName(factoryMethodMetadata.getMethodName());
        this.factoryMethodMetadata = factoryMethodMetadata;
    }


    @Override
    public final AnnotationMetadata getMetadata() {
        return this.metadata;
    }

    @Override
    @Nullable
    public final MethodMetadata getFactoryMethodMetadata() {
        return this.factoryMethodMetadata;
    }

}

验证

新建 MyConfig

@Configuration
public class MyConfig {

}

启动

public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        BeanDefinition myConfig = context.getBeanFactory().getBeanDefinition("myConfig");
    }

image.png

如果使用 AppConfig作为扫描包,MyConfig 的实际类型是 ScannedGenericBeanDefinition,当然这个与启动有关,后面的博文再说。

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        BeanDefinition myConfig = context.getBeanFactory().getBeanDefinition("myConfig");

image-20210428231825279.png

ConfigurationClassBeanDefinition

它是ConfigurationClassBeanDefinitionReader的一个私有的静态内部类:这个类负责将@Bean注解的方法转换为对应的ConfigurationClassBeanDefinition 类,源码就不过多解释了,和之前几个BeanDefinition差不多。

其功能特点如下:

  • 1、如果 @Bean 注解没有指定 Bean 的名字,默认会用方法的名字作为Bean的名称。
  • 2、标注 @Configuration、@Component、@Service 注解的类会成为一个工厂类,而标注 @Bean 注解的方法会成为工厂方法,通过工厂方法实例化 Bean。

    验证

    MyConfig 类中新增方法:

@Bean("mz")
    public User myUserBean(){
        return new User();
    }

启动

public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
    BeanDefinition mz = context.getBeanFactory().getBeanDefinition("mz");
    User myUserBean = (User)context.getBean("mz");
    System.out.println("mz =" + mz);
    System.out.println("myUserBean = " + myUserBean);
}

image.png

spring初始化时,会用GenericBeanDefinition或是ConfigurationClassBeanDefinition(用@Bean注解注释的类)存储用户自定义的Bean,在初始化Bean时,又会将其转换为RootBeanDefinition。

参考文献

相关文章
|
16天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
45 2
|
1月前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
23天前
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
22天前
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
45 9
|
2月前
|
Java 测试技术 Windows
咦!Spring容器里为什么没有我需要的Bean?
【10月更文挑战第11天】项目经理给小菜分配了一个紧急需求,小菜迅速搭建了一个SpringBoot项目并完成了开发。然而,启动测试时发现接口404,原因是控制器包不在默认扫描路径下。通过配置`@ComponentScan`的`basePackages`字段,解决了问题。总结:`@SpringBootApplication`默认只扫描当前包下的组件,需要扫描其他包时需配置`@ComponentScan`。
|
2月前
|
Java Spring
Spring底层架构源码解析(三)
Spring底层架构源码解析(三)
120 5
|
2月前
|
XML Java 数据格式
Spring底层架构源码解析(二)
Spring底层架构源码解析(二)
|
7月前
|
安全 Java 应用服务中间件
阿里技术官架构使用总结:Spring+MyBatis源码+Tomcat架构解析等
分享Java技术文以及学习经验也有一段时间了,实际上作为程序员,我们都清楚学习的重要性,毕竟时代在发展,互联网之下,稍有一些落后可能就会被淘汰掉,因此我们需要不断去审视自己,通过学习来让自己得到相应的提升。
|
7月前
|
Java 关系型数据库 数据库连接
Spring源码解析--深入Spring事务原理
本文将带领大家领略Spring事务的风采,Spring事务是我们在日常开发中经常会遇到的,也是各种大小面试中的高频题,希望通过本文,能让大家对Spring事务有个深入的了解,无论开发还是面试,都不会让Spring事务成为拦路虎。
100 1
|
2月前
|
Java Spring 容器
Spring IOC、AOP与事务管理底层原理及源码解析
【10月更文挑战第1天】Spring框架以其强大的控制反转(IOC)和面向切面编程(AOP)功能,成为Java企业级开发中的首选框架。本文将深入探讨Spring IOC和AOP的底层原理,并通过源码解析来揭示其实现机制。同时,我们还将探讨Spring事务管理的核心原理,并给出相应的源码示例。
137 9