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
Spring-Framework 源码阅读之AnnotationBeanUtils的更多相关文章
- Spring事务源码阅读笔记
1. 背景 本文主要介绍Spring声明式事务的实现原理及源码.对一些工作中的案例与事务源码中的参数进行总结. 2. 基本概念 2.1 基本名词解释 名词 概念 PlatformTransaction ...
- spring framework 源码
spring framework 各版本源码下载地址 现在spring的源码下载地址真是不好找,这次终于找到了.记录一下,以帮助需要的朋友. https://github.com/spring-pro ...
- Idea搭建spring framework源码环境
spring的源码目前放在github上,https://github.com/spring-projects/spring-framework 一.安装Git 二.安装Gradle gradle为解 ...
- Spring框架源码阅读之Springs-beans(一)容器的基本实现概述(待续)
去年通过实际框架代码的阅读,以及结合<Spring源码深度解析>和<Spring技术内幕>的阅读,对Spring框架内Bean模块有了一个整体性的认识.对此进行的总结性整理和回 ...
- Spring JdbcTemplate源码阅读报告
写在前面 spring一直以删繁就简为主旨,所以设计出非常流行的bean管理模式,简化了开发中的Bean的管理,少写了很多重复代码.而JdbcTemplate的设计更令人赞叹,轻量级,可做ORM也可如 ...
- 【面试】足够应付面试的Spring事务源码阅读梳理(建议珍藏)
Starting from a joke 问:把大象放冰箱里,分几步? 答:三步啊,第一.把冰箱门打开,第二.把大象放进去,第三.把冰箱门带上. 问:实现Spring事务,分几步? 答:三步啊,第一. ...
- Spring,tk-mapper源码阅读
Mybatis的源码学习(一): 前言: 结合spring本次学习会先从spring-mybatis开始分析 在学习mybatis之前,应该要对spring的bean有所了解,本文略过 先贴一下myb ...
- Spring Framework 源码编译导入
预先准备环境 Window 10 JDK环境 List item Gradle 以及其环境变量配置 spring-framework源码(https://gitee.com/mirrors/Sprin ...
- Robot Framework 源码阅读 day2 TestSuitBuilder
接上一篇 day1 run.py 发现build test suit还挺复杂的, 先从官网API找到了一些资料,可以看出这是robotframework进行组织 测试案例实现的重要步骤, 将传入的te ...
随机推荐
- Java基础——封装
最近学习Java面向对象方面的知识点,一直没时间更新博客,因为这块的知识点真的蛮绕的.一个知识点一个知识点的往外冒,而且对于我这个初学者来说区分构造器和方法就花费了一整天的时间.现在准备再重新过一遍知 ...
- Nmap脚本引擎原理
Nmap脚本引擎原理 一.NSE介绍 虽然Nmap内嵌的服务于版本探测已足够强大,但是在某些情况下我们需要多伦次的交互才能够探测到服务器的信息,这时候就需要自己编写NSE插件实现这个功能.NSE插件能 ...
- 前台ajax加载数据
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script> <script sr ...
- fdisk 非交互式创建 分区
一. key 非交互式创建分区, 与 交互式创建分区区别不大. 使用 fdisk 的默认选项, 使用空行即可, 不用回车. 创建 主分区 和 扩展分区时, 需要注意 分区号 二. 创建主分区 fdis ...
- Blockly编程:用Scratch制作游戏愤怒的小牛(小鸟)
愤怒的小鸟曾经很热门,网上还说他是程序员最喜欢玩的游戏.最先我是WIKIOI的评测页面看到他的,后来在2014年全国信息学奥林匹克联赛第一天第三题飞扬的小鸟也看到了它.因此,突然想做一个类似愤怒的小鸟 ...
- arcgis api for js入门开发系列十叠加SHP图层
上一篇实现了demo的热力图,本篇新增叠加SHP图层,截图如下: 叠加SHP图层效果实现的思路如下:利用封装的js文件,直接读取shp图层,然后转换geojson,最后通过arcgis api来解析转 ...
- git视频教程
git 精简版视频教程-2小时快速入门精华版,小教程很快就可以看完. 旺旺 QQ:Git是目前世界上最先进的分布式版本控制系统(没有之一). Git有非常高的逼格,简单来说就是:高端大气上档次. 这么 ...
- 论文笔记 Generative Face Completion
这篇paper将巧妙地将四个loss函数结合在一起,其中每一个loss的功能不同.但这篇paper不够elegant的地方也是loss太多!在本文中,我采用散文的写作方法谈谈自己对这篇paper的理解 ...
- 几种 vue的数据交互形式
var that=this get请求 that.$http.get("1.txt").then(function(result){ console.log(result) thi ...
- 更改zendstudio花括号匹配显示的方法