温馨提示:如果读者刚接触spring源码,建议从本专题第一篇读起,这样知识点才能串联起来。
本片博客你将学到BeanDefinition的父接口:
1. AttributeAccessor
1.1 实现类 AttributeAccessorSupport
2. BeanMetadataElement
2.1 实现类 BeanMetadataAttributeAccessor
2.2 属性封装对象 BeanMetadataAttribute
1、BeanDefinition的父接口
上一篇博文详细讲了接口BeanDefinition的功能,笔者打算围绕该接口进行扩展。
首先看下BeanDefinition的父接口有哪些:
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
.....省略
}
BeanDefinition
继承了AttributeAccessor
和BeanMetadataElement
两个接口。也就是说BeanDefinition
的实现类同时实现了BeanDefinition 、AttributeAccessor、BeanMetadataElement
三个接口的功能。
1.1 AttributeAccessor
/**
* Interface defining a generic contract for attaching and accessing metadata
* to/from arbitrary objects.
*定义用于附加和访问BeanDefinition元数据的通用的接口,来自任意对象
*/
public interface AttributeAccessor {
/**
* Set the attribute defined by {@code name} to the supplied {@code value}.
将name的属性值设置为value*/
void setAttribute(String name, Object value);
/**
* Get the value of the attribute identified by {@code name}.
* Return {@code null} if the attribute doesn't exist.
获取name的属性值,如果该属性不存在,则返回Null*/
Object getAttribute(String name);
/**
* Remove the attribute identified by {@code name} and return its value.
* Return {@code null} if no attribute under {@code name} is found.
删除name的属性值,如果找不到Nmae属性的值则返回Null*/
Object removeAttribute(String name);
/**
* Return {@code true} if the attribute identified by {@code name} exists.
如果name属性值存在则返回true,否者返回false*/
boolean hasAttribute(String name);
/**
* Return the names of all attributes.
返回所有的属性名称
*/
String[] attributeNames();
}
该接口定义用于附加和访问BeanDefinition元数据,我们知道,接口只是定义了操作方法,这个接口的方法很简单,但我们看不出这个接口到底代表啥意思呢,回头看继承图,找到这个接口唯一的实现类AttributeAccessorSupport
:
1.1.1AttributeAccessorSupport
public abstract class AttributeAccessorSupport implements AttributeAccessor, Serializable {
/** Map with String keys and Object values. */
//用于存放属性键值对
private final Map<String, Object> attributes = new LinkedHashMap<>();
//设置属性值
@Override
public void setAttribute(String name, @Nullable Object value) {
Assert.notNull(name, "Name must not be null");
if (value != null) {
this.attributes.put(name, value);
}
else {
removeAttribute(name);
}
}
//获取属性值
@Override
@Nullable
public Object getAttribute(String name) {
Assert.notNull(name, "Name must not be null");
return this.attributes.get(name);
}
//删除属性值
@Override
@Nullable
public Object removeAttribute(String name) {
Assert.notNull(name, "Name must not be null");
return this.attributes.remove(name);
}
//判断是否有属性值
@Override
public boolean hasAttribute(String name) {
Assert.notNull(name, "Name must not be null");
return this.attributes.containsKey(name);
}
//获取所有属性值名字
@Override
public String[] attributeNames() {
return StringUtils.toStringArray(this.attributes.keySet());
}
//内部使用,属性值的拷贝
/**
* Copy the attributes from the supplied AttributeAccessor to this accessor.
* @param source the AttributeAccessor to copy from
*/
protected void copyAttributesFrom(AttributeAccessor source) {
Assert.notNull(source, "Source must not be null");
String[] attributeNames = source.attributeNames();
for (String attributeName : attributeNames) {
setAttribute(attributeName, source.getAttribute(attributeName));
}
}
//重写equals方法,判断是否与别的属性类共用一个存储结构,即判断LinkedHashMap是否相等
@Override
public boolean equals(Object other) {
return (this == other || (other instanceof AttributeAccessorSupport &&
this.attributes.equals(((AttributeAccessorSupport) other).attributes)));
}
@Override
public int hashCode() {
return this.attributes.hashCode();
}
}
其实,这个实现类我们还是看不出他跟BeanDefinition有什么关系,但是我们搞清楚一点,就是AttributeAccessorSupport
就是维护一个LinkedHashMap
而已,BeanDefinition的某些属性值就存储在这个LinkedHashMap
中,是哪些属性值呢?看下面代码:
public class SpringTest {
public static void main(String[] args) throws InterruptedException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注册配置类
context.register(Config.class);
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClassName("com.InterService");
//设置属性值
beanDefinition.setAttribute("AttributeAccessor","源码之路");
//将beanDefinition注册到spring容器中
context.registerBeanDefinition("interService",beanDefinition);
//加载或者刷新当前的配置信息
context.refresh();
//拿到属性信息
String[] attributes = context.getBeanDefinition("interService").attributeNames();
}
}
image.png
我们知道BeanDefinition用来描述你的业务类,那么,谁来描述BeanDefitino呢?就是通过设置属性值来描述的!比如beanDefinition的代理模式等,以后会讲到。
1.2 BeanMetadataElement
public interface BeanMetadataElement {
//获取源对象,可能返回null
Object getSource();
}
啥意思?懵圈!
BeanDefinition中存了业务类在虚拟机中的class,这个上篇博文讲了。但是这个class文件存在你电脑硬盘哪里呢?或者这么讲,getSource翻译成中文就是获取源,对象的源是class,那class的源就是你硬盘上的文件。看下面代码:
public class SpringTest {
public static void main(String[] args) throws InterruptedException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注册配置类
context.register(Config.class);
//加载或者刷新当前的配置信息
context.refresh();
//获取InterService.class的源
System.out.println(context.getBeanDefinition("interService").getSource());
}
}
打印结果:
image.png
1.2.1 BeanMetadataAttributeAccessor
BeanMetadataElement 只是提供获取源的方法,真正的实现是在它的实现类BeanMetadataAttributeAccessor
中,我们看一下它的源码:
public class BeanMetadataAttributeAccessor extends AttributeAccessorSupport implements BeanMetadataElement {
@Nullable
private Object source;
/**
* Set the configuration source {@code Object} for this metadata element.
* <p>The exact type of the object will depend on the configuration mechanism used.
* 设置源
*/
public void setSource(@Nullable Object source) {
this.source = source;
}
@Override
@Nullable
//获取源
public Object getSource() {
return this.source;
}
/**
* Add the given BeanMetadataAttribute to this accessor's set of attributes.
* @param attribute the BeanMetadataAttribute object to register
*/
//设置属性值,如果已经存在就覆盖,不存在就添加,BeanMetadataAttribute封装了键值对
public void addMetadataAttribute(BeanMetadataAttribute attribute) {
super.setAttribute(attribute.getName(), attribute);
}
/**
* Look up the given BeanMetadataAttribute in this accessor's set of attributes.
* @param name the name of the attribute
* @return the corresponding BeanMetadataAttribute object,
* or {@code null} if no such attribute defined
* 根据名字获取属性键值对的封装对象BeanMetadataAttribute
*/
@Nullable
public BeanMetadataAttribute getMetadataAttribute(String name) {
return (BeanMetadataAttribute) super.getAttribute(name);
}
//设置属性值,name表示键,value表示值
@Override
public void setAttribute(String name, @Nullable Object value) {
super.setAttribute(name, new BeanMetadataAttribute(name, value));
}
@Override
@Nullable
//根据键获取属性值
public Object getAttribute(String name) {
BeanMetadataAttribute attribute = (BeanMetadataAttribute) super.getAttribute(name);
return (attribute != null ? attribute.getValue() : null);
}
@Override
@Nullable
//移除属性值,并返回值,不存在就返回空
public Object removeAttribute(String name) {
BeanMetadataAttribute attribute = (BeanMetadataAttribute) super.removeAttribute(name);
return (attribute != null ? attribute.getValue() : null);
}
}
BeanMetadataAttributeAccessor
不但继承了BeanMetadataElement还实现了AttributeAccessorSupport,换言之,既可以操作属性值,也可以操作源。
1.2.2 BeanMetadataAttribute
上文代码中的类BeanMetadataAttribute
其实就是对属性的键值对进行了封装,如下:
public class BeanMetadataAttribute implements BeanMetadataElement {
/**
* 属性信息
*/
private final String name; // 属性名
private final Object value; // 属性值
private Object source; // 属性所属对象,,这里的源是属性值对象的源,不是BeanDefinition中所封装的业务类的源
/**
* 构造器(设置属性信息)
*/
public BeanMetadataAttribute(String name, Object value) {
Assert.notNull(name, "Name must not be null");
this.name = name;
this.value = value;
}
/**
* 获取属性名、属性值以及获取、设置属性所属对象
*/
public String getName() {
return this.name;
}
public Object getValue() {
return this.value;
}
public void setSource(Object source) {
this.source = source;
}
@Override
public Object getSource() {
return this.source;
}
/**
* 判断属性是否相等
*/
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof BeanMetadataAttribute)) {
return false;
}
BeanMetadataAttribute otherMa = (BeanMetadataAttribute) other;
return (this.name.equals(otherMa.name) &&
ObjectUtils.nullSafeEquals(this.value, otherMa.value) &&
ObjectUtils.nullSafeEquals(this.source, otherMa.source));
}
@Override
public int hashCode() {
return this.name.hashCode() * 29 + ObjectUtils.nullSafeHashCode(this.value);
}
@Override
public String toString() {
return "metadata attribute '" + this.name + "'";
}
}
小总结:
至此,我们讲完了BeanDefinition接口、父接口、父接口实现类的源代码,BeanDefinition的实现类会继承BeanDefinition父接口的实现类。到此为止,BeanDefinition的实现类可以操作属性和源,下面讲解BeanDefinition的实现类如何实现BeanDefinition接口。
网友评论