上回书讲了BeanDefinition的基础知识,本篇文章咱们详细讨论BeanDefinition家族体系。 在讲解之前笔者再一次祭出BeanDefinition家族继承关系图:
java
复制代码
/*** BeanDefinition接口的父接口: 1. AttributeAccessor 1.1 实现类 AttributeAccessorSupport 作用是操作bd的属性,属性存放在LinkedHashMap。 2. BeanMetadataElement 2.1 实现类 BeanMetadataAttributeAccessor获取源即bd对应的class的磁盘文件位置 2.2 实现类 BeanMetadataAttributeAccessor继承了AttributeAccessorSupport既可以操作属性值,也可以操作源 2.3 属性封装对象 BeanMetadataAttribute ***/ public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement
1.BeanDefinition的父接口
上一篇博文详细讲了接口BeanDefinition的功能,笔者打算围绕该接口进行扩展。
首先看下BeanDefinition的父接口有哪些:
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement
BeanDefinition接口继承了AttributeAccessor和BeanMetadataElement两个接口。
也就是说BeanDefinition的实现类同时实现了
BeanDefinition 、AttributeAccessor、BeanMetadataElement三个接口的功能。
1.1 AttributeAccessor:作用操作bd属性
java
复制代码
/** *定义用于附加和访问BeanDefinition元数据的通用的接口,来自任意对象 */ public interface AttributeAccessor { /** 将属性名为name的属性的属性值设置为value 注意是BeanDefinition的属性 */ void setAttribute(String name, Object value); /** 获取指定name的属性值,如果该属性不存在,则返回Null 注意是BeanDefinition的属性 */ Object getAttribute(String name); /** 删除指定name的属性值,如果找不到Nmae属性的值则返回Null 注意是BeanDefinition的属性 */ Object removeAttribute(String name); /** 如果属性名为name的属性存在则返回true,否者返回false 注意是BeanDefinition的属性 */ boolean hasAttribute(String name); /** 返回所有的属性名称 注意是BeanDefinition的属性 */ String[] attributeNames(); }
该接口定义用于附加和访问BeanDefinition元数据,我们知道,接口只是定义了操作方法,这个接口的方法很简单,但我们看不出这个接口到底代表啥意思呢,回头看继承图,找到这个接口唯一的实现类AttributeAccessorSupport:
1.1.1实现类AttributeAccessorSupport
java
复制代码
public abstract class AttributeAccessorSupport implements AttributeAccessor, Serializable { /** Map with String keys and Object values. */ //用于存放属性键值对 private final Map<String, Object> attributes = new LinkedHashMap<>(); //设置属性值 value是BeanMetadataAttribute类型 @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); } } //获取属性值 value是BeanMetadataAttribute类型 @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中,是哪些属性值呢?看下面代码:
java
复制代码
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(); } }
查看interService对应的beanDefinition的attribute。
我们知道BeanDefinition用来描述你的业务类,那么,谁来描述BeanDefitino呢?
就是通过设置属性值来描述的!
比如beanDefinition的代理模式等,以后会讲到。这里的FULL和LITE就是是否生成代理的标志!
具体区别可参考: blog.csdn.net/tales522/ar…
1.2 BeanMetadataElement:作用是获取bd对应的class的磁盘文件位置
java
复制代码
public interface BeanMetadataElement { //获取源对象,可能返回null Object getSource(); }
BeanDefinition中存了业务类在虚拟机中的class,这个上篇博文讲了。
但是这个class文件存在你电脑硬盘哪里呢?
getSource翻译成中文就是获取源,对象的源是class,那class的源就是你硬盘上的文件。看下面代码:
java
复制代码
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()); } } //输出:file [E:\study\spring-framework\source-code\out\production\classes\tyrant\InterService.class]
1.2.1 实现:BeanMetadataAttributeAccessor
BeanMetadataElement接口提供了获取源的抽象方法。
真正的实现是在它的实现类BeanMetadataAttributeAccessor中。
BeanMetadataAttributeAccessor继承了AttributeAccessorSupport并且实现了BeanMetadataElement接口。
AttributeAccessorSupport实现了上面的AttributeAccessor。
我们看一下它的源码:
java
复制代码
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; } //设置属性值,如果已经存在就覆盖,不存在就添加,BeanMetadataAttribute封装了键值对 //注意value是1个BeanMetadataAttribute public void addMetadataAttribute(BeanMetadataAttribute attribute) { //super指的是AttributeAccessorSupport //AttributeAccessorSupport中维护了1个LinkedHashMap用于存放BD的属性 super.setAttribute(attribute.getName(), attribute); } /** * 根据名字获取属性键值对的封装对象BeanMetadataAttribute */ @Nullable public BeanMetadataAttribute getMetadataAttribute(String name) { //super指的是AttributeAccessorSupport //AttributeAccessorSupport中维护了1个LinkedHashMap用于存放BD的属性 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不但继承了AttributeAccessorSupport还实现了BeanMetadataElement,换言之,既可以操作属性值,也可以操作源。
1.2.1.1BeanMetadataAttribute
上面代码中的BeanMetadataAttribute其实就是对BeanDefinition的属性的键值对进行了封装,如下:
java
复制代码
public class BeanMetadataAttribute implements BeanMetadataElement { /** * 属性信息 */ private final String name; // 属性名 private final Object value; // 属性值 // bd的class对应的文件位置 private Object source; /** * 构造器(设置属性信息) */ 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接口。
总结
kotlin
复制代码
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement
vbnet
复制代码
BeanDefinition接口的父接口: 1. AttributeAccessor 1.1 实现类AttributeAccessorSupport是1个抽象类,作用是操作bd的属性,属性存放在LinkedHashMap。 1.2 LinkedHashMap的key是String,value是BeanMetadataAttribute。 2. BeanMetadataElement 2.1 实现类BeanMetadataAttributeAccessor,作用是获取源即bd对应的class的磁盘文件位置 2.2 实现类BeanMetadataAttributeAccessor继承了AttributeAccessorSupport既可以操作属性值,也可以操作源 2.3 通过重写AttributeAccessorSupport抽象类的方法和BeanMetadataAttribute对象操作bd的属性。 ***/
一句话总结:BeanDefinition实现类BeanMetadataAttributeAccessor实现了BeanMetadataElement继承了AttributeAccessorSupport。既可以设置和获取源,也可以设置和获取bd的属性值。
作者:Emanon
链接:https://juejin.cn/post/7234909292447744037
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。