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的注入