1. 程式人生 > >Spring學習筆記一之容器

Spring學習筆記一之容器

        老實說樓主也是從今天才開始學習Spring的底層知識,所以很多細節知識樓主也不懂,So從網上get了很多Spring相關的資料作為參考,以下內容是對學習的知識做一個簡單的彙總.

        在正式學習Spring核心之前,先了解IOC最基礎的組成部分:容器。

        案例一:簡單的容器

/**
 * 容器的元素物件,用於儲存類
 */
class BeanDefinition {
    private Object bean;
    public BeanDefinition(Object bean) {
        this.bean = bean;
    }
    public Object getBean() {
        return bean;
    }
}

/**
 * 容器工廠
 */
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);
    }
}

/**
 * 被 容器的元素 儲存的類
 */
class HelloWorldService {
    public void helloWorld(){
        System.out.println("Hello World!");
    }
}

/**
 * 測試
 */
class BeanFactoryMain {
    public static void main(String[] args) {
        // 1.初始化beanfactory
        BeanFactory beanFactory = new BeanFactory();
        // 2.注入bean
	BeanDefinition beanDefinition = new BeanDefinition(new HelloWorldService());
	beanFactory.registerBeanDefinition("helloWorldService", beanDefinition);
        // 3.獲取bean
        HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");
            helloWorldService.helloWorld();
	}
}

        以上程式碼是一個單純的map,有get和put bean的功能,示例一個簡單的容器,程式碼簡單在此不做解釋。

        通過以上程式碼我們知道了容器的基礎構成,對容器有了基本的瞭解,而優秀的容器會有更深層的包含,循序漸進,我們也需要做進一步瞭解。

        案例二:通過反射維護容器

/**
 * 容器的元素物件,用於儲存類
 */
class BeanDefinition {
    private Object bean;
    private Class beanClass;
    private String beanClassName;
	
    public BeanDefinition() {}
    public Object getBean() {
        return bean;
    }
    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();
	}
    }
}

/**
 * 定義 bean工廠/容器 的內含:儲存 和 取出
 */
interface BeanFactory {
    // 獲取容器的元素
    Object getBean(String name);
    // 註冊容器的元素
    void registerBeanDefinition(String name, BeanDefinition beanDefinition);
}

/**
 * 抽象BeanFactory
 * 1.具體化介面中的定義,使得抽象BeanFactory具備 獲取容器的元素 和 新增容器的元素 的能力
 * 2.建立新定義: 初始化 容器元素 
 */
abstract class AbstractBeanFactory implements BeanFactory {
    private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
    @Override
    public Object getBean(String name) {
	return beanDefinitionMap.get(name).getBean();
    }
    @Override
    public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
        Object bean = doCreateBean(beanDefinition);
        beanDefinition.setBean(bean);
        beanDefinitionMap.put(name, beanDefinition);
    }
    /**
     * 初始化bean
     */
    protected abstract Object doCreateBean(BeanDefinition beanDefinition);
}

/**
 * 自動註冊容器工廠
 * 1.繼承抽象BeanFactory的方法 獲取容器的元素 和 新增容器的元素
 * 2.具體化抽象BeanFactory的定義:建立Bean
 */
class AutowireCapableBeanFactory extends AbstractBeanFactory {
    @Override
    protected Object doCreateBean(BeanDefinition beanDefinition) {
        try {
            Object bean = beanDefinition.getBeanClass().newInstance();
            return bean;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }
}

/**
 * 被 容器的元素 儲存的類
 */
class HelloWorldService {
    public void helloWorld(){
        System.out.println("Hello World!");
    }
}

/**
 * 測試
 */
class BeanFactoryTest {
    public static void main() {
        // 1.初始化beanfactory
        BeanFactory beanFactory = new AutowireCapableBeanFactory();
	// 2.注入bean
	BeanDefinition beanDefinition = new BeanDefinition();
        beanDefinition.setBeanClassName("us.codecraft.tinyioc.HelloWorldService");
	beanFactory.registerBeanDefinition("helloWorldService", beanDefinition);
        // 3.獲取bean
        HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");
        helloWorldService.helloWorld();
    }
}

        有了對比物件,我們來分析上面兩個案例的區別:

            1.初始化定義

            2.BeanFactory類 抽象化

            3.BeanFactory 儲存物件 從 傳變數獲取儲存 到 傳地址從反射中獲取儲存

        有什麼好處?

            解耦 容器 對 儲存物件 的獲取方式,原本 只能通過方法傳物件獲取,現在 既支援 反射獲取 又支援 傳物件獲取
        還算簡單的例子,接著往下看。

          案例三 :通過反射新增bean屬性

        

/**
 * 用於儲存、獲取property的容器
 */
class PropertyValues {
    private final List<PropertyValue> propertyValueList = new ArrayList<PropertyValue>();
    public PropertyValues() {}
    public void addPropertyValue(PropertyValue pv) {
        //TODO:這裡可以對於重複propertyName進行判斷,直接用list沒法做到
	his.propertyValueList.add(pv);
    }
    public List<PropertyValue> getPropertyValues() {
	return this.propertyValueList;
    }
}

/**
 * property容器的元素,用於bean的屬性注入
 */
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;
    }
}

/**
 * 定義容器的元素
 * 1.儲存、獲取類物件
 * 2.儲存、獲取 property屬性
 */
class BeanDefinition {
    private Object bean;
    private Class beanClass;
    private String beanClassName;
    private PropertyValues propertyValues;

    public BeanDefinition() {}

    public Object getBean() {
	return bean;
    }
    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();
	}
    }
    // 獲取property物件的容器
    public PropertyValues getPropertyValues() {
        return propertyValues;
    }
    // 修改property物件的容器
    public void setPropertyValues(PropertyValues propertyValues) {
        this.propertyValues = propertyValues;
    }
}

/**
 * 定義BeanFactory
 */
interface BeanFactory {
    Object getBean(String name);
    void registerBeanDefinition(String name, BeanDefinition beanDefinition) throws Exception;
}

/**
 * 具體化BeanFactory,定義建立bean方法
 */
abstract class AbstractBeanFactory implements BeanFactory {
    private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
    @Override
    public Object getBean(String name) {
        return beanDefinitionMap.get(name).getBean();
    }
    @Override
    public void registerBeanDefinition(String name, BeanDefinition beanDefinition) throws Exception {
        Object bean = doCreateBean(beanDefinition);
        beanDefinition.setBean(bean);
        beanDefinitionMap.put(name, beanDefinition);
    }
    protected abstract Object doCreateBean(BeanDefinition beanDefinition) throws Exception;
}

/**
 * 自動裝配的BeanFactory
 *	1.具體化建立Bean方式
 * 2.通過反射修改Bean中的屬性
 */
class AutowireCapableBeanFactory extends AbstractBeanFactory {
    @Override
    protected 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());
	}
    }
}

/**
 * 被 BeanFactory(容器)的元素 儲存的類
 */
class HelloWorldService {
    private String text;
    public void helloWorld(){
        System.out.println(text);
    }
    public void setText(String text) {
        this.text = text;
    }
}

/**
 * 測試類
 */
class BeanFactoryTest {
    public static  void maint() throws Exception {
        // 1.初始化beanfactory
        BeanFactory beanFactory = new AutowireCapableBeanFactory();
        // 2.bean定義
        BeanDefinition beanDefinition = new BeanDefinition();
        beanDefinition.setBeanClassName("us.codecraft.tinyioc.HelloWorldService");
        // 3.設定屬性
        PropertyValues propertyValues = new PropertyValues();
        propertyValues.addPropertyValue(new PropertyValue("text", "Hello World!"));
        beanDefinition.setPropertyValues(propertyValues);
	// 4.生成bean
	beanFactory.registerBeanDefinition("helloWorldService", beanDefinition);
	// 5.獲取bean
	HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");
	helloWorldService.helloWorld();
    }
}

        享受閱讀程式碼的樂趣,在這就不講解程式碼具體流程

        這裡簡單的總結下案例二到案例三的改變:

              1 在案例二的基礎上繼續完善容器,使得BeanFactory在獲取類物件的同時還能注入外部屬性

       案例講到這裡,我們來說說 什麼是DI 依賴注入? 

              看案例,首先建立容器,再建立容器元素Bean,然後再一套接一套的將元素根據規則封裝起來,最終將物件儲存在容器中,這一套流程就叫做依賴注入,依賴定義,注入物件。接著往下看!

       案例四:讀取xml配置來初始化bean

/**
 * 具體化屬性容器:新增屬性 、獲取屬性容器
 */
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;
	}
}

/**
 *	具體化屬性封裝:初始化、獲取
 */
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;
    }
}

/**
 * 定義資源定位:獲取流
 */
public interface Resource {
    InputStream getInputStream() throws IOException;
}

/**
 * 具體化資源定位:流獲取方式
 */
public class UrlResource implements Resource {
    private final URL url;
    public UrlResource(URL url) {
        this.url = url;
    }
    @Override
    public InputStream getInputStream() throws IOException{
        URLConnection urlConnection = url.openConnection();
        urlConnection.connect();
        return urlConnection.getInputStream();
    }
}

/**
 * 具體化資源載入器
 */
class ResourceLoader {
    public Resource getResource(String location){
        URL resource = this.getClass().getClassLoader().getResource(location);
        return new UrlResource(resource);
    }
}

/**
 * 定義讀取BeanFactory的元素
 */
interface BeanDefinitionReader {
	void loadBeanDefinitions(String location) throws Exception;
}

/**
 * 抽象化讀取BeanFactory的元素
 * 1.定義屬性記錄容器
 * 2.定義屬性資源載入器
 */
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;
    }
}

/**
 * 具體化讀取BeanFactory的元素
 * 1.持有資源載入器
 * 2.具體化讀取BeanFactory容器的元素
 * 3.解析XML,將屬性注入到BeanDefinition,並儲存在屬性記錄容器中
 */
class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

	public XmlBeanDefinitionReader(ResourceLoader resourceLoader) {
		super(resourceLoader);
	}

	@Override
	public 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);
		// 解析bean
		registerBeanDefinitions(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));
            }
        }
    }
}

/**
 * bean定義
 */
class BeanDefinition {
	private Object bean;
	private Class beanClass;
	private String beanClassName;
	private PropertyValues propertyValues = new PropertyValues();
	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;
	}
	public PropertyValues getPropertyValues() {
		return propertyValues;
	}
	public void setPropertyValues(PropertyValues propertyValues) {
		this.propertyValues = propertyValues;
	}
}

/**
 * bean容器的定義
 */
 interface BeanFactory {
    Object getBean(String name);
    void registerBeanDefinition(String name, BeanDefinition beanDefinition) throws Exception;
}

 /**
  * 抽象化Bean容器
  */
 abstract class AbstractBeanFactory implements BeanFactory {
	private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
	@Override
    public Object getBean(String name) {
		return beanDefinitionMap.get(name).getBean();
	}
	@Override
    public void registerBeanDefinition(String name, BeanDefinition beanDefinition) throws Exception {
        Object bean = doCreateBean(beanDefinition);
        beanDefinition.setBean(bean);
        beanDefinitionMap.put(name, beanDefinition);
    }
    /**
     * 初始化bean
     * @param beanDefinition
     * @return
     */
    protected abstract Object doCreateBean(BeanDefinition beanDefinition) throws Exception;
}
 
 /**
  * 具體化一個可以自動裝配的BeanFactory容器
  */
 class AutowireCapableBeanFactory extends AbstractBeanFactory {
	@Override
	protected 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());
		}
	}
}
 
/**
 * 要注入屬性的class
 */
class HelloWorldService {
    private String text;
    public void helloWorld(){
        System.out.println(text);
    }
    public void setText(String text) {
        this.text = text;
    }
}

/**
 * XML中要讀取的Bean
 */
<bean name="helloWorldService" class="us.codecraft.tinyioc.HelloWorldService">
	<property name="text" value="Hello World!"></property>
</bean>

/**
 * 測試類
 */
class BeanFactoryTest {
	public static void main() throws Exception {
		// 1.讀取配置
		XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());
		xmlBeanDefinitionReader.loadBeanDefinitions("tinyioc.xml");
		// 2.初始化BeanFactory並註冊bean
		BeanFactory beanFactory = new AutowireCapableBeanFactory();
		for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {
			beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
		}
		// 3.獲取bean
		HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");
		helloWorldService.helloWorld();
	}
}

       看起來程式碼很多,但是覺得有種“泡沫”般的充實感,相比於案例三,在案例四中添加了一段程式碼用於讀取XML的文件節點,獲取節點上的屬性,通過容器來管理這些屬性,再結合案例三的內容將屬性注入到BeanFactory中,形成XML中Bean的注入