Announcement Announcement Module
No announcement yet.
lazy-init problem Page Title Module
Move Remove Collapse
This topic is closed
Conversation Detail Module
  • Filter
  • Time
  • Show
Clear All
new posts

  • lazy-init problem

    I set lazy-init as the default for beans in my core applicationContext. This works when I run the app in stand-alone mode, but when I run it as a webapp I find that Spring is eagerly instantiating beans and injecting colloborators into them.

    A quick look in the debuger shows that FilterToBeanProxy is causing the instantiations. FilterToBeanProxy is, of course, declared in web.xml, and is thus not invoked when I run the app as a stand-alone.

    So how can I prevent FilterToBeanProxy from eagerly instantiating beans from my core applicationContext? By the way, the app is using version acegi version 0.82. I have a small preference not to upgrade immediately, but will be glad to do so if that's the only way to solve this problem.

  • #2
    Why is this a problem? Is FilterToBeanProxy eagerly initializing something that is expensive to initialize? Generally I use (and see other projects using) the default eager initialization without a problem.


    • #3

      Yes, SessionFactories and DataSources are being initialized, and these are expensive. In this particular case, the expense is not so much in startup time (that's about 5 seconds or so) but in developer productivity. All (two) of our developers sometimes work off site, and very often work on features that don't need to hit the database, but that are instead using mock DAOs. Running with the FilterChainProxy means that we still need to have a database running locally because the SessionFactories and DataSources are being eagerly initialized.

      In fact, the cost in development time is not restricted only to the inital effort of installing Oracle locally and importing a database dump. Even though we're running with mock DAOs, we frequently need to re-import a new version of the database dump so that the newly revised SessionFactory doesn't blow up because it doesn't find the expected changes in the newly revised database. Either that, or we just remove the filterChainProxy declaration from web-xml. But that's not always practical.

      I'd also like, in the near future, to use lazy initialization to declare several data sources, and only use those that are resolved by a PropertyPlaceholderConfigurer. In short, I think lazy initialization is a very valuable feature.


      • #4
        FilterToBeanProxy and the associated FilterChainProxy both use the Service Locator pattern to obtain (by name) only the beans they require. Therefore I'm not sure why it would be causing an eager initialization of all of your beans. Are you sure it's not another bean responsible?


        • #5

          I remember debugging the problem and, at that time, being convinced that FilterToBeanProxy was the cause. But I may have missed something. I didn't do much more than note that lazy-init works when I deploy in standalone mode, doesn't work when deploying as a webapp, and that the debugger finds bean initialization initiated by FilterToBeanProxy.

          It might be that I could refactor so that the beans that FilterToBeanProxy requires don't cause so much overhead. But if it happens that 1) some of those beans need datasources, and 2) FilterToBeanProxy locates the beans it needs eagerly, then refactoring won't help much.

          I guess I should ask, does FilterToBeanProxy locate the beans it needs eagerly? And if so, is there a way to configure it so that it acquires those beans lazily.


          • #6
            You could look into the FilterToBeanProxy servlet-container-managed parameter, but I don't think you'll achieve much as the initialization will be deferred, at best, until your first web request comes in when all the filters will need to fire.


            • #7
              too eager

              Filter Chain Proxy looks like it acquires more than just the beans it needs. Here's why I say this. I've been working on a requirement that I think many apps have-- enabling the use of different DataSources in tomcat and in weblogic. In particular, my client wants to access a jndi datasouce in weblogic.

              But when running in tomcat, I get this error:

              2006-02-08 15:12:12 StandardContext[/eductionWebApp]Exception starting filter Acegi Filter Chain Proxy
              org.springframework.beans.factory.BeanCreationExce ption: Error creating bean with name 'weblogicDataSource' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Initialization of bean failed; nested exception is javax.naming.NameNotFoundException: Name weblogicDataSource is not bound in this Context
              javax.naming.NameNotFoundException: Name weblogicDataSource is not bound in this Context
              at org.apache.naming.NamingContext.lookup(NamingConte
              at org.apache.naming.NamingContext.lookup(NamingConte
              at org.apache.naming.SelectorContext.lookup(SelectorC

              If Filter Chain Proxy was just loading the beans it needed, it wouldn't access the weblogicDataSource. That's because when I build for tomcat there are absolutely no beans that reference the weblogic data source.

              I've been able to work around this problem by having ant write the whole weblogicDataSource configuration only when deploying in weblogic. That makes for the longest ant property I've ever seen, and I'd much rather rely on Spring's lazy-init feature.

              I hope you give consideration to the possibility that acegi breaks lazy-init, and that this might be a bug.


              • #8
                You sure your UserDetailsService doesn't access the DataSource?


                • #9
                  I too just ran into this issue. Basically I have a few FactoryBean beans declared with lazy-int="true". My web app start up fine and the lazy beans aren't instantiated as expected. The problem arises when I first access a page and Acegi's servlet filter is hit.

                  The problem seems to be that FilterToBeanProxy has the following method invocation in its doInit() method.

                  Map beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(ctx ,
                  targetClass, true, true);

                  This method causes all the lazy beans to be instantiated.

                  Can you pass "false" for the last two arguments when calling BeanFactoryUtils.beansOfTypeIncludingAncestors(ctx ,
                  targetClass, false, false);

                  * @param includePrototypes whether to include prototype beans too or just singletons
                  * (also applies to FactoryBeans)
                  * @param includeFactoryBeans whether to include FactoryBeans too or just normal beans

                  In my case, the lazy factory bean is a bean that talks to a remote server using Lingo Spring Remoting.

                  <bean id="myService" class="org.logicblaze.lingo.jms.JmsProxyFactoryBea n" lazy-init="true">
                  <property name="serviceInterface" value="com.test.MyService"/>
                  <property name="connectionFactory" ref="jmsFactory"/>
                  <property name="destination" ref="optimizerDestination"/>
                  <!-- enable async one ways on the client -->
                  <property name="remoteInvocationFactory" ref="invocationFactory"/>

                  I need this to be lazily loaded as the server side of the client may not be up until a certain point in the workflow of my app. Below is the entire stack trace .


                  <Mar 31, 2006 3:59:00 PM EST> <Notice> <WebLogicServer> <BEA-000360> <Server started in RUNNING mode>
                  <Mar 31, 2006 3:59:09 PM EST> <Error> <HTTP> <BEA-101020> <[ServletContext(id=11629507,name=tbr,context-path=/tbr)] Servlet failed with Exception
                  org.springframework.beans.factory.BeanCreationExce ption: Error creating bean with name 'myService' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Initialization of bean failed;
                  nested exception is javax.jms.JMSException: Initialization of TcpTransportChannel failed. URI was: tcp://localhost:61616 Reason:
                  javax.jms.JMSException: Initialization of TcpTransportChannel failed.
                  URI was: tcp://localhost:61616 Reason: Connection refused: connect
                  at org.activemq.util.JMSExceptionHelper.newJMSExcepti on(
                  at org.activemq.transport.tcp.TcpTransportChannel.<in it>(
                  at org.activemq.transport.tcp.TcpTransportChannelFact ory.create(
                  at org.activemq.ActiveMQConnectionFactory.createTrans portChannel(
                  at org.activemq.ActiveMQConnectionFactory.createConne ction(
                  at org.activemq.ActiveMQConnectionFactory.createConne ction(
                  at org.logicblaze.lingo.jms.impl.DefaultJmsProducer.n ewInstance(
                  at org.logicblaze.lingo.jms.impl.MultiplexingRequesto r.newInstance(
                  at org.logicblaze.lingo.jms.JmsClientInterceptor.crea teRequestor(
                  at org.logicblaze.lingo.jms.JmsClientInterceptor.afte rPropertiesSet(
                  at org.logicblaze.lingo.jms.JmsProxyFactoryBean.after PropertiesSet(
                  at AutowireCapableBeanFactory.invokeInitMethods(Abstr
                  at AutowireCapableBeanFactory.createBean(AbstractAuto
                  at AutowireCapableBeanFactory.createBean(AbstractAuto
                  at BeanFactory.getBean(
                  at BeanFactory.getBean(
                  at BeanFactory.getType(
                  at istableBeanFactory.isBeanTypeMatch(DefaultListable
                  at istableBeanFactory.getBeanNamesForType(DefaultList
                  at istableBeanFactory.getBeansOfType(DefaultListableB
                  at ationContext.getBeansOfType(AbstractApplicationCon
                  at org.springframework.beans.factory.BeanFactoryUtils .beansOfTypeIncludingAncestors(BeanFactoryUtils.ja va:224)
                  at net.sf.acegisecurity.util.FilterToBeanProxy.doInit (
                  at net.sf.acegisecurity.util.FilterToBeanProxy.doFilt er(
                  at weblogic.servlet.internal.FilterChainImpl.doFilter (
                  at org.ajaxanywhere.AAFilter.doFilter( 3)
                  at weblogic.servlet.internal.FilterChainImpl.doFilter (
                  at weblogic.servlet.internal.WebAppServletContext$Ser :6356)
                  at t.doAs(
                  at weblogic.servlet.internal.WebAppServletContext.inv okeServlet(
                  at weblogic.servlet.internal.ServletRequestImpl.execu te(
                  at weblogic.kernel.ExecuteThread.execute(ExecuteThrea
                  at va:170)
                  Caused by: Connection refused: connect
                  at Method)
                  at .java:305)
                  at ava:158)
                  at org.activemq.transport.tcp.TcpTransportChannel.cre ateSocket(
                  at org.activemq.transport.tcp.TcpTransportChannel.<in it>(
                  ... 32 more
                  <Mar 31, 2006 4:03:51 PM EST> <Error> <HTTP> <BEA-101020> <[ServletContext(id=11629507,name=tbr,context-path=/tbr)] Servlet failed


                  • #10
                    Replying to Ben's question: "You sure your UserDetailsService doesn't access the DataSource?"

                    I was running with two data sources, one for tomcat, one for weblogic. When deploying for tomcat the build process ensures that the applicationContext has no references to the weblogic dataSource. But the weblogic dataSource was still loaded, and the stack trace pointed to FilterToBeanProxy.

                    I don't run with two datasourcs anymore (I use an inelegant workaround that I mentioned in a previous post to this thread.) But today I was quickly able to reproduce the problem and to verify that there are indeed no references to the weblogic dataSource.