Я знаю, что могу заменить bean-компонент Spring, предоставляемый Grails, просто определив свой собственный bean-компонент с тем же именем. Например, если я хочу заменить bean-компонент messageSource, предоставленный Grails

class MyMessageSource implements MessageSource {
    // methods omitted
}

Затем добавьте следующее в resources.groovy

messageSource(MyMessageSource)

Однако предположим, что я хочу MyMessageSource украсить реализацию этого bean-компонента, предоставляемого Grails.

class MyMessageSource implements MessageSource {

    // this field should be set to the MessageSource impl provided by Grails
    MessageSource messageSource
}

Я не могу понять, как подключить это к resources.groovy. Очевидно, я не могу этого сделать:

messageSource(MyMessageSource) {
    messageSource = ref('messageSource')
}

Потому что похоже, что я определяю bean-компонент, который зависит от самого себя. Конечно, я мог бы дать своему bean-компоненту другое имя, например

myMessageSource(MyMessageSource) {
    messageSource = ref('messageSource')
}

Но тогда любой класс вне моего контроля (например, класс подключаемого модуля), который объявляет зависимость от messageSource, будет установлен на bean-компонент, предоставляемый Grails, а не на мой декоратор.

4
Dónal 8 Май 2014 в 19:19

2 ответа

Лучший ответ

В приложении (не в плагине) что-то в этом роде должно работать ...

Новый источник сообщения:

// src/groovy/com/demo/MyMessageSource.groovy
package com.demo

import org.springframework.context.MessageSource
import org.springframework.context.MessageSourceResolvable
import org.springframework.context.NoSuchMessageException

class MyMessageSource implements MessageSource {
    MessageSource theRealMessageSource

    String getMessage(String code, Object[] args, String defaultMessage, Locale locale) {
        theRealMessageSource.getMessage code, args, defaultMessage, locale
    }

    String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException {
        theRealMessageSource.getMessage code, args, locale
    }

    String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException {
        theRealMessageSource.getMessage resolvable, locale
    }
}

Постпроцессор:

// src/groovy/com/demo/MyPostProcessor.groovy
package com.demo

import org.springframework.beans.factory.config.BeanFactoryPostProcessor
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory
import org.springframework.beans.BeansException

class MyPostProcessor implements BeanFactoryPostProcessor {

    @Override
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // error handling ommitted for brevity here...

        def realMessageSource = beanFactory.getBean('messageSource')
        def newMessageSource = new MyMessageSource()
        newMessageSource.theRealMessageSource = realMessageSource

        beanFactory.removeBeanDefinition 'messageSource'
        beanFactory.registerSingleton 'messageSource', newMessageSource
    }
}

Зарегистрируйте постпроцессор:

// grails-app/conf/spring/resources.groovy
beans = {
    myMessageSourcePostProcessor com.demo.MyPostProcessor
}
7
Jeff Scott Brown 9 Май 2014 в 09:27

После инициализации контекста вы можете получить bean-компонент messageSource, создать экземпляр вашего bean-компонента, который делегирует bean-компонент messageSource, а затем зарегистрировать ваш bean-компонент в контексте под именем «messageSource», чтобы, когда произойдет DI, ваш bean-компонент будет использоваться. В плагине вы должны иметь возможность сделать это в doWithApplicationContext (а не в doWithSpring).

1
Jeff Scott Brown 9 Май 2014 в 04:10