1:从最简单的工厂模式开始
BeanDefinition : 一个用来描述bean的类
BeanFactory : 一个用来存储 BeanDefinition 集合的类,提供了get和set方法。
BeanDefinition:
public class BeanDefinition {private Object bean;public BeanDefinition(Object bean) {this.bean = bean;}public Object getBean() {return bean;}}
BeanFactory:
public class BeanFactory {private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();public Object getBean(String name) {return beanDefinitionMap.get(name).getBean();}public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {beanDefinitionMap.put(name, beanDefinition);}}
测试类
public class BeanFactoryTest {@Testpublic void test() {// 1.初始化beanfactoryBeanFactory beanFactory = new BeanFactory();// 2.注入beanBeanDefinition beanDefinition = new BeanDefinition(new HelloWorldService());beanFactory.registerBeanDefinition("helloWorldService", beanDefinition);// 3.获取beanHelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");helloWorldService.helloWorld();}}public class HelloWorldService {public void helloWorld(){System.out.println("Hello World!");}}
使用工厂模式来存储BeanDefinition ,这个 BeanDefinition 是spring 在生成Bean之前, 要先对类进行封装,记下类的属性, 单例 , 类路径 等等一些 属性来描述这个以后要生成bean的这个类。
2:抽象工厂模式 创建bean
把 BeanFactory 变成接口,转换成抽象工厂模式,然后定义方法,具体的实现交给子类,子类新增创建bean的方法。
BeanFactory 接口
public interface BeanFactory {Object getBean(String name);void registerBeanDefinition(String name, BeanDefinition beanDefinition);}
抽象工厂
AbstractBeanFactory
public abstract class AbstractBeanFactory implements BeanFactory {private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();@Overridepublic Object getBean(String name) {return beanDefinitionMap.get(name).getBean();}@Overridepublic void registerBeanDefinition(String name, BeanDefinition beanDefinition) {Object bean = doCreateBean(beanDefinition);beanDefinition.setBean(bean);beanDefinitionMap.put(name, beanDefinition);}/*** 初始化bean* @param beanDefinition* @return*/protected abstract Object doCreateBean(BeanDefinition beanDefinition);}
抽象工厂实现类
public class AutowireCapableBeanFactory extends AbstractBeanFactory {@Overrideprotected Object doCreateBean(BeanDefinition beanDefinition) {try {Object bean = beanDefinition.getBeanClass().newInstance();return bean;} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}return null;}}
BeanDefinition 除了会有生成的bean属性外,新增class classname属性
public class BeanDefinition {private Object bean;private Class beanClass;private String beanClassName;public BeanDefinition() {}public void setBean(Object bean) {this.bean = bean;}public Class getBeanClass() {return beanClass;}public void setBeanClass(Class beanClass) {this.beanClass = beanClass;}public String getBeanClassName() {return beanClassName;}public void setBeanClassName(String beanClassName) {this.beanClassName = beanClassName;try {this.beanClass = Class.forName(beanClassName);} catch (ClassNotFoundException e) {e.printStackTrace();}}public Object getBean() {return bean;}}
3:创建bean 再设置bean的属性
BeanFactory , AbstractBeanFactory 代码不变
新增类 PropertyValue 用来描述bean对象的属性
public class PropertyValue {private final String name;private final Object value;public PropertyValue(String name, Object value) {this.name = name;this.value = value;}public String getName() {return name;}public Object getValue() {return value;}}
新增属性集合类,而并不是直接使用一个集合,这样做的好处就是,通过类封装集合,可以在设置集合的时候,再设置其他的一下属性。
PropertyValues
public class PropertyValues {private final List<PropertyValue> propertyValueList = new ArrayList<PropertyValue>();public PropertyValues() {}public void addPropertyValue(PropertyValue pv) {//TODO:这里可以对于重复propertyName进行判断,直接用list没法做到this.propertyValueList.add(pv);}public List<PropertyValue> getPropertyValues() {return this.propertyValueList;}}
在BeanDefinition中新增PropertyValues 集合类
public class BeanDefinition {private Object bean;private Class beanClass;private String beanClassName;private PropertyValues propertyValues;......}
在实现类去实现创建类的时候,要把对象属性设置上去
public class AutowireCapableBeanFactory extends AbstractBeanFactory {@Overrideprotected Object doCreateBean(BeanDefinition beanDefinition) throws Exception {Object bean = createBeanInstance(beanDefinition);applyPropertyValues(bean, beanDefinition);return bean;}protected Object createBeanInstance(BeanDefinition beanDefinition) throws Exception {return beanDefinition.getBeanClass().newInstance();}protected void applyPropertyValues(Object bean, BeanDefinition mbd) throws Exception {for (PropertyValue propertyValue : mbd.getPropertyValues().getPropertyValues()) {Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName());declaredField.setAccessible(true);declaredField.set(bean, propertyValue.getValue());}}}
4:怎么获取BeanDefinition(xml)
资源接口以及实现类
//定义抽象类 来获取资源的流public interface Resource {InputStream getInputStream() throws IOException;}//通过url可以获取资源 提供获取资源的方式public class UrlResource implements Resource {private final URL url;public UrlResource(URL url) {this.url = url;}@Overridepublic InputStream getInputStream() throws IOException{URLConnection urlConnection = url.openConnection();urlConnection.connect();return urlConnection.getInputStream();}}//资源加载器public class ResourceLoader {public Resource getResource(String location){URL resource = this.getClass().getClassLoader().getResource(location);return new UrlResource(resource);}}
定义 BeanDefinitionReader 来得到 BeanDefinition ,然后在抽象类定义获取的BeanDefinition 集合和获取BeanDefinition 的来源的ResourceLoader
spring中存在大量的抽象类来实现接口的方式(类似装饰器模式),通过包装抽象类,把所有实现类的功能再抽象到一个类中。
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader {private Map<String,BeanDefinition> registry;private ResourceLoader resourceLoader;protected AbstractBeanDefinitionReader(ResourceLoader resourceLoader) {this.registry = new HashMap<String, BeanDefinition>();this.resourceLoader = resourceLoader;}public Map<String, BeanDefinition> getRegistry() {return registry;}public ResourceLoader getResourceLoader() {return resourceLoader;}}
具体的XmlBeanDefinitionReader 类继承 BeanDefinitionReader,通过解析xml -> resource 来获取bean
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {public XmlBeanDefinitionReader(ResourceLoader resourceLoader) {super(resourceLoader);}@Overridepublic void loadBeanDefinitions(String location) throws Exception {InputStream inputStream = getResourceLoader().getResource(location).getInputStream();doLoadBeanDefinitions(inputStream);}protected void doLoadBeanDefinitions(InputStream inputStream) throws Exception {DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();DocumentBuilder docBuilder = factory.newDocumentBuilder();Document doc = docBuilder.parse(inputStream);// 解析beanregisterBeanDefinitions(doc);inputStream.close();}public void registerBeanDefinitions(Document doc) {Element root = doc.getDocumentElement();parseBeanDefinitions(root);}protected void parseBeanDefinitions(Element root) {NodeList nl = root.getChildNodes();for (int i = 0; i < nl.getLength(); i++) {Node node = nl.item(i);if (node instanceof Element) {Element ele = (Element) node;processBeanDefinition(ele);}}}protected void processBeanDefinition(Element ele) {String name = ele.getAttribute("name");String className = ele.getAttribute("class");BeanDefinition beanDefinition = new BeanDefinition();processProperty(ele,beanDefinition);beanDefinition.setBeanClassName(className);getRegistry().put(name, beanDefinition);}private void processProperty(Element ele,BeanDefinition beanDefinition) {NodeList propertyNode = ele.getElementsByTagName("property");for (int i = 0; i < propertyNode.getLength(); i++) {Node node = propertyNode.item(i);if (node instanceof Element) {Element propertyEle = (Element) node;String name = propertyEle.getAttribute("name");String value = propertyEle.getAttribute("value");beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name,value));}}}}
5:解决循环依赖问题
解决循环依赖问题核心思想:
创建一个bean属性的时候判断这个bean是否存在。
详细就是:用一个对象来描述一个类引用其他类的情况,之前初始化beanDefintion的时候就调用createbean方法,现在统一再getbean的时候判断为空就创建bean,然后如果想就把所有的bean初始化,循环beanname 然后创建bean。
核心代码:
1:填充属性的时候发现是对象,就再调用getbean方法,如果容器有这个bean就能直接获取到这个bean,如果容器没有这个bean就再去创建bean直到它返回。
private void applyPropertyValues(Object bean, BeanDefinition beanDefinition) {try {//获取所有的属性的集合PropertyValues propertyValues = beanDefinition.getPropertyValues();for(PropertyValue propertyValue : propertyValues.getPropertyValues()){Field field = bean.getClass().getDeclaredField(propertyValue.getName());field.setAccessible(true);Object value = propertyValue.getValue();//在加载属性的时候发现这个属性是一个bean,去把这个bean获取到然后设置到属性上if (value instanceof BeanReference) {BeanReference beanReference = (BeanReference) value;//就是说这个类的bean属性设置的时候 又会去调用父方法的getBean方法获取bean,// 这个就是我们在调试spring源码的时候 老是转回来的原因 也就是我们放弃的原因value = getBean(beanReference.getName());}field.set(bean, value);}}catch (Exception e){e.printStackTrace();}}
@Overridepublic Object getBean(String name) {BeanDefinition beanDefinition = beanDefinitionMap.get(name);if(null == beanDefinition){throw new IllegalArgumentException("No bean named " + name + " is defined");}Object bean = beanDefinition.getBean();if(null == bean){bean = doCreateBean(beanDefinition);}return bean;}
2:在读取xml配置的时候,要提前识别这个属性 是一个bean ,然后初始化这个bean的时候才能知晓
private void processProperty(Element ele, BeanDefinition beanDefinition) {NodeList propertyNode = ele.getElementsByTagName("property");for (int i = 0; i < propertyNode.getLength(); i++) {Node node = propertyNode.item(i);if (node instanceof Element) {Element propertyEle = (Element) node;String name = propertyEle.getAttribute("name");String value = propertyEle.getAttribute("value");//是普通的含有值的属性 直接把属性值添加进来if (value != null && value.length() > 0) {beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, value));}else{//没有值的 那没有值的一种是ref 就是属性是其他bean情况String ref = propertyEle.getAttribute("ref");//如果配置和ref 没有配置ref内容 抛出异常if (ref == null || ref.length() == 0) {throw new IllegalArgumentException("Configuration problem: <property> element for property '"+ name + "' must specify a ref or value");}//如果ref配置了一个其他bean的名称, 之前定义的描述属性 对象类 也可以存储这个 bean属性,因为 PropertyValue 的属性值是一个ObjectBeanReference beanReference = new BeanReference(ref);beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, beanReference));}}}}
6:AppliactionContext 加入
新增applicationContext接口,老三样,接口,抽象类,具体实现类
public interface ApplicationContext extends BeanFactory {}
public abstract class AbstractApplicationContext implements ApplicationContext{protected AbstractBeanFactory beanFactory;public AbstractApplicationContext(AbstractBeanFactory beanFactory) {this.beanFactory = beanFactory;}public void refresh() throws Exception{}@Overridepublic Object getBean(String name) {return beanFactory.getBean(name);}}
public class ClassPathXmlApplicationContext extends AbstractApplicationContext{private String configLocation;//加载xml的地址public ClassPathXmlApplicationContext(String configLocation) throws Exception {this(configLocation, new AutowireCapableBeanFactory());}public ClassPathXmlApplicationContext(String configLocation, AbstractBeanFactory beanFactory) throws Exception{super(beanFactory);this.configLocation = configLocation;refresh();}/*** 相当于把之前的加载的这一段代码 都放在了ApplicationContext 中* @throws Exception*/@Overridepublic void refresh() throws Exception {XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());xmlBeanDefinitionReader.loadBeanDefinitions(configLocation);for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());}}}
核心就是 applicationContext 继承了BeanFactory类,然后把上一张我们初始化 beanDefintion map等动作的功能干了.
调用方式如下 ,只能说很像, 有点相似了。
public void test() throws Exception {ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("tinyiocl6.xml");OrderService orderService = (OrderService) classPathXmlApplicationContext.getBean("orderService");System.out.println(orderService.getStockService());}

