zoukankan      html  css  js  c++  java
  • 从源码理解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框架完毕。







  • 相关阅读:
    身残志坚,贫困学子返乡创业,做出生态产业园
    贫苦藏家女养豪猪,成功带领村民脱贫致富
    南航大学生校内创业,5个小摊位月销售5万元
    $_server[]关于浏览器和服务器的参数获取
    $_server[]关于浏览器和服务器的参数获取
    $_server[]关于浏览器和服务器的参数获取
    $_server[]关于浏览器和服务器的参数获取
    [20170616]recover copy of datafile 6.txt
    [20170616]recover copy of datafile 6.txt
    [20170616]recover copy of datafile 6.txt
  • 原文地址:https://www.cnblogs.com/enjoyall/p/7398314.html
Copyright © 2011-2022 走看看