【问题标题】:Why GORM is using methodMissing为什么 GORM 使用 methodMissing
【发布时间】:2012-11-21 21:06:25
【问题描述】:

当我读到here 时,grails 正在使用 methodMissing 将 GORM 方法注入到域类中,但是已经说过 methodMissing 执行起来很昂贵,因为只有在调度失败的情况下才会发生,为什么这些方法不是通过 metaClass 注入的或 AST 转换?有什么线索吗?

【问题讨论】:

  • 从 Grails 2 开始,大多数方法都是使用 AST 添加的。动态方法(findBy*、findAllBy* 等)并不是因为@sbglasius 指出最好按需添加这些方法
  • 好的,据我所知,sbglasius 和 Tomasz 都是正确的,不是吗?我的意思是 Tomasz 指出某些方法是由 AST 添加的,但作为 sbglasius 指出的不是动态查找器。

标签: grails groovy metaprogramming grails-orm abstract-syntax-tree


【解决方案1】:

使用 methodMissing 并没有那么昂贵,因为 Grails 仅在第一次执行未找到的方法时在 MOP 中创建一个新方法。后续执行发生在新创建的方法上。

考虑一个具有许多属性的域类。如果所有 findBy*、findAlLBy*、countBy* 等排列都应该在编译时创建,那么类很容易变得非常大。通过使用methodeMissing,只会创建运行时实际使用的方法。

【讨论】:

    【解决方案2】:

    据我了解代码,此信息已过时。这些方法被注入到元类中。查看 grails-hiberante 插件的代码。

    HibernateGrailsPlugin.groovy (github) 每次上下文启动时都会执行第 49 行:

    def doWithDynamicMethods = HibernatePluginSupport.doWithDynamicMethods
    

    然后,打开HibernatePluginSupport (github) 并按照流程操作:

    /*451*/ static final doWithDynamicMethods = { ApplicationContext ctx ->
        def grailsApplication = application
        enhanceSessionFactories(ctx, grailsApplication)
    }
    
    /*456*/ static void enhanceSessionFactories(ApplicationContext ctx, grailsApplication, source = null)
    // calls in line 464:
    /*464* enhanceSessionFactory sessionFactory, grailsApplication, ctx, suffix, datastores, source
    

    这个闭包在 enhanceSessionFactory 方法中是至关重要的:

    /*548*/ def enhanceEntity = ...
    

    它在第 581-583 行中为每个实体调用。方法是从方法registerNamespaceMethods 中的第587 行生成的。据我正确理解,这些方法从第 597 行直接注入到 metaClass:

        def classLoader = application.classLoader
    
        def finders = HibernateGormEnhancer.createPersistentMethods(application, classLoader, datastore)
        def staticApi = new HibernateGormStaticApi(dc.clazz, datastore, finders, classLoader, transactionManager)
        dc.metaClass.static."$getter" = { -> staticApi }
    
        def validateApi = new HibernateGormValidationApi(dc.clazz, datastore, classLoader)
        def instanceApi = new HibernateGormInstanceApi(dc.clazz, datastore, classLoader)
        dc.metaClass."$getter" = { -> new InstanceProxy(delegate, instanceApi, validateApi) }
    

    如果我错了,请修改并纠正我。我不太相信这一切都是正确的。这些只是我在阅读 Grails 源代码时的发现。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-27
      • 1970-01-01
      • 1970-01-01
      • 2020-05-07
      • 2012-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多