使用Spring Bean声明覆盖Grails中的服务

时间:2016-03-30 23:23:07

标签: spring grails dependency-injection

我正在创建一个包含CustomService的新插件,用​​于替换现有插件中的现有服务。按照自定义安全性实现中显示的模式并显示here,我已将配置添加到resources.groovy,oldService(path.to.new.CustomService)。我也尝试将所有注入的类添加到此服务的闭包中。 (实际服务名称是代码块中的RegistrationPersonRegistrationCompositeService和NewRegistrationPersonRegistrationCompositeService)

我不希望原始应用程序代码对新插件有任何引用。但是,应用程序级别的BuildConfig将需要plugin.location条目。我的resource.groovy mods在新的插件中。我没有在这方面取得成功。我修改了错误的资源吗?如果原始应用程序代码中需要进行此更改,我将无法保持原始代码不变。我没有扩展原始服务,也没有使用覆盖注释。我的目的是在启动时替换服务(Spring bean)。新插件依赖于旧插件,试图管理加载这些类的操作顺序。

以前在控制器中注入旧服务是否重要?这将要求我以相同的方式覆盖新插件中的控制器并为期望的行为注入正确的服务?

我发现文档显示在插件中,resources.groovy将被忽略。此外,将resources.groovy构建成战争也是有问题的。我还没有找到解决方案。我没有得到任何可以分享的错误,只是缺少了所期望的行为;原始服务正在处理请求。

//was resource.groovy - now renamed to serviceOverRide.groovy - still located in \grails-app\conf\spring of plugin
//tried this with and without the BeanBuilder. Theory: I'm missing the autowire somehow
import org.springframework.context.ApplicationContext
import grails.spring.BeanBuilder

def bb = new BeanBuilder()

bb.beans {
    registrationPersonRegistrationCompositeService(path.to.services.registration.NewRegistrationPersonRegistrationCompositeService) { bean ->
        bean.autowire = true
        registrationRestrictionCompositeService = ref("registrationRestrictionCompositeService")
        registrationPersonTermVerificationService = ref("registrationPersonTermVerificationService")
    }
    classRegistrationController(path.to.services.registration.ClassRegistrationController) { bean ->
        bean.autowire = true
        selfServiceLookupService = ref("selfServiceLookupService")
        registrationPersonRegistrationCompositeService = ref("registrationPersonRegistrationCompositeService")
    }
}
ApplicationContext appContext = bb.createApplicationContext()

其他信息:在PluginGrailsPlugin.groovy中添加了以下行。原始服务仍在处理这些请求

def dependsOn = ['appPersonRegistration': '1.0.20  > *']
List loadAfter = ['appPersonRegistration']

def doWithSpring = {
    registrationPersonCourseRegistrationCompositeService(path.to.new.registration.TccRegistrationPersonCourseRegistrationCompositeService)
}

def doWithApplicationContext = { applicationContext ->
    SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL)
    DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory()
    beanFactory.registerBeanDefinition("registrationPersonCourseRegistrationCompositeService", BeanDefinitionBuilder.rootBeanDefinition(TccRegistrationPersonCourseRegistrationCompositeService.class.getName()).getBeanDefinition())
}

2 个答案:

答案 0 :(得分:1)

我强烈建议您阅读Plugins上的文档部分。我推荐这个的原因是因为插件:

  • 请勿包含或使用resources.groovy
  • 通过doWithSpring提供实施弹簧应用程序的方法

根据文档中的信息,在应用程序上下文中覆盖服务应该没有问题。

您必须使用doWithSpring对应用程序上下文实施更改,这是解决问题的关键。

答案 1 :(得分:0)

在这个实现中,我在服务中有一个实用工具方法,我试图提供覆盖。问题是,Aspect作为代理工作,必须覆盖直接从另一个类调用的方法。在我的classRegistrationController中,我正在调用service processRegistration(),后者又调用applyRules()。仅使用示例的方法名称。由于服务调用了自己的实用程序,因此代理/包装器没有机会绕过对applyRules()的调用。一旦发现这一点,我就会以这种方式重构代码:Controller会像往常一样调用processRegistration。返回后,对服务processLocalRules()进行另一次调用。新方法是一个空占位符,旨在被客户端的自定义逻辑覆盖。 Aspect的插件现在使用resources.groovy。我更喜欢doWithSpring,正如Joshua为此解释的那样:我的意图是让插件无需修改原始的app-config即可工作;另外resource.groovy是一种有效的方法。提升约书亚的答案,因为它确实满足了要求并且更加清洁。谢谢!