從源碼理解Spring原理,並用代碼實現簡易Spring框架

  • 前言(本文爲原創,轉載請註明出處)

  個人之前對於框架的學習,就停留在配置,使用階段。說實話過段時間就會忘得蕩然無存。也不知道框架的運行邏輯,就是知道添加個註解,就可以用了。

  由於實習,時間比較多,也感恩遇到個好老師,教並給我時間看源碼,雖然沒有做過多少業務,但是感覺比做業務更有意義。慢慢的去跟代碼, 對Spring

  運行流程大致有個解。現分享給大家,不足之處,希望各位補充,相互學習。

  • 從源碼看Spring

  可能我們很少在意,ClassPathXmlApplicationContext這個類,其實這個類做了很多的事情,它纔是我們瞭解Spring框架的窗戶。 

    ClassPathXmlApplicationContext c=new ClassPathXmlApplicationContext("ApplicationContext.xml");

 當我們執行上面的語句的時候,

  public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
  throws BeansException {
     super(parent);
   setConfigLocations(configLocations);
   if (refresh) {
   refresh();
   }
  }
實際上走的是這個構造函數,這個構造函數做了兩個事情,一是setConfigLocations()方法初始化一些配置。一是reFresh()函數,該函數進行了Bean的註冊,事件廣播等。
refresh()函數十分重要,具體幹了什麼,請看下面的源碼註釋:
   public void refresh() throws BeansException, IllegalStateException {
  synchronized (this.startupShutdownMonitor) {
   prepareRefresh();
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
  prepareBeanFactory(beanFactory);
  try {
   // Allows post-processing of the bean factory in context subclasses.
   postProcessBeanFactory(beanFactory);
  // 註冊Bean.
   invokeBeanFactoryPostProcessors(beanFactory);
  // 登記攔截bean創建的處理器
   registerBeanPostProcessors(beanFactory);
  initMessageSource();
   // 創建了一個廣播事件的類
  initApplicationEventMulticaster();
  onRefresh();
  // 註冊事件監聽者
  registerListeners();
  // 實例化那些被配置成單例的Bean
  finishBeanFactoryInitialization(beanFactory);
  // 結束刷新,實際上就是廣播事件等操作
   finishRefresh();
  }
   catch (BeansException ex) {
   // Destroy already created singletons to avoid dangling resources.
  destroyBeans();
  // Reset 'active' flag.
  cancelRefresh(ex);
  // Propagate exception to caller.
  throw ex;
   }
  }
  }
 先對Spring框架的事件機制簡單的做個擴展,常規來看事件涉及如下幾方:
  1)事件本身(生產者)
  2)消費事件者
  3)事件管理(訂閱中心)
 1.Spring事件本身從ApplicationEvent派生,事件消費者爲ApplicationListener<T extends ApplicationEvent>,事件管理中心爲ApplicationEventMulticaster
  它負責管理監聽者等。
 2.Spring當廣播一個事件時,它首先去查找該事件的監聽者,然後再去遍歷監聽者調用其onApplicationEvent(Application evnet)接口,將事件傳給監聽者。
  最後當我們調用getBean()的時候,實際上經過refresh()的bean註冊,已經被緩存到map裏面,直接出map裏面取出實例化即可。

  • 代碼簡易實現Spring
     

 

  上面的工程目錄結構爲com.springImpl.annotion放的spring的註解類。com.springImple.core放得實現Spring框架的核心類。com.springImpl.test放的是測試類。

  1)註解類:

   假設現在我這個框架還是比較搓,就一個註解,

    import java.lang.annotation.*;
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)//爲了書寫簡單 這裏只作用於屬性 也就是域 成員變量
    public @interface Resources {
    }

   2)事件類:

   現在這個事件就是一個約定,實際啥也沒有     

    public class ApplicationEvent {
    }

  3)監聽者類  

    public interface ApplicationListener<T extends ApplicationEvent> {
    void onApplicationEvent(T event);
    }

  4)事件訂閱中心類

    public interface ApplicationEventMulticaster {
     void publishEvent(ApplicationEvent event);
    }

  5)解析配置文件的類

    public class ConfigResolver extends ApplicationEvent implements ApplicationEventMulticaster{
    private String configXml="spring.xml";
    static HashMap<String ,Object> BeanFactory;//這裏就是模仿beanFactory 將所有的bean用beanid與對應實例用map保存起來
    static HashMap<String ,ApplicationListener> RegistryListener;//這裏保存那些是監聽者的bean
    static {
    BeanFactory=new HashMap<>();
    RegistryListener=new HashMap<>();
    }
    public ConfigResolver(String config){
    configXml=config==null?configXml:config;//默認就是spring.xml
    setConfigLocations(configXml);
    refresh();
    }
     public Object getBean(String beanId){
    return BeanFactory.get(beanId);
     }
     private void setConfigLocations(String configXml){
    //什麼都不做 當然可以做一些環境的檢查 將配置的提取用一個類去處理等等 我這偷個懶
    }
    private void refresh(){
    //註冊bean
    invokeBeanFactoryPostProcessors(BeanFactory);
    //登記監聽者
    registerListeners();
    //j結束刷新 表面程序已經啓動 可以廣播這個刷新完畢事件了 廣播事件
    finishRefresh();
    }
    private void finishRefresh(){
    publishEvent(this);
  }

     /**
     * 從beanfactory找到那些是監聽者類型的bean
     */
    private void registerListeners(){
    Iterator<String> it=BeanFactory.keySet().iterator();
    while(it.hasNext()){
    String key=it.next();
    if(BeanFactory.get(key) instanceof ApplicationListener){
     RegistryListener.put(key,(ApplicationListener)BeanFactory.get(key));
     it.remove();
    }
    }
     }

     /**
    * 將配置文件中的bean全部實例化到map裏面
    * @param beanFactory
    */
     private void invokeBeanFactoryPostProcessors(HashMap beanFactory){

    InputStream in= null;
    try {
     in = ConfigResolver.class.getResourceAsStream(configXml)==null?
              new FileInputStream(configXml):ConfigResolver.class.getResourceAsStream(configXml);//兼容資源路徑 與 絕對路徑
    } catch (FileNotFoundException e) {
     e.printStackTrace();
     }
    try {
     DocumentBuilder db=DocumentBuilderFactory.newInstance().newDocumentBuilder();
    Document dc=db.parse(in);
    NodeList nl=dc.getElementsByTagName("bean");
    for(int i=0;i<nl.getLength();i++){
    NamedNodeMap attrs= nl.item(i).getAttributes();
     HashMap<String,String> beanMap=new HashMap<>();//對應一個bean標籤
    for(int j=0;j<attrs.getLength();j++){
    String beanNodeName=attrs.item(j).getNodeName();
    String beanNodeValue=null;
    if(beanNodeName!=null) {
    beanNodeValue = attrs.item(j).getNodeValue();
    }
    if(beanNodeValue!=null){
     beanMap.put(beanNodeName,beanNodeValue);
     }
    }
     String beanId=beanMap.get("id");
    String beanClass=beanMap.get("class");
    if(beanClass==null||beanId==null){
     continue;
     }
     try {
     Class cls=Class.forName(beanClass);
     Object beanObject=cls.newInstance();
    Field[] fds=beanObject.getClass().getDeclaredFields();
    for(Field fd:fds){
    fd.setAccessible(true);//獲取訪問私有變量權限
    Resources rs=fd.getAnnotation(Resources.class);
    if(rs!=null){
     fd.set(beanObject,fd.getType().newInstance());//實例化帶有Resource註解的成員
    }
    }
    beanFactory.put(beanId,beanObject);//將bean放到map
    } catch (ClassNotFoundException e) {
     e.printStackTrace();
    } catch (IllegalAccessException e) {
     e.printStackTrace();
    } catch (InstantiationException e) {
     e.printStackTrace();
    }
     }
     } catch (ParserConfigurationException e) {
     e.printStackTrace();
     } catch (SAXException e) {
     e.printStackTrace();
    } catch (IOException e) {
     e.printStackTrace();
     }
     }

    /**
    * 廣播事件
     * @param event
     */
     @Override
     public void publishEvent(ApplicationEvent event) {
    Iterator<String> it=RegistryListener.keySet().iterator();
    while(it.hasNext()){
    RegistryListener.get(it.next()).onApplicationEvent(event);
    }
    }
    }
  6)看一下測試類:
    //監聽程序啓動的類 監聽者
    public class ApplicationStartLister implements ApplicationListener<ApplicationEvent> {
     @Override
     public void onApplicationEvent(ApplicationEvent event) {
     System.out.println("SpringImpl App start");
    }
    }
  
    //假設這裏有個眼瞎的人 他用註解注注入了個眼睛Ege類
    public class Blind {
    @Resources
    private Ege ege;
     public Ege getEge(){
    return ege;
     }
    }
    //眼睛Ege類
    public class Ege {
     public String see(){
    return "the world is so beautiful.";
    }
    }

    //主程序
     public class DoMain {
        public static void main(String []args){
     ConfigResolver cfg=new ConfigResolver("E:\\__Java\\__idea_proj\\SpringImpl\\src\\resources\\spring.xml");
     Blind b= (Blind) cfg.getBean("mybean");
     System.out.println("tell me how is the world :"+b.getEge().see());
     }
    }
    //配置文件

                  

   7)運行結果

      

                  

  到此完畢,一個簡單的模仿spring框架完畢。

 







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章