美文网首页spring
Spring源码(一)-BeanDefinition

Spring源码(一)-BeanDefinition

作者: 程序员小杰 | 来源:发表于2021-01-04 21:46 被阅读0次

    BeanDefinition

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

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

    还有就是可以通过BeanDefinition

    比如,我们可以通过定义一个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 是一个接口,继承自 BeanMetadataElement 和 AttributeAccessor 接口。

    • 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 是否懒加载(默认都是立马加载)
    // XML 中的 <bean lazy-init="">
     void setLazyInit(boolean lazyInit);
     boolean isLazyInit();
    
    //配置/获取 Bean 的依赖对象  XML中的 <bean depends-on="">
     void setDependsOn(@Nullable String... dependsOn);
     @Nullable
     String[] getDependsOn();
    
    //配置/获取 Bean 是否是自动装配  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。

    BeanDefinition子类图

    再来看一张继承关系图:


    image.png

    删除了一些无关的继承关系,最终形成了上面那副图。

    抽象实现:AbstractBeanDefinition

    AbstractBeanDefinition 是一个抽象类,它根据 BeanDefinition 中定义的接口提供了相应的属性,并实现了 BeanDefinition 中定义的一部分方法。BeanDefinition 中原本只是定义了一系列的 get/set 方法,并没有提供对应的属性,在 AbstractBeanDefinition 中将所有的属性定义出来了。该抽象类下有个三个子类:GenericBeanDefinitionRootBeanDefinitionChildBeanDefinition

    public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
            implements BeanDefinition, Cloneable {
    
        //默认作用域名称的常量:等效于单例
        public static final String SCOPE_DEFAULT = "";
    
        //自动装配的一些常量
        //默认值,未激活Autowiring,需要手动指定依赖注入对象
        public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;
        //根据被注入属性的名称作为Bean名称进行依赖查找,并将对象设置到该属性
        public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
        //根据被注入属性的类型作为Bean类型进行依赖查找,并将对象设置到该属性
        public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
        //特殊的byType,用于构造器参数
        public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
        //表明通过Bean的class的内部来自动装配 Spring3.0被弃用。
        @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的函数式接口
        @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

    这是一个最常用的实现类,对应了一般的元素标签。RootBeanDefinition继承了AbstractBeanDefinition,在AbstractBeanDefinition的基础上扩展了一些之外的功能,并且RootBeanDefinition是没有父BeanDefinition的。

    public class RootBeanDefinition extends AbstractBeanDefinition {
    
        // BeanDefinitionHolder 存储 Bean 的名称、别名、BeanDefinition
        @Nullable
        private BeanDefinitionHolder decoratedDefinition;
    
        // AnnotatedElement 是java反射包的接口,通过它可以查看 Bean 的注解信息
        @Nullable
        private AnnotatedElement qualifiedElement;
    
        // 决定了什么时候definition需要重新合并
        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) {
          //容器
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
           //普通属性的集合  在其父类 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);
            context.refresh();
            User user = (User)context.getBean("user");
            System.out.println(user);
        }
    
    结果:User{id=4, name='gongj'}
    

    ChildBeanDefinition

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

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

    实践

    新建一个 Person 类,Person 类在 User 类的基础上增加一个 address属性,这样 Person 就可以继承到 User 的 id 和 name 两个属性的值了:

    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) {
            //容器
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
            //普通属性的集合  在其父类 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);
            
            // ChildBeanDefinition 开始
            MutablePropertyValues childValues = new MutablePropertyValues();
            childValues.add("address","上海市");
            //通过构造方法传入父 BeanDetintion 的名称
            ChildBeanDefinition childBeanDefinition  = new ChildBeanDefinition("user", Person.class,null,childValues);
            //注册
            context.registerBeanDefinition("person", childBeanDefinition);
    
            context.refresh();
            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,同时兼具 RootBeanDefinition 和 ChildBeanDefinition 的功能。

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

    实践

        public static void main(String[] args) {
            //容器
            AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
            //普通属性的集合  在其父类 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);
            ctx.refresh();
            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。

    它的源码很简单,就是多了一个属性:private final AnnotationMetadata 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

    ConfigurationClassBeanDefinition

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

    其功能特点如下:

    • 1、如果 @Bean 注解没有指定 Bean 的名字,默认会用方法的名字命名 Bean。
    • 2、标注 @Configuration 注解的类会成为一个工厂类,而标注 @Bean 注解的方法会成为工厂方法,通过工厂方法实例化 Bean,而不是直接通过构造方法初始化。
    • 3、标注 @Bean 注解的类会使用构造方法自动装配

    验证

    在MyConfig 类中新增方法:

    @Bean
        public User myUserBean(){
            return new User();
        }
    
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
            BeanDefinition user = context.getBeanFactory().getBeanDefinition("myUserBean");
        }
    
    image.png
    spring初始化时,会用GenericBeanDefinition或是ConfigurationClassBeanDefinition(用@Bean注解注释的类)存储用户自定义的Bean,在初始化Bean时,又会将其转换为RootBeanDefinition。

    松哥大佬:Spring 源码第四弹!深入理解 BeanDefinition
    大佬:Spring IoC容器中核心定义之------BeanDefinition深入分析(RootBeanDefinition、ChildBeanDefinition)
    大佬:Spring(四)核心容器 - BeanDefinition 解析
    大佬:Spring元数据Metadata的使用

    相关文章

      网友评论

        本文标题:Spring源码(一)-BeanDefinition

        本文链接:https://www.haomeiwen.com/subject/nbjeoktx.html