Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issues with proxies and enhanced classes in Spring context #75

Open
arne-vandamme opened this issue Jul 5, 2014 · 4 comments
Open

Issues with proxies and enhanced classes in Spring context #75

arne-vandamme opened this issue Jul 5, 2014 · 4 comments

Comments

@arne-vandamme
Copy link
Contributor

We are using Mbassador extensively as the event bus in a Spring 4 environment with multiple application contexts etc.

I have run into some oddities when using the message bus with listeners that are either aop proxies or cglib enhanced:

  • handlers do not register (subscribe) because the proxy does not have the method annotations (probably in case of an AOP proxy, not cglib)
  • filters get a reference to a proxied or enhanced method and don't find the annotations on the originally declared method

The behavior i'm looking for a in Spring context would be:

  • when subscribing a listener, the target class (not the proxy) is used to determine the handlers
  • filters are run against with the target method metadata
  • execution is done on the outer proxied method

However, using this approach would (i think) remove the ability to do the reverse: using AOP to decorate regular methods with Handler annotations and subscribe them to the event bus. I think the case for the latter is perhaps less common.

Anybody else has experience with this and built solutions around it? Any thoughts on how and where this whould be fixed from a generic mbassador point of view?

I have to checkout mbassador-spring myself, will try to build some test cases we can build on to reproduce/resolve.

@bennidi
Copy link
Owner

bennidi commented Jul 5, 2014

I think that using AOP to decorate regular methods with handler annotations seems a very obscure technique. I think a handler should be annotated directly to explicitly state that it is meant to participate in messaging. It is not a pattern that I would aim to support.

Regarding your problems with proxies: We did run into similar issues when using mbassador in a Spring managed web application. We used mbassador to communicate between differently scoped beans. Bean scoped were implemented as scoped proxies created by cglib.

When you use a Bean PostProcessor to subscribe beans to the bus, then for Session/Request scoped beans there will be an invocation of that post processor for each concrete instance as well as once for the managing proxy. In our case we subscribed the scoped proxy and ignored the beans because we wanted the proxy to take care of delivering the message to the correct session bean (depending on the Thread context). Otherwise we would have had to manage some form of identification mechanism ourselves. But this introduced another problem when session beans were listening to messages that could be sent by a job/asynchronous task (which runs outside the Thread context).

One also needs to be aware that transaction management is handled by proxies as well, so when you want to have your message handlers to participate in transactions (which is a common case). To me it seems, that in order to integrate mbassador well with different Spring scenarios you need some form of rule specification mechanism that allows to match a newly created spring bean and determine whether or not to subscribe it and if the instance itself should be subscribed or a nested object. You might have rules like:
AnnotatedWith(@Session) -> ProxyOnly, AnnotatedWith(@request) AND AnnotatedWith(@IgnoreProxy) -> Not the proxy but the instances.

I think it will be not very trivial to determine what kind of object you are actually looking at. We used a very ugly hack to check for CGLIB (look for the substring 'cglib' in the class name...urghhs). There must be cleaner ways and with time it may be possible to establish a set of meaningful and composable rules.

BTW: cglib proxies don't loose annotations as long as they are @Inherited which all of mbassadors annotations are. So I suspect that lost annotation relate to another AOP implementation technique.

@arne-vandamme
Copy link
Contributor Author

Hm, i see the situation with scoped beans. However, it seems to me that the purpose of the proxies/enhanced beans would be that you use them transparently. So - in almost all cases - subscribe/unsubscribe and publishing should behave as expected, because i don't know (or need to) that i'm dealing with a proxy.

So then it should always be the proxy that is executed and filters should not be influenced by them.

The problem you described seems a bit odd to me. What would be the relevant use case for Session beans to listen to non-session related messages? Would it not be up to the application design to make sure that those only listen to messages they can handle?

An annotation to force the instance to be used in all circumstances could be useful and perhaps not too difficult to achieve. I'll have to think this through still :-)

BTW: Spring has some good utility classes to detect and work with proxies, I'm creating a new branch on my mbassador-spring fork, trying out some stuff there. There are indeed several proxy mechanism, i'll try to cover most of them.

@cyberoblivion
Copy link

@bennidi I am interested in your hack to check for CGLIB. I wrote a simple BeanPostProcessor for auto registration but it doesn't seem to ever get passed the CGLIB enhanced class. Maybe this is a change in spring behavior? I'm using spring 5

@bennidi
Copy link
Owner

bennidi commented Nov 8, 2017

The BeanPostProcessor I wrote was for Spring 3, I think. I assume that a lot of behaviour changed within the past releases (of Spring and CGLIB). I found my way to the right class with a break point in the main method of the BeanPostProcessor and inspected the instances which were handed to it. Took me a while because I did not create a sample app but used the complex production app. I suggest you make a minimal example and debug your way through then. Have fun! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants