亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Spring實(shí)現(xiàn)一個(gè)簡(jiǎn)單的SpringIOC容器

 更新時(shí)間:2017年04月14日 10:55:45   作者:醉眼識(shí)朦朧  
本篇文章主要介紹了Spring實(shí)現(xiàn)一個(gè)簡(jiǎn)單的SpringIOC容器,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。

接觸Spring快半年了,前段時(shí)間剛用Spring4+S2H4做完了自己的畢設(shè),但是很明顯感覺(jué)對(duì)Spring尤其是IOC容器的實(shí)現(xiàn)原理理解的不到位,說(shuō)白了,就是僅僅停留在會(huì)用的階段,有一顆想讀源碼的心于是買了一本計(jì)文柯的《Spring技術(shù)內(nèi)幕》,第二章沒(méi)看完,就被我扔一邊了,看的那是相當(dāng)痛苦,深深覺(jué)得自己資質(zhì)尚淺,能力還不夠,昨天在網(wǎng)上碰巧看到一個(gè)實(shí)現(xiàn)簡(jiǎn)單的SpringIOC容器的視頻教程,于是跟著做了一遍,竟然相當(dāng)順利,至少每一行代碼都能理解,于是細(xì)心整理了一番,放在這里.

主要思想:

提到IOC,第一反應(yīng)就是控制反轉(zhuǎn),我以前以為SpringIOC就是控制反轉(zhuǎn),控制反轉(zhuǎn)就是SpringIOC,當(dāng)然這種理解是錯(cuò)誤的,控制反轉(zhuǎn)是一種思想,一種模式,而Spring的IOC容器是實(shí)現(xiàn)了這種思想這種模式的一個(gè)載體.

使用過(guò)Spring的人都熟知,SpringIOC容器可以在對(duì)象生成或初始化時(shí)就直接將數(shù)據(jù)注入到對(duì)象中,如果對(duì)象A的屬性是另一個(gè)對(duì)象B,還可以將這個(gè)對(duì)象B的引用注入到注入到A的數(shù)據(jù)域中.

如果在初始化對(duì)象A的時(shí)候,對(duì)象B還沒(méi)有進(jìn)行初始化,而A又需要對(duì)象B作為自己的屬性,那么就會(huì)用一種遞歸的方式進(jìn)行注入,這樣就可以把對(duì)象的依賴關(guān)系清晰有序的建立起來(lái).

IOC容器解決問(wèn)題的核心就是把創(chuàng)建和管理對(duì)象的控制權(quán)從具體的業(yè)務(wù)對(duì)象手中搶過(guò)來(lái).由IOC容器來(lái)管理對(duì)象之間的依賴關(guān)系,并由IOC容器完成對(duì)象的注入.這樣就把應(yīng)用從復(fù)雜的對(duì)象依賴關(guān)系的管理中解放出來(lái),簡(jiǎn)化了程序的開發(fā)過(guò)程.

下圖是這個(gè)簡(jiǎn)單IOC容器的類圖(原諒我真沒(méi)學(xué)過(guò)UML,湊合看吧):

程序中所有的Bean之間的依賴關(guān)系我們是放在一個(gè)xml文件中進(jìn)行維護(hù)的,就是applicationContext.xml  

ConfigManager類完成的功能是讀取xml,并將所有讀取到有用的信息封裝到我們創(chuàng)建的一個(gè)Map<String,Bean>集合中,用來(lái)在初始化容器時(shí)創(chuàng)建bean對(duì)象.

定義一個(gè)BeanFactory的接口,接口中有一個(gè)getBean(String name)方法,用來(lái)返回你想要?jiǎng)?chuàng)建的那個(gè)對(duì)象.

然后定義一個(gè)該接口的實(shí)現(xiàn)類ClassPathXmlApplicationContext.就是在這個(gè)類的構(gòu)造方法中,初始化容器,通過(guò)調(diào)用ConfigManager的方法返回的Map集合,通過(guò)反射和內(nèi)省一一創(chuàng)建bean對(duì)象.這里需要注意,對(duì)象的創(chuàng)建有兩個(gè)時(shí)間點(diǎn),這取決與bean標(biāo)簽中scope屬性的值:  

  1. 如果scope="singleton",那么對(duì)象在容器初始化時(shí)就已創(chuàng)建好,用的時(shí)候只需要去容器中取即可.
  2. 如果scope="prototype",那么容器中不保存這個(gè)bean的實(shí)例對(duì)象,每次開發(fā)者需要使用這個(gè)對(duì)象時(shí)再進(jìn)行創(chuàng)建.

使用的主要知識(shí)點(diǎn):

  1. dom4j解析xml文件
  2. xpath表達(dá)式(用于解析xml中的標(biāo)簽)
  3. java反射機(jī)制
  4. 內(nèi)省(獲取Bean屬性的set方法進(jìn)行賦值)

項(xiàng)目結(jié)構(gòu)圖及介紹如下:

         

項(xiàng)目需要的jar包與項(xiàng)目結(jié)構(gòu)已經(jīng)在上圖中介紹了,這個(gè)項(xiàng)目所能實(shí)現(xiàn)的功能如下:

1. IOC容器能管理對(duì)象的創(chuàng)建以及對(duì)象之間的依賴關(guān)系.

2. 能夠?qū)崿F(xiàn)數(shù)據(jù)的自動(dòng)類型轉(zhuǎn)換(借助BeanUtils).

3. 能夠?qū)崿F(xiàn)scope="singleton"和scope="prototype"的功能,即能夠控制對(duì)象是否為單例.  

下面介紹代碼部分:

application.xml:

<?xml version="1.0" encoding="utf-8"?>
<beans>
  <bean name="student" class="com.wang.entity.Student" >
    <property name="name" value="123"></property>
  </bean>
  
  <bean name="teacher" class="com.wang.entity.Teacher">
    <property name="student" ref="student"></property>
  </bean>
  <bean name="person" class="com.wang.entity.Person" scope="prototype">
    <property name="teacher" ref="teacher"></property>
    <property name="student" ref="student"></property>
  </bean>
  
</beans>

實(shí)體類Student,Teacher,Person:

package com.wang.entity;
//Student類
public class Student {
  private String name;

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }
}
/************************************/
package com.wang.entity;
//Teacher類
public class Teacher {

  private Student student;

  public Student getStudent() {
    return student;
  }

  public void setStudent(Student student) {
    this.student = student;
  }
   
}
/************************************/
package com.wang.entity;
//Person類
public class Person {

  private Student student;
  private Teacher teacher;
  
  public Student getStudent() {
    return student;
  }
  public void setStudent(Student student) {
    this.student = student;
  }
  public Teacher getTeacher() {
    return teacher;
  }
  public void setTeacher(Teacher teacher) {
    this.teacher = teacher;
  }
}

用于封裝Bean標(biāo)簽信息的Bean類:

package com.wang.config;

import java.util.ArrayList;
import java.util.List;

public class Bean {

  
  private String name;
  private String className;
  private String scope="singleton";
  private List<Property> properties=new ArrayList<Property>();

  
  public String getScope() {
    return scope;
  }

  public void setScope(String scope) {
    this.scope = scope;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String getClassName() {
    return className;
  }

  public void setClassName(String className) {
    this.className = className;
  }

  public List<Property> getProperties() {
    return properties;
  }

  public void setProperties(List<Property> properties) {
    this.properties = properties;
  }

  
}

用與封裝Bean子標(biāo)簽property內(nèi)容的Property類:

package com.wang.config;

public class Property {

  private String name;
  private String value;
  private String ref;
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getValue() {
    return value;
  }
  public void setValue(String value) {
    this.value = value;
  }
  public String getRef() {
    return ref;
  }
  public void setRef(String ref) {
    this.ref = ref;
  }

  
}

ConfigManager類:

package com.wang.config.parse;

import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.Test;

import com.wang.config.Bean;
import com.wang.config.Property;

public class ConfigManager {
  
  private static Map<String,Bean> map=new HashMap<String,Bean>(); 

  //讀取配置文件并返回讀取結(jié)果
  //返回Map集合便于注入,key是每個(gè)Bean的name屬性,value是對(duì)應(yīng)的那個(gè)Bean對(duì)象
  public static Map<String, Bean> getConfig(String path){
    /*dom4j實(shí)現(xiàn)
     * 1.創(chuàng)建解析器
     * 2.加載配置文件,得到document對(duì)象
     * 3.定義xpath表達(dá)式,取出所有Bean元素
     * 4.對(duì)Bean元素繼續(xù)遍歷
     *   4.1將Bean元素的name/class屬性封裝到bean類屬性中
     *   4.2獲得bean下的所有property子元素
     *   4.3將屬性name/value/ref分裝到類Property類中
     * 5.將property對(duì)象封裝到bean對(duì)象中
     * 6.將bean對(duì)象封裝到Map集合中,返回map 
      */
    //1.創(chuàng)建解析器
    SAXReader reader=new SAXReader();
    //2.加載配置文件,得到document對(duì)象
    InputStream is = ConfigManager.class.getResourceAsStream(path);
    Document doc =null;
    try {
       doc = reader.read(is);
    } catch (DocumentException e) {
      e.printStackTrace();
      throw new RuntimeException("請(qǐng)檢查您的xml配置是否正確");
    }
    // 3.定義xpath表達(dá)式,取出所有Bean元素
    String xpath="http://bean";
    
    //4.對(duì)Bean元素繼續(xù)遍歷
    List<Element> list = doc.selectNodes(xpath);
    if(list!=null){
      //4.1將Bean元素的name/class屬性封裝到bean類屬性中
    
       // 4.3將屬性name/value/ref分裝到類Property類中
      for (Element bean : list) {
        Bean b=new Bean();
        String name=bean.attributeValue("name");
        String clazz=bean.attributeValue("class");
        String scope=bean.attributeValue("scope");
        b.setName(name);
        b.setClassName(clazz);
        if(scope!=null){
          b.setScope(scope);
        }
         // 4.2獲得bean下的所有property子元素
        List<Element> children = bean.elements("property");
        
         // 4.3將屬性name/value/ref分裝到類Property類中
        if(children!=null){
          for (Element child : children) {
            Property prop=new Property();
            String pName=child.attributeValue("name"); 
            String pValue=child.attributeValue("value");
            String pRef=child.attributeValue("ref");
            prop.setName(pName);
            prop.setRef(pRef);
            prop.setValue(pValue);
            // 5.將property對(duì)象封裝到bean對(duì)象中
            b.getProperties().add(prop);
          }
        }
        //6.將bean對(duì)象封裝到Map集合中,返回map 
        map.put(name, b);
      }
    }
    
    return map;
  }

}

 BeanFactory接口:

package com.wang.main;

public interface BeanFactory {
  //核心方法getBean
  Object getBean(String name);
}

ClassPathXmlApplicationContext類:

package com.wang.main;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.beanutils.BeanUtils;
import org.junit.Test;

import com.wang.config.Bean;
import com.wang.config.Property;
import com.wang.config.parse.ConfigManager;
import com.wang.entity.Student;
//import com.wang.utils.BeanUtils;
import com.wang.utils.BeanUtil;

public class ClassPathXmlApplicationContext implements BeanFactory {

  // 獲得讀取的配置文件中的Map信息
  private Map<String, Bean> map;
  // 作為IOC容器使用,放置sring放置的對(duì)象
  private Map<String, Object> context = new HashMap<String, Object>();

  public ClassPathXmlApplicationContext(String path) {
    // 1.讀取配置文件得到需要初始化的Bean信息
    map = ConfigManager.getConfig(path);
    // 2.遍歷配置,初始化Bean
    for (Entry<String, Bean> en : map.entrySet()) {
      String beanName = en.getKey();
      Bean bean = en.getValue();

      Object existBean = context.get(beanName);
      // 當(dāng)容器中為空并且bean的scope屬性為singleton時(shí)
      if (existBean == null && bean.getScope().equals("singleton")) {
        // 根據(jù)字符串創(chuàng)建Bean對(duì)象
        Object beanObj = createBean(bean);

        // 把創(chuàng)建好的bean對(duì)象放置到map中去
        context.put(beanName, beanObj);
      }
    }

  }

  // 通過(guò)反射創(chuàng)建對(duì)象
  private Object createBean(Bean bean) {
    // 創(chuàng)建該類對(duì)象
    Class clazz = null;
    try {
      clazz = Class.forName(bean.getClassName());
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
      throw new RuntimeException("沒(méi)有找到該類" + bean.getClassName());
    }
    Object beanObj = null;
    try {
      beanObj = clazz.newInstance();
    } catch (Exception e) {
      e.printStackTrace();
      throw new RuntimeException("沒(méi)有提供無(wú)參構(gòu)造器");
    }
    // 獲得bean的屬性,將其注入
    if (bean.getProperties() != null) {
      for (Property prop : bean.getProperties()) {
        // 注入分兩種情況
        // 獲得要注入的屬性名稱
        String name = prop.getName();
        String value = prop.getValue();
        String ref = prop.getRef();
        // 使用BeanUtils工具類完成屬性注入,可以自動(dòng)完成類型轉(zhuǎn)換
        // 如果value不為null,說(shuō)明有
        if (value != null) {
          Map<String, String[]> parmMap = new HashMap<String, String[]>();
          parmMap.put(name, new String[] { value });
          try {
            BeanUtils.populate(beanObj, parmMap);
          } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("請(qǐng)檢查你的" + name + "屬性");
          }
        }

        if (ref != null) {
          // 根據(jù)屬性名獲得一個(gè)注入屬性對(duì)應(yīng)的set方法
          // Method setMethod = BeanUtil.getWriteMethod(beanObj,
          // name);

          // 看一看當(dāng)前IOC容器中是否已存在該bean,有的話直接設(shè)置沒(méi)有的話使用遞歸,創(chuàng)建該bean對(duì)象
          Object existBean = context.get(prop.getRef());
          if (existBean == null) {
            // 遞歸的創(chuàng)建一個(gè)bean
            existBean = createBean(map.get(prop.getRef()));
            // 放置到context容器中
            // 只有當(dāng)scope="singleton"時(shí)才往容器中放
            if (map.get(prop.getRef()).getScope()
                .equals("singleton")) {
              context.put(prop.getRef(), existBean);
            }
          }
          try {
            // setMethod.invoke(beanObj, existBean);
              //通過(guò)BeanUtils為beanObj設(shè)置屬性
            BeanUtils.setProperty(beanObj, name, existBean);
          } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("您的bean的屬性" + name
                + "沒(méi)有對(duì)應(yīng)的set方法");
          }

        }

      }
    }

    return beanObj;
  }

  @Override
  public Object getBean(String name) {
    Object bean = context.get(name);
    // 如果為空說(shuō)明scope不是singleton,那么容器中是沒(méi)有的,這里現(xiàn)場(chǎng)創(chuàng)建
    if (bean == null) {
      bean = createBean(map.get(name));
    }

    return bean;
  }

}

最后就是一個(gè)測(cè)試類TestBean:

 package com.wang.main;

import org.junit.Test;

import com.wang.entity.Person;
import com.wang.entity.Student;
import com.wang.entity.Teacher;


public class TestBean {

  @Test
  public void func1(){
    
    BeanFactory bf=new ClassPathXmlApplicationContext("/applicationContext.xml");
    Person s=(Person)bf.getBean("person");
    Person s1=(Person)bf.getBean("person");
    System.out.println(s==s1);
    System.out.println(s1);
    Student stu1=(Student) bf.getBean("student");
    Student stu2=(Student) bf.getBean("student");
    String name=stu1.getName();
    System.out.println(name);
    System.out.println(stu1==stu2);
  }
}

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringBoot打Jar包在命令行運(yùn)行流程詳解

    SpringBoot打Jar包在命令行運(yùn)行流程詳解

    這篇文章主要介紹了SpringBoot打Jar包在命令行運(yùn)行流程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • SpringBoot集成redisson全過(guò)程

    SpringBoot集成redisson全過(guò)程

    本文主要介紹了如何集成Redisson,包括環(huán)境配置、引入Redisson的依賴、添加Redisson的配置類以及Redisson的常見使用方法,在類中注入Redisson后,可以獲取鎖對(duì)象和使用,這些都是作者的個(gè)人經(jīng)驗(yàn),供讀者參考
    2024-10-10
  • SpringBoot使用Scheduling實(shí)現(xiàn)定時(shí)任務(wù)的示例代碼

    SpringBoot使用Scheduling實(shí)現(xiàn)定時(shí)任務(wù)的示例代碼

    Spring Boot提供了一種方便的方式來(lái)實(shí)現(xiàn)定時(shí)任務(wù),即使用Spring的@Scheduled注解,通過(guò)在方法上添加@Scheduled注解,我們可以指定方法在何時(shí)執(zhí)行,本文我們就給大家介紹一下SpringBoot如何使用Scheduling實(shí)現(xiàn)定時(shí)任務(wù),需要的朋友可以參考下
    2023-08-08
  • 解決javaBean規(guī)范導(dǎo)致json傳參首字母大寫將永遠(yuǎn)獲取不到問(wèn)題

    解決javaBean規(guī)范導(dǎo)致json傳參首字母大寫將永遠(yuǎn)獲取不到問(wèn)題

    這篇文章主要介紹了解決javaBean規(guī)范導(dǎo)致json傳參首字母大寫將永遠(yuǎn)獲取不到問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • SpringMVC REST風(fēng)格深入詳細(xì)講解

    SpringMVC REST風(fēng)格深入詳細(xì)講解

    這篇文章主要介紹了SpringMVC REST風(fēng)格,Rest全稱為Representational State Transfer,翻譯為表現(xiàn)形式狀態(tài)轉(zhuǎn)換,它是一種軟件架構(gòu)
    2022-10-10
  • Java中properties文件中的中文亂碼問(wèn)題

    Java中properties文件中的中文亂碼問(wèn)題

    Properties為了方便用戶的配置,用于讀取Java的配置文件,不同的編程語(yǔ)言有自己所支持的配置文件,能讓用戶夠脫離程序本身去修改相關(guān)的變量設(shè)置,這篇文章主要介紹了Java中properties文件中的中文亂碼問(wèn)題,需要的朋友可以參考下
    2023-08-08
  • SpringMVC實(shí)現(xiàn)文件上傳下載功能

    SpringMVC實(shí)現(xiàn)文件上傳下載功能

    這篇文章主要為大家詳細(xì)介紹了springMVC實(shí)現(xiàn)文件上傳和下載的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • Java 利用枚舉實(shí)現(xiàn)接口進(jìn)行統(tǒng)一管理

    Java 利用枚舉實(shí)現(xiàn)接口進(jìn)行統(tǒng)一管理

    這篇文章主要介紹了Java 利用枚舉實(shí)現(xiàn)接口進(jìn)行統(tǒng)一管理,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-02-02
  • Java基于Scanner對(duì)象的簡(jiǎn)單輸入計(jì)算功能示例

    Java基于Scanner對(duì)象的簡(jiǎn)單輸入計(jì)算功能示例

    這篇文章主要介紹了Java基于Scanner對(duì)象的簡(jiǎn)單輸入計(jì)算功能,結(jié)合實(shí)例形式分析了Java使用Scanner對(duì)象獲取用戶輸入半徑值計(jì)算圓形面積功能,需要的朋友可以參考下
    2018-01-01
  • springboot整合spring-data-redis遇到的坑

    springboot整合spring-data-redis遇到的坑

    使用springboot整合redis,使用默認(rèn)的序列化配置,然后使用redis-client去查詢時(shí)查詢不到相應(yīng)的key.問(wèn)題出在哪,怎么解決呢?下面小編給大家?guī)?lái)了springboot整合spring-data-redis遇到的坑,需要的的朋友參考下吧
    2017-04-04

最新評(píng)論