• Spring-Framework 源码阅读之AnnotationBeanUtils


      Java程序员,就是要学会一个名字叫做“春”的东西,这玩意运用的非常的广泛,现在如果你的业务系统或者软件没有在这个东西上开发,都不要意思拿出来。因为你更不上时代了。在平时的工作的中基本都是简单的运用,没有深入的了解内部的肌理。这次我一定可以满满的看完里面的骨架。加油!加油!加油!

      在之前我也看过一些讲Spring的书籍,比如<<Spring揭秘>>,《Spring技术内幕》。大体知道了Spring的工作流程,但是还是有些迷茫。有一点一知半解的感觉。接下来我准备以自己一知半解的半桶水的知识去阅读Spring的源码。根据自己的模模糊糊的感觉和去网上搜索来帮助阅读。这一次要地毯式的搜索阅读。可是有时也会觉得Spring 框架这么大,如此的阅读是不是浪费时间。但是又有另一种想法,只要我们把每个类的作用都了解清楚了,每个类都自己写一下单元测试。都跟进源码阅读。这样等我大部分的内容都阅读了,Spring的了解深度会更加清晰咯。

      首先第一步就是下载Spring源码,然后导入Idea中,如下图所示。

      Spring 最最最核心的地方就是Bean,所以我准备从spring-beans这个工程看起。首先第一个package: org.springframework.beans.annotation,这个包下就只有一个类AnnotationBeanUtils,该类就只有一个核心的方法,就是拷贝注解值到指定的类中。

    public abstract class AnnotationBeanUtils {
    
        /**
         * Copy the properties of the supplied {@link Annotation} to the supplied target bean.
         * Any properties defined in {@code excludedProperties} will not be copied.
         * @param ann the annotation to copy from
         * @param bean the bean instance to copy to
         * @param excludedProperties the names of excluded properties, if any
         * @see org.springframework.beans.BeanWrapper
         */
        public static void copyPropertiesToBean(Annotation ann, Object bean, String... excludedProperties) {
            copyPropertiesToBean(ann, bean, null, excludedProperties);
        }
    
        /**
         * Copy the properties of the supplied {@link Annotation} to the supplied target bean.
         * Any properties defined in {@code excludedProperties} will not be copied.
         * <p>A specified value resolver may resolve placeholders in property values, for example.
         * @param ann the annotation to copy from
         * @param bean the bean instance to copy to
         * @param valueResolver a resolve to post-process String property values (may be {@code null})
         * @param excludedProperties the names of excluded properties, if any
         * @see org.springframework.beans.BeanWrapper
         */
        public static void copyPropertiesToBean(Annotation ann, Object bean, @Nullable StringValueResolver valueResolver,
                String... excludedProperties) {
    
            Set<String> excluded = new HashSet<>(Arrays.asList(excludedProperties));
            Method[] annotationProperties = ann.annotationType().getDeclaredMethods(); //获取注解上的方法
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(bean); //同过bean对象获取bean的定义BeanDefinition
            for (Method annotationProperty : annotationProperties) { //遍历方法
                String propertyName = annotationProperty.getName(); //获取方法名
                if (!excluded.contains(propertyName) && bw.isWritableProperty(propertyName)) {
                    Object value = ReflectionUtils.invokeMethod(annotationProperty, ann); //获取注解方法上的值
                    if (valueResolver != null && value instanceof String) {
                        value = valueResolver.resolveStringValue((String) value); //处理value的值,StringValueResolver的作用比如处理占位符${}
                    }
                    bw.setPropertyValue(propertyName, value);//把该值设置到bean定义上。
                }
            }
        }
    }

    从上面的解释,应该非常清楚该工具类的作用,现在我们来写一个例子来验证。

    package com.qee.beans.annotation;
    
    import java.lang.annotation.*;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface FooAnnotation {
        String name();
    
        int age();
    }
    package com.qee.beans.annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Foo2Annotation {
        String accountId();
    }
    package com.qee.beans.annotation;
    
    
    @FooAnnotation(name = "xiao ming", age = 23)
    public class Foo {
        private String names;
    
        private int age;
    
        @Foo2Annotation(accountId = "123456")
        private  String id;
    
        public String getNames() {
            return names;
        }
    
        public void setName(String names) {
            this.names = names;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public void  setAccountId(String id){
            setId(id);
        }
    }
    package com.qee.beans.annotation;
    
    import org.springframework.beans.annotation.AnnotationBeanUtils;
    
    
    public class AnnotationBeanUtilsTest {
        public static void main(String[] args) throws NoSuchFieldException {
            testCopyProperties();
            testCopyProperties2();
            testCopyPropertiesWithIgnore();
        }
    
        public static void testCopyProperties2() throws NoSuchFieldException {
    
            Foo2Annotation annotation = Foo.class.getDeclaredField("id").getAnnotation(Foo2Annotation.class);
            Foo foo = new Foo();
            AnnotationBeanUtils.copyPropertiesToBean(annotation, foo);
            System.out.println(foo.getId());
    
        }
    
        public static void testCopyProperties() {
            FooAnnotation annotation = Foo.class.getAnnotation(FooAnnotation.class);
            Foo foo = new Foo();
            AnnotationBeanUtils.copyPropertiesToBean(annotation, foo);
            System.out.println("Name  :  " + annotation.name() + "  " + foo.getNames());
            System.out.println("Age   :   " + annotation.age() + "  " + foo.getAge());
        }
    
        public static void testCopyPropertiesWithIgnore() {
            FooAnnotation annotation = Foo.class.getAnnotation(FooAnnotation.class);
            Foo foo = new Foo();
            foo.setName("Juergen Hoeller");
            foo.setAge(30);
            AnnotationBeanUtils.copyPropertiesToBean(annotation, foo, "name", "age");
            System.out.println("Name  :  " + annotation.name() + "  " + foo.getNames());
            System.out.println("Age   :   " + annotation.age() + "  " + foo.getAge());
        }
    
    }

      从上面测试例子可以知道,AnnotationBeanUtils.copyPropertiesToBean把注解上的值拷贝给某个对象,只有某个对象有这个注解方法的setXX方法。并且如果该对象的某个属性已经有值了,就不会在拷贝注解上的值到该属性上。

      从上面AnnotationBeanUtils的源码上,我们知道引入了新的Spring对象--StringValueResolver,BeanWrapper,ReflectionUtils。在之后的源码阅读中,在进行解析。在这里做一下红色标记,哇哈哈,哇哈哈,哇哈哈!!!!!!

    待看的,等看看到这些包的时候,在继续分析下面的内容

    org.springframework.util.StringValueResolver

    org.springframework.beans.BeanWrapper

    org.springframework.util.ReflectionUtils

  • 相关阅读:
    元宇宙通证
    高性能公链
    区块链不可能三角
    搭建自己的在线API文档系统
    windows 安装python环境
    golang beego项目的正确开启方法
    人生发财靠康波
    蒙代尔不可能三角
    Kubernetes 部署Dashboard UI
    Kubernetes 使用kubeadm创建集群
  • 原文地址:https://www.cnblogs.com/liferecord/p/7255375.html
Copyright © 2020-2023  润新知