接口&多态
我有一辆自行车,每天骑着它去上班
package com.zhao.SpringIoc;
public class Bike {
public void go() {
System.out.println("骑单车去上班");
}
}
package com.zhao.SpringIoc;
public class ShuaiQiZhao {
private static Bike bike;
// private static Bus bus;
// private static Car car;
public static void main(String[] args) {
bike = new Bike();
bike.go(); // 骑单车去上班
}
}
过了不久,我不想骑车觉得太累,于是我坐公交上班
package com.zhao.SpringIoc;
public class Bus {
public void go() {
System.out.println("乘坐公交去上班");
}
}
package com.zhao.SpringIoc;
public class ShuaiQiZhao {
// private static Bike bike;
private static Bus bus;
// private static Car car;
public static void main(String[] args) {
bus = new Bus();
bus.go(); // 乘坐公交去上班
}
}
没过多久我有钱了,买了一辆汽车,于是我每天开车上班
package com.zhao.SpringIoc;
public class Car {
public void go() {
System.out.println("开着玛莎去上班");
}
}
package com.zhao.SpringIoc;
public class ShuaiQiZhao {
// private static Bike bike;
// private static Bus bus;
private static Car car;
public static void main(String[] args) {
car = new Car();
car.go(); // 开着玛莎去上班
}
}
当我每买一辆交通工具,我就要修改Person类中成员变量和main方法中的交通工具。有人觉得这也没什么呀?那是因为代码不是你写的,看当然比做要来的舒服!而且如果有一千种交通工具,你还会这样说吗?
用多态改善上述情况
管家管理这些交通工具
package com.zhao.SpringIoc;
public interface Movable {
public void go(); // 抽象三种交通工具共有行为(去上班)
}
三种交通工具实现这个接口
package com.zhao.SpringIoc.Impl;
import com.zhao.SpringIoc.Movable;
public class Bike implements Movable {
public void go() {
System.out.println("骑单车去上班");
}
}
package com.zhao.SpringIoc.Impl;
import com.zhao.SpringIoc.Movable;
public class Bus implements Movable {
public void go() {
System.out.println("乘坐公交去上班");
}
}
package com.zhao.SpringIoc.Impl;
import com.zhao.SpringIoc.Movable;
public class Car implements Movable {
public void go() {
System.out.println("开着玛莎去上班");
}
}
帅气赵找到管家
package com.zhao.SpringIoc;
import com.zhao.SpringIoc.Impl.Car;
public class ShuaiQiZhao {
private static Movable movable;
public static void main(String[] args) {
movable = new Car();
movable.go(); // 开着玛莎去上班
}
}
对比一下,以前想用某种交通工具就要声明它的成员变量,修改main方法的类名,引用名。
现在只需要改下类名就行,是不是很方便?
但这也不是最方便的,就是每次都有自己 new 对象。但这也是无可奈何的,那就真的没有别的办法了吗?
有
Spring最擅长的就是管理,需要什么对象你管它要就行。传统编程,需要手动创建各种对象,在对象内部控制对象。Spring则是将设计好的对象交给容器管理(IOC)。需要什么对象,你找它拿。
正文
Spring的对象是由Xml文档,或者注解产生的。我们先不说注解,那离我们太远。就从xml开始谈。
搭建环境接口:BookService
package com.zhao.Interface;
public interface BookService {
double getBookPrice();
}
接口:PressService
package com.zhao.Interface;
public interface PressService {
String say();
}
接口实现类:BookServiceImpl
package com.zhao.service;
import com.zhao.Interface.BookService;
public class BookServiceImpl implements BookService {
@Override
public double getBookPrice() {
return 508.8;
}
}
接口实现类:PressServiceImpl
package com.zhao.service;
import com.zhao.Interface.BookService;
import com.zhao.Interface.PressService;
public class PressServiceImpl implements PressService {
private BookService bookService;
public void setBookService(BookService bookService) {
this.bookService = bookService;
}
@Override
public String say() {
return "本书的价格是:" + bookService.getBookPrice();
}
}
配置文件:applicationContext.xml
启动类:SourceCodeLearning
package com.zhao;
import com.zhao.Interface.PressService;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
public class SourceCodeLearning {
public static void main(String[] args) {
//从容器中获取名字为user的bean
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
PressService pressService = (PressService) bf.getBean("pressService");
//调用bean的方法
String price = pressService.say();
System.out.println(price);
}
}
好了,开始了哦!
咱们由结果分析过程,现在你把自己当成Spring,首先第一件事要做的是什么?是不是加载配置文件,看看有哪些Bean需要创建?万事开头难,迈出了第一步下面就好办了!
- 加载配置文件
- 解析配置文件
- 解析后的Bean信息放入Map集合中
加载配置文件
我现在是Spring,我并不知道我接下来面临的是什么,是加载Xml文件,还是加载JSON文件,亦或加载yaml文件,这些对于我都是未知的。但是我一点也不慌,你们每一种配置文件都要实现我的规则,也就是 Resource,现在是Xml文件,用来加载Xml文件的是 XmlBeanFactory
package org.springframework.beans.factory.xml;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.core.io.Resource;
@Deprecated
@SuppressWarnings({"serial", "all"})
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}
在 XmlBeanFactory 类中真正干活的是 XmlBeanDefinitionReader (XBDR),由它去读取Xml配置文件中的Bean给我。一开始我还挺好奇它是怎么读取的,但是看到它爸爸的朋友老王 ResourceLoader,我就知道肯定是王叔叔把自己的看家本领教给它了。没过多久 XBDR 抱着一堆数据回来了,但是这密密麻麻的数据谁也看不懂,于是 XBDR 请自己的好朋友 documentLoader 帮忙把它翻译成 Doc文档(Java文件),documentLoader 再请自己的好朋友 BeanDefinitionParserDelegate,进行标签解析。
由于加载和解析的过程并不重要,这里就只展示了流程图。具体源码自己 Debgger 下行了。我们更关心的是解析后的javaBean存储在什么地方,和Ioc容器是如何创建!
BeanDefinitionParserDelegate对默认标签的解析
package org.springframework.beans.factory.xml;
public class DefaultBeanDefinitiondocumentReader implements BeanDefinitiondocumentReader {
// BDDR的好朋友,解析标签
@Nullable
private BeanDefinitionParserDelegate delegate;
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, import_ELEMENT)) {
// 解析 import 标签
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
// 解析 alias 标签
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
// 解析 bean 标签
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// 解析 beans 标签
doRegisterBeanDefinitions(ele);
}
}
// 解析 bean 标签
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 好朋友的方法进行解析,经此方法,bdHolder实例已经包含配置文件中配置的各种属性,例如:Class,name,id
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
//如果存在默认标签的子节点下再有自定义属性,对自定义标签进行解析
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
//解析完后,对解析后的 bdHolder 进行注册
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
//通知相关的监听器,这个bean已经加载完成了
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
}
解析标签的源码就精简一下吧?不然密密麻麻的代码看起来头疼!
public class BeanDefinitionParserDelegate {
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
// 解析 ID
String id = ele.getAttribute(ID_ATTRIBUTE);
// 解析 name
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
// 调用parseBeanDefinitionElement方法,解析其他属性
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {
//创建用于承载属性的 GenericBeanDefinition,它在xml文件中对应的就是Bean标签
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
...
return bd;
}
finally {
this.parseState.pop();
}
return null;
}
}
这里着重讲
// 遍历,提取所有 constructor-arg ,然后进行解析
public class BeanDefinitionParserDelegate {
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) {
// 实现具体的解析过程
parseConstructorArgElement((Element) node, bd);
}
}
}
// 实现具体的解析过程
public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
// 提取 index 属性
String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
// 提取 type 属性
String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
// 提取 name 属性
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(indexAttr)) {
try {
int index = Integer.parseInt(indexAttr);
if (index < 0) {
error("'index' cannot be lower than 0", ele);
}
else {
try {
Object value = parsePropertyValue(ele, bd, null);
ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
if (StringUtils.hasLength(typeAttr)) {
valueHolder.setType(typeAttr);
}
if (StringUtils.hasLength(nameAttr)) {
valueHolder.setName(nameAttr);
}
valueHolder.setSource(extractSource(ele));
bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
}
finally {
this.parseState.pop();
}
}
}
catch (NumberFormatException ex) {
error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
}
}
else {
try {
this.parseState.push(new ConstructorArgumentEntry());
Object value = parsePropertyValue(ele, bd, null);
ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
if (StringUtils.hasLength(typeAttr)) {
valueHolder.setType(typeAttr);
}
if (StringUtils.hasLength(nameAttr)) {
valueHolder.setName(nameAttr);
}
valueHolder.setSource(extractSource(ele));
bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
}
finally {
this.parseState.pop();
}
}
}
}
上面的代码大概的意思是,
如果配置文件指定了index,那么操作步骤如下。
- 解析 constructor-arg 的子元素
- 使用 ConstructorArgumentValues.ValueHolder 类型来封装解析出来的元素。
- 将type,name和index树勋个一并封装在ConstructorArgumentValues.ValueHolder类型中并添加至当前 BeanDefinition 的 ConstructorArgumentValues 的 IndexedArgumentValue 属性中。
如果没有指定index属性,那么操作步骤如下
- 解析 constructor-arg 的子元素
- 使用 ConstructorArgumentValues.ValueHolder 类型来封装解析出来的元素。
- 将type,name和index树勋个一并封装在ConstructorArgumentValues.ValueHolder类型中并添加至当前 BeanDefinition 的 ConstructorArgumentValues 的 GenericArgumentValue 属性中。
等以上标签解析完毕,要做的就是注册了。也就是 DefaultBeanDefinitiondocumentReader 类中方法 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,getReaderContext().getRegistry());
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition oldBeanDefinition;
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(oldBeanDefinition)) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set updatedSingletons = new linkedHashSet<>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
}
将bean注册至 register 中,以beanName为key,以beanDefinition 为值,注册至 register(Map)集合中。
上面的代码大概的意思是
- 校验
- 对 beanName 已经注册的情况处理。如果设置了不允许bean的覆盖,则需要抛出异常,否则直接覆盖
- 加入map缓存
- 清除解析之前留下的对应beanName的缓存
方法 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); 实现通知监听器解析。spring目前并没有对此事件做任何的逻辑处理。



