Rails源码阅读(六)ActionController::Dispatcher_用户请求在rails中的处理流程(1)

Rails源码阅读(六)ActionController::Dispatcher和接下来的处理流程_用户请求在rails中的处理流程(1)

--紧接这一节:Rails源码阅读(二)_script/server

前面的分析小回顾:

用户的请求,经过rack的栈后,终于到了rails的ActionController::Dispatcher,这也是一个rack的实现,因此,请求会去调用ActionController::Dispatcher的call方法,并且应该返回一个样子的数组:[status, header, body]

 

=ActionController::Dispatcher的new代码:

    # DEPRECATE: Remove arguments, since they are only used by CGI
    def initialize(output = $stdout, request = nil, response = nil)
      @output = output
      build_middleware_stack if @@cache_classes 
    end

#1 @@cache_classes 用处

 

@@cache_classes = true #这个是默认的,但是在develop环境中,设置为false

如果设置为false的话,每次请求都会重新加载???,这个在开发环境非常有用。

 

#2 build_middleware_stack做什么

    private
      def build_middleware_stack
        @app = @@middleware.build(lambda { |env| self.dup._call(env) })
      end

@@middleware从字面上也可以看出来,是存储middleware们的。

@@middleware是MiddlewareStack的一个实例

 

@@middleware的赋值代码:

    cattr_accessor :middleware
    self.middleware = MiddlewareStack.new do |middleware|
      middlewares = File.join(File.dirname(__FILE__), "middlewares.rb") 
      middleware.instance_eval(File.read(middlewares))
    end

# middlewares.rb文件内存储的是需要固定使用的rack们

use "Rack::Lock", :if => lambda {

  !ActionController::Base.allow_concurrency

}

use "ActionController::Failsafe"

use lambda { ActionController::Base.session_store },

    lambda { ActionController::Base.session_options }

use "ActionController::ParamsParser"

use "Rack::MethodOverride"

use "Rack::Head"

use "ActionController::StringCoercion"

# @@middleware是MiddlewareStack的一个实例,这个实例的build方法返回一个rack,这个rack是已经排列好stack顺序的rack

    def build(app)
      active.reverse.inject(app) { |a, e| e.build(a) } #看了后面就知道这里为啥用reverse了
    end

每一个在middlewares.rb里的rack,都会执行下面的方法

      def build(app)
        if block
          klass.new(app, *build_args, &block)
        else
          klass.new(app, *build_args)
        end
      end 

这样的结果是:每一个在middlewares.rb文件里的rack,都会new一个实例出来

 

build的结果:组成了一个很好的rack栈,先new的在顶端,app在最底端。返回的是顶端的实例。

是这样做到的:

    #ActionController::ParamsParser.new和.call的代码是这样的:
    def initialize(app)
      @app = app
    end
 
    def call(env) #先执行自己
      if params = parse_formatted_parameters(env)
        env["action_controller.request.request_parameters"] = params
      end
      @app.call(env) #后执行别人,即new的时候传入的app
    end

这样最后实现了目的:new的时候,持有了下一层的句柄@app,先执行自己的代码,最后执行@app.call,这样就实现了过滤栈的效果。这种方式不错~~  

 

 

@app = @@middleware.build(lambda { |env| self.dup._call(env) })在这里传入的一个block,会在放在stack的最底端。

@app就是最终的rack栈的句柄

有个小问题:self即inner_app = ActionController::Dispatcher.new对象,为啥dup呢???

 

分析完了new代码,接下来执行的应该是call代码:

=call的代码:

    def call(env)
      if @@cache_classes
        @app.call(env)
      else
        Reloader.run do
          # When class reloading is turned on, we will want to rebuild the
          # middleware stack every time we process a request. If we don't
          # rebuild the middleware stack, then the stack may contain references
          # to old classes metal classes, which will b0rk class reloading.
          build_middleware_stack
          @app.call(env)
        end
      end
    end

这里解释了在develop环境下时,@@cache_classes是关闭的,走else分支,每个请求都重新build rack-stack。

请求执行的过程为:

当有一个请求来的时候,会执行call,

执行call的时候,会build出一个rack栈,

先执行之前加入到rack栈中的rack,最后执行block,代码为:self.dup._call(env)

    #_call的代码:
    def _call(env)
      @env = env
      dispatch
    end

这里才进入主操作:就是dispatch方法!!

    def dispatch
      begin
        run_callbacks :before_dispatch
        Routing::Routes.call(@env)
      rescue Exception => exception
        if controller ||= (::ApplicationController rescue Base)
          controller.call_with_exception(@env, exception).to_a
        else
          raise exception
        end
      ensure
        run_callbacks :after_dispatch, :enumerator => :reverse_each
      end
    end

在这里,dispach做的真正的操作交给了Routing::Routes.call(@env) 

 

 

总结:

ActionController::Dispatcher这个rack的call操作做了哪些操作:

#1 根据配置build出了一个rack栈(并没有用栈,怎么实现的上面讲了)

#2 在develop中,@@cache_classes是false,每次请求都重新build一次rack-stack

#3 dispach操作,交给了ActionController::Routing::Routes.call(@env)

 

 

 

====结束====

===           ===

==                ==

=                     =

|                       |

 

Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计,皆可应用在项目、毕业设计、课程设计、期末/期/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值