Announcement Announcement Module
Collapse
No announcement yet.
HttpSession trick: this is clever, but is it a good idea? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • HttpSession trick: this is clever, but is it a good idea?

    Like the title implies, a request for opinions on what I think is a neat trick.

    I want to use Spring to manage per-HttpSession objects in my app. For various reasons, I don't want to use the FormController approach (these session objects can't be targets of request binding, for instance.)

    i.e., I want my context description to look a little like this (and definitely NO MORE verbose: )

    Code:
      <bean id="doesLotsaStuff">
         <property name="doStuffTo">
            <ref bean="justamap"/>
         </property>
      </bean>
    
      <bean id="justamap" class="java.util.HashMap" singleton="false"/>
    
      <bean id="bindToSession" class="MyHttpSessionAutoProxyCreator">
        <property name="targetNames">
          <list>
            <value>justamap</value>
          </list>
        </property>
      </bean>
    ...and doesLotsaStuff should just magically use the correct justamap for the session currently being handled, without being any the wiser. JSPs, etc., could refer to justamap and get the correct object too.

    I have actually made this work! It's pretty slick. However, some of my hacking under the covers makes me nervous:

    -- I have to hook into the context startup in lotsa places: my class is a BeanPostProcessor, BeanFactoryPostProcessor, ApplicationListener, BeanNameAware, and has an inner class that's a FactoryBean and TargetSource. Whew.

    -- I detect the currently-being-handled request by intercepting calls to the HandlerMapping (request starts) and getting RequestHandledEvents (request ends) and use a ThreadLocal. good/bad?

    -- 'justamap' gets forcibly replaced by an AOP proxy, instead of the proxy being fetched from a FactoryBean. Bad form: nobody else can get at the unproxied template anymore. I'd rather use a FactoryBean, but see below.

    I ran into what may be a bug: say a FactoryBean also implements BeanPostProcessor. When an ApplicationContext is detecting BeanPostProcessors, it finds the factory itself but tries to use the factory's product as a BeanPostProcessor, which it likely is not. Shouldn't the context both detect and fetch BeanPostProcessors in the same way?

  • #2
    Re: HttpSession trick: this is clever, but is it a good idea

    Originally posted by rgeorge
    -- I have to hook into the context startup in lotsa places: my class is a BeanPostProcessor, BeanFactoryPostProcessor, ApplicationListener, BeanNameAware, and has an inner class that's a FactoryBean and TargetSource. Whew.
    Well, I suppose you need all of those, however, I'm wondering why you need the post processor to be a FactoryBean. But that aside, what's wrong with implementing a couple of interfaces? Have you ever programmed some Swing ;-).

    Originally posted by rgeorge
    -- I detect the currently-being-handled request by intercepting calls to the HandlerMapping (request starts) and getting RequestHandledEvents (request ends) and use a ThreadLocal. good/bad?
    Good. basically the only way to do it, except for a filter. I'm wondering whether or not you could implement the whole mechanism in your post processor. Look up all handlermappings and programmatically add the interceptor to the mapping. This way you end up defining only one bean, the SessionProxyCreatorConfigurer thingy, both creating proxies and adding the interceptor.

    Originally posted by rgeorge
    -- 'justamap' gets forcibly replaced by an AOP proxy, instead of the proxy being fetched from a FactoryBean. Bad form: nobody else can get at the unproxied template anymore. I'd rather use a FactoryBean, but see below.
    FactoryBeans have the ability to be referenced with an ampersand prefixed to the bean name. You'll get the FactoryBean instead of the object it creates. I think this works for autoproxycreators. I'll post a question in the AOP forum so Rod (or somebody else can have a look at this).

    I ran into what may be a bug: say a FactoryBean also implements BeanPostProcessor. When an ApplicationContext is detecting BeanPostProcessors, it finds the factory itself but tries to use the factory's product as a BeanPostProcessor, which it likely is not. Shouldn't the context both detect and fetch BeanPostProcessors in the same way?
    I'm curious as to why you need the postprocessor to be a factorybean as well. I usually see postprocessor only postprocessing beanfactories, not delivering objects yourself. Could you elaborate on why you did this?

    Comment


    • #3
      http://forum.springframework.org/showthread.php?t=10371
      Last edited by robyn; May 14th, 2006, 10:42 AM.

      Comment


      • #4
        I'm wondering whether or not you could implement the whole mechanism in your post processor. Look up all handlermappings and programmatically add the interceptor to the mapping. This way you end up defining only one bean, the SessionProxyCreatorConfigurer thingy, both creating proxies and adding the interceptor.
        Bingo. Precisely what I was after. A single drop-in bean that would bless a list of templates with per-session behavior, that clients (e.g. singleton Handler classes) could just use directly and be none the wiser.

        As for why to use a FactoryBean... well, the answer to this sort of question is usually "designer is confused." I also tried being a BeanPostProcessor and intercepting requests for the templates that way, but I realized too many throwaways would get generated.

        Here's how I finally did it: in setApplicationContext, I move the target template BeanDefinitions to mangled names, and replace them with my own fresh BeanDefinitions that serve up the proxies. The only thing I do as a BeanPostProcessor now is locate and wrap the HandlerMappings.

        I may abandon this particular approach anyway, since I've discovered that some beans don't like being instantiated through a BeanDefinition that's been moved like that. Plain Maps and such behave ok, but (in this case) an IMAP Store retrieved from a javamail Session does not.

        In any case, the "bug" code, in case anyone else is strange enough to do what I tried:
        Code:
        	String&#91;&#93; beanNames = getBeanDefinitionNames&#40;BeanPostProcessor.class&#41;;
        	...
               for &#40;int i = 0; i < beanNames.length; i++&#41;
        		beanProcessors.add&#40;getBean&#40;beanNames&#91;i&#93;&#41;&#41;;
        this is in AbstractApplicationContext, around line 319; it threw a ClassCastException when I configured an object that was both a FactoryBean and a BeanPostProcessor. I imagine similar behavior would happen for other such strange mixes.

        Shouldn't getBeanDefinitionNames either ignore beanFactories, or interrogate them for their manufactured type, or prepend '&' when the beanFactory itself is of the type being searched for? Alternatively, should ApplicationContext autodetection code like that be aware that it might get fed FactoryBeans, and accommodate?

        Comment


        • #5
          Hi,

          didn't have the time to get into this any further yet... Hope to find some time this week.

          Comment


          • #6
            Very interesting stuff! What has kept me from Spring is that the apps I work on have tons of "session-singletons" and very few application-level objects. Spring concentrates much more heavily on application-level and request-level than it does session-level. Glad to see someone is blazing the way.

            Comment


            • #7
              Originally posted by rgeorge
              Shouldn't getBeanDefinitionNames either ignore beanFactories, or interrogate them for their manufactured type, or prepend '&' when the beanFactory itself is of the type being searched for? Alternatively, should ApplicationContext autodetection code like that be aware that it might get fed FactoryBeans, and accommodate?
              AbstractApplicationContext should use getBeansOfType here rather than getBeanDefinitionNames. The former is aware of objects created FactoryBeans, the latter is only aware of the FactoryBeans themselves (by definition). I've just fixed this: AbstractApplicationContext will properly ignore FactoryBeans now.

              Juergen

              Comment

              Working...
              X