1:从最简单的工厂模式开始

BeanDefinition : 一个用来描述bean的类
BeanFactory : 一个用来存储 BeanDefinition 集合的类,提供了get和set方法。

BeanDefinition:

  1. public class BeanDefinition {
  2. private Object bean;
  3. public BeanDefinition(Object bean) {
  4. this.bean = bean;
  5. }
  6. public Object getBean() {
  7. return bean;
  8. }
  9. }

BeanFactory:

  1. public class BeanFactory {
  2. private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
  3. public Object getBean(String name) {
  4. return beanDefinitionMap.get(name).getBean();
  5. }
  6. public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
  7. beanDefinitionMap.put(name, beanDefinition);
  8. }
  9. }

测试类

  1. public class BeanFactoryTest {
  2. @Test
  3. public void test() {
  4. // 1.初始化beanfactory
  5. BeanFactory beanFactory = new BeanFactory();
  6. // 2.注入bean
  7. BeanDefinition beanDefinition = new BeanDefinition(new HelloWorldService());
  8. beanFactory.registerBeanDefinition("helloWorldService", beanDefinition);
  9. // 3.获取bean
  10. HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");
  11. helloWorldService.helloWorld();
  12. }
  13. }
  14. public class HelloWorldService {
  15. public void helloWorld(){
  16. System.out.println("Hello World!");
  17. }
  18. }

使用工厂模式来存储BeanDefinition ,这个 BeanDefinition 是spring 在生成Bean之前, 要先对类进行封装,记下类的属性, 单例 , 类路径 等等一些 属性来描述这个以后要生成bean的这个类。

2:抽象工厂模式 创建bean

把 BeanFactory 变成接口,转换成抽象工厂模式,然后定义方法,具体的实现交给子类,子类新增创建bean的方法。

BeanFactory 接口

  1. public interface BeanFactory {
  2. Object getBean(String name);
  3. void registerBeanDefinition(String name, BeanDefinition beanDefinition);
  4. }

抽象工厂
AbstractBeanFactory

  1. public abstract class AbstractBeanFactory implements BeanFactory {
  2. private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
  3. @Override
  4. public Object getBean(String name) {
  5. return beanDefinitionMap.get(name).getBean();
  6. }
  7. @Override
  8. public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
  9. Object bean = doCreateBean(beanDefinition);
  10. beanDefinition.setBean(bean);
  11. beanDefinitionMap.put(name, beanDefinition);
  12. }
  13. /**
  14. * 初始化bean
  15. * @param beanDefinition
  16. * @return
  17. */
  18. protected abstract Object doCreateBean(BeanDefinition beanDefinition);
  19. }

抽象工厂实现类

  1. public class AutowireCapableBeanFactory extends AbstractBeanFactory {
  2. @Override
  3. protected Object doCreateBean(BeanDefinition beanDefinition) {
  4. try {
  5. Object bean = beanDefinition.getBeanClass().newInstance();
  6. return bean;
  7. } catch (InstantiationException e) {
  8. e.printStackTrace();
  9. } catch (IllegalAccessException e) {
  10. e.printStackTrace();
  11. }
  12. return null;
  13. }
  14. }

BeanDefinition 除了会有生成的bean属性外,新增class classname属性

  1. public class BeanDefinition {
  2. private Object bean;
  3. private Class beanClass;
  4. private String beanClassName;
  5. public BeanDefinition() {
  6. }
  7. public void setBean(Object bean) {
  8. this.bean = bean;
  9. }
  10. public Class getBeanClass() {
  11. return beanClass;
  12. }
  13. public void setBeanClass(Class beanClass) {
  14. this.beanClass = beanClass;
  15. }
  16. public String getBeanClassName() {
  17. return beanClassName;
  18. }
  19. public void setBeanClassName(String beanClassName) {
  20. this.beanClassName = beanClassName;
  21. try {
  22. this.beanClass = Class.forName(beanClassName);
  23. } catch (ClassNotFoundException e) {
  24. e.printStackTrace();
  25. }
  26. }
  27. public Object getBean() {
  28. return bean;
  29. }
  30. }

3:创建bean 再设置bean的属性

BeanFactory AbstractBeanFactory 代码不变
新增类 PropertyValue 用来描述bean对象的属性

  1. public class PropertyValue {
  2. private final String name;
  3. private final Object value;
  4. public PropertyValue(String name, Object value) {
  5. this.name = name;
  6. this.value = value;
  7. }
  8. public String getName() {
  9. return name;
  10. }
  11. public Object getValue() {
  12. return value;
  13. }
  14. }

新增属性集合类,而并不是直接使用一个集合,这样做的好处就是,通过类封装集合,可以在设置集合的时候,再设置其他的一下属性。
PropertyValues

  1. public class PropertyValues {
  2. private final List<PropertyValue> propertyValueList = new ArrayList<PropertyValue>();
  3. public PropertyValues() {
  4. }
  5. public void addPropertyValue(PropertyValue pv) {
  6. //TODO:这里可以对于重复propertyName进行判断,直接用list没法做到
  7. this.propertyValueList.add(pv);
  8. }
  9. public List<PropertyValue> getPropertyValues() {
  10. return this.propertyValueList;
  11. }
  12. }

BeanDefinition中新增PropertyValues 集合类

  1. public class BeanDefinition {
  2. private Object bean;
  3. private Class beanClass;
  4. private String beanClassName;
  5. private PropertyValues propertyValues;
  6. ......
  7. }

在实现类去实现创建类的时候,要把对象属性设置上去

  1. public class AutowireCapableBeanFactory extends AbstractBeanFactory {
  2. @Override
  3. protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception {
  4. Object bean = createBeanInstance(beanDefinition);
  5. applyPropertyValues(bean, beanDefinition);
  6. return bean;
  7. }
  8. protected Object createBeanInstance(BeanDefinition beanDefinition) throws Exception {
  9. return beanDefinition.getBeanClass().newInstance();
  10. }
  11. protected void applyPropertyValues(Object bean, BeanDefinition mbd) throws Exception {
  12. for (PropertyValue propertyValue : mbd.getPropertyValues().getPropertyValues()) {
  13. Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName());
  14. declaredField.setAccessible(true);
  15. declaredField.set(bean, propertyValue.getValue());
  16. }
  17. }
  18. }

4:怎么获取BeanDefinition(xml)

资源接口以及实现类

  1. //定义抽象类 来获取资源的流
  2. public interface Resource {
  3. InputStream getInputStream() throws IOException;
  4. }
  5. //通过url可以获取资源 提供获取资源的方式
  6. public class UrlResource implements Resource {
  7. private final URL url;
  8. public UrlResource(URL url) {
  9. this.url = url;
  10. }
  11. @Override
  12. public InputStream getInputStream() throws IOException{
  13. URLConnection urlConnection = url.openConnection();
  14. urlConnection.connect();
  15. return urlConnection.getInputStream();
  16. }
  17. }
  18. //资源加载器
  19. public class ResourceLoader {
  20. public Resource getResource(String location){
  21. URL resource = this.getClass().getClassLoader().getResource(location);
  22. return new UrlResource(resource);
  23. }
  24. }

定义 BeanDefinitionReader 来得到 BeanDefinition ,然后在抽象类定义获取的BeanDefinition 集合和获取BeanDefinition 的来源的ResourceLoader
spring中存在大量的抽象类来实现接口的方式(类似装饰器模式),通过包装抽象类,把所有实现类的功能再抽象到一个类中。

  1. public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader {
  2. private Map<String,BeanDefinition> registry;
  3. private ResourceLoader resourceLoader;
  4. protected AbstractBeanDefinitionReader(ResourceLoader resourceLoader) {
  5. this.registry = new HashMap<String, BeanDefinition>();
  6. this.resourceLoader = resourceLoader;
  7. }
  8. public Map<String, BeanDefinition> getRegistry() {
  9. return registry;
  10. }
  11. public ResourceLoader getResourceLoader() {
  12. return resourceLoader;
  13. }
  14. }

具体的XmlBeanDefinitionReader 类继承 BeanDefinitionReader,通过解析xml -> resource 来获取bean

  1. public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
  2. public XmlBeanDefinitionReader(ResourceLoader resourceLoader) {
  3. super(resourceLoader);
  4. }
  5. @Override
  6. public void loadBeanDefinitions(String location) throws Exception {
  7. InputStream inputStream = getResourceLoader().getResource(location).getInputStream();
  8. doLoadBeanDefinitions(inputStream);
  9. }
  10. protected void doLoadBeanDefinitions(InputStream inputStream) throws Exception {
  11. DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  12. DocumentBuilder docBuilder = factory.newDocumentBuilder();
  13. Document doc = docBuilder.parse(inputStream);
  14. // 解析bean
  15. registerBeanDefinitions(doc);
  16. inputStream.close();
  17. }
  18. public void registerBeanDefinitions(Document doc) {
  19. Element root = doc.getDocumentElement();
  20. parseBeanDefinitions(root);
  21. }
  22. protected void parseBeanDefinitions(Element root) {
  23. NodeList nl = root.getChildNodes();
  24. for (int i = 0; i < nl.getLength(); i++) {
  25. Node node = nl.item(i);
  26. if (node instanceof Element) {
  27. Element ele = (Element) node;
  28. processBeanDefinition(ele);
  29. }
  30. }
  31. }
  32. protected void processBeanDefinition(Element ele) {
  33. String name = ele.getAttribute("name");
  34. String className = ele.getAttribute("class");
  35. BeanDefinition beanDefinition = new BeanDefinition();
  36. processProperty(ele,beanDefinition);
  37. beanDefinition.setBeanClassName(className);
  38. getRegistry().put(name, beanDefinition);
  39. }
  40. private void processProperty(Element ele,BeanDefinition beanDefinition) {
  41. NodeList propertyNode = ele.getElementsByTagName("property");
  42. for (int i = 0; i < propertyNode.getLength(); i++) {
  43. Node node = propertyNode.item(i);
  44. if (node instanceof Element) {
  45. Element propertyEle = (Element) node;
  46. String name = propertyEle.getAttribute("name");
  47. String value = propertyEle.getAttribute("value");
  48. beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name,value));
  49. }
  50. }
  51. }
  52. }

5:解决循环依赖问题

整体结构图如下

image.png

解决循环依赖问题核心思想:
创建一个bean属性的时候判断这个bean是否存在。
详细就是:用一个对象来描述一个类引用其他类的情况,之前初始化beanDefintion的时候就调用createbean方法,现在统一再getbean的时候判断为空就创建bean,然后如果想就把所有的bean初始化,循环beanname 然后创建bean。
核心代码:
1:填充属性的时候发现是对象,就再调用getbean方法,如果容器有这个bean就能直接获取到这个bean,如果容器没有这个bean就再去创建bean直到它返回。

  1. private void applyPropertyValues(Object bean, BeanDefinition beanDefinition) {
  2. try {
  3. //获取所有的属性的集合
  4. PropertyValues propertyValues = beanDefinition.getPropertyValues();
  5. for(PropertyValue propertyValue : propertyValues.getPropertyValues()){
  6. Field field = bean.getClass().getDeclaredField(propertyValue.getName());
  7. field.setAccessible(true);
  8. Object value = propertyValue.getValue();
  9. //在加载属性的时候发现这个属性是一个bean,去把这个bean获取到然后设置到属性上
  10. if (value instanceof BeanReference) {
  11. BeanReference beanReference = (BeanReference) value;
  12. //就是说这个类的bean属性设置的时候 又会去调用父方法的getBean方法获取bean,
  13. // 这个就是我们在调试spring源码的时候 老是转回来的原因 也就是我们放弃的原因
  14. value = getBean(beanReference.getName());
  15. }
  16. field.set(bean, value);
  17. }
  18. }catch (Exception e){
  19. e.printStackTrace();
  20. }
  21. }
  1. @Override
  2. public Object getBean(String name) {
  3. BeanDefinition beanDefinition = beanDefinitionMap.get(name);
  4. if(null == beanDefinition){
  5. throw new IllegalArgumentException("No bean named " + name + " is defined");
  6. }
  7. Object bean = beanDefinition.getBean();
  8. if(null == bean){
  9. bean = doCreateBean(beanDefinition);
  10. }
  11. return bean;
  12. }

2:在读取xml配置的时候,要提前识别这个属性 是一个bean ,然后初始化这个bean的时候才能知晓

  1. private void processProperty(Element ele, BeanDefinition beanDefinition) {
  2. NodeList propertyNode = ele.getElementsByTagName("property");
  3. for (int i = 0; i < propertyNode.getLength(); i++) {
  4. Node node = propertyNode.item(i);
  5. if (node instanceof Element) {
  6. Element propertyEle = (Element) node;
  7. String name = propertyEle.getAttribute("name");
  8. String value = propertyEle.getAttribute("value");
  9. //是普通的含有值的属性 直接把属性值添加进来
  10. if (value != null && value.length() > 0) {
  11. beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, value));
  12. }else{
  13. //没有值的 那没有值的一种是ref 就是属性是其他bean情况
  14. String ref = propertyEle.getAttribute("ref");
  15. //如果配置和ref 没有配置ref内容 抛出异常
  16. if (ref == null || ref.length() == 0) {
  17. throw new IllegalArgumentException("Configuration problem: <property> element for property '"
  18. + name + "' must specify a ref or value");
  19. }
  20. //如果ref配置了一个其他bean的名称, 之前定义的描述属性 对象类 也可以存储这个 bean属性,因为 PropertyValue 的属性值是一个Object
  21. BeanReference beanReference = new BeanReference(ref);
  22. beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, beanReference));
  23. }
  24. }
  25. }
  26. }

6:AppliactionContext 加入

新增applicationContext接口,老三样,接口,抽象类,具体实现类

  1. public interface ApplicationContext extends BeanFactory {
  2. }
  1. public abstract class AbstractApplicationContext implements ApplicationContext{
  2. protected AbstractBeanFactory beanFactory;
  3. public AbstractApplicationContext(AbstractBeanFactory beanFactory) {
  4. this.beanFactory = beanFactory;
  5. }
  6. public void refresh() throws Exception{
  7. }
  8. @Override
  9. public Object getBean(String name) {
  10. return beanFactory.getBean(name);
  11. }
  12. }
  1. public class ClassPathXmlApplicationContext extends AbstractApplicationContext{
  2. private String configLocation;//加载xml的地址
  3. public ClassPathXmlApplicationContext(String configLocation) throws Exception {
  4. this(configLocation, new AutowireCapableBeanFactory());
  5. }
  6. public ClassPathXmlApplicationContext(String configLocation, AbstractBeanFactory beanFactory) throws Exception{
  7. super(beanFactory);
  8. this.configLocation = configLocation;
  9. refresh();
  10. }
  11. /**
  12. * 相当于把之前的加载的这一段代码 都放在了ApplicationContext 中
  13. * @throws Exception
  14. */
  15. @Override
  16. public void refresh() throws Exception {
  17. XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());
  18. xmlBeanDefinitionReader.loadBeanDefinitions(configLocation);
  19. for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {
  20. beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
  21. }
  22. }
  23. }

核心就是 applicationContext 继承了BeanFactory类,然后把上一张我们初始化 beanDefintion map等动作的功能干了.
调用方式如下 ,只能说很像, 有点相似了。

  1. public void test() throws Exception {
  2. ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("tinyiocl6.xml");
  3. OrderService orderService = (OrderService) classPathXmlApplicationContext.getBean("orderService");
  4. System.out.println(orderService.getStockService());
  5. }