budjb / grails-rabbitmq-native

A Grails plugin that provides convenient RabbitMQ functionality using the native Java library for RabbitMQ.
Other
27 stars 38 forks source link

Match consumer by annotation #69

Closed jakon89 closed 9 years ago

jakon89 commented 9 years ago

Hi,

At present when we need to define consumer we have to: 1) register consumer in application.groovy 2) put our consumer to grails-app/rabbit-consumers

First solution is ok, but second is not. Adding new directory (rabbit-consumers) brekas default groovy application structure. I think there shouldn't be anything more than services, models and controllers. For our own application sources, default directory should be src/groovy (as in rabbit-mq native plugin). I rather prefer to put my code anywhere - I don't like when plugni/framework forces me to keep sources here or there and scream 'put in rabbit-consumers !' or ' it should end with Consumer.groovy !' It's my point of view of course.

But there is solution :) We can define our consumers by annotating them. For example:

@Consumer
class IncomingConsumer extends MessageConsumer{
}
@Consumer
class MyAwesomeClass extends MessageConsumer{
}

rest will be like in old version: config, handeMessage.

It's easy to implement, we only have to scan our application packages( for example: 'com.jakon'), but spirng provides org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider and it do all magic. We also need to register this consumers as spring bean in old way:

.each { GrailsClass clazz ->
            "${clazz.propertyName}"(clazz.clazz) { bean ->
                bean.autowire = true
            }
        }
budjb commented 9 years ago

Jakon, I have to disagree with you regarding source code structure. There are many examples of plugins creating their own artefacts that live in defined directories under the grails-app directory. For example, the jaxrs plugin creates the directories grails-app/resources and grails-app/providers, while the Quartz plugin (which the Grails org frequently cites as an example) uses the grails-app/jobs directory.

Creating artefacts with a requirement of a directory under grails-app is a common practice.

jakon89 commented 9 years ago

I didn't know it's commot practice, but is there any obstacle to implement loadinb by annotation?

budjb commented 9 years ago

Additionally, domains, services, controllers, and taglibs are all artefacts that just happen to be bundled with the base Grails distribution. Plugins that define their own artefact types (which implement a lot of magic, just as bundled Grails artefacts do) tend to define the directory requirements in the same way.

There is a very good reason for this practice: auto-reload handling. In a plugin, authors have the ability to "watch" a directory for class changes and act on that change. Services are simply singleton Spring beans (unless explicitly configured with another scope) that have a transaction handling wrapper created around them. When services are reloaded, that wrapper needs to be re-initialized for that class instance. In much the same way, RabbitMQ consumers need to be re-initialized with the RabbitMQ plugin system after they've been changed and reloaded. Having this plugin watch all of src/groovy would be very inefficient, as every file reload that occurs will need to be evaluated.

jakon89 commented 9 years ago

Great explanation :) Thanks for new knowledge for me.