Announcement Announcement Module
Collapse
No announcement yet.
Access application context from code without servlet context Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Access application context from code without servlet context

    Hi

    I'm designing a pretty straight-forward web application. As we'll have approx. 40-50 business classes and around 50 DAO implementation classes, I'd like to provide factory classes for these (DAOFactory). However, as soon as I move the bean creation into the code and away from the Spring context, I loose the references.

    For the DAOFactory, I'd need a reference to the Hibernate sessionFactory. How do I get such a reference? I'm aware of WebApplicationContextUtils.getWebApplicationContex t, but I'd need a servlet context for that method. I don't have a servlet context in my DAOFactory, and I'd rather not couple the DAOFactory with some presentation layer class.

    Currently, I've added an ApplicationContext class which implements BeanFactoryAware, stores the BeanFactory and and has a getter for the BeanFactory. But that's ugly.

    An obvious but - imho - short-sighted solution would be to create a DAOFactory bean in the Spring context XML and pass a reference of the sessionFactory bean. With this, my problem would simply be shifted from

    How does the DAOFactory get the sessionFactory instance

    to

    How does the business layer get the DAOFactory instance

    Nothing solved, really.

    Appreciate any help, links (or even a RTFM if a chapter is provided).
    Simon

  • #2
    The clean approach would be to wire everything inside the spring context. That way you would not need a reference to the ApplicationContext as all beans would be configured completely.

    If that is not feasible (e.g. for porting an existing application) the best approach would IMHO be to store the ApplicationContext in a well known place. As I understand this is the approach you are currently taking. So, if you cannot (yet) wire everything inside the context, that approach would be fitting. As alternative to subclassing ApplicationContext, you could also use a ServletListener (executed after ContextLoaderListener) to retrieve the context and store it in some place accessible by the application.

    Regards,
    Andreas

    Comment


    • #3
      Andreas,

      thank you very much for your feedback. I feel I understand the "Spring way" more or less, but I can't understand how it's possible to write large applications where ALL beans are wired together in the context XML.

      Say I need to load a specific client (based on an field from an order provided in a HTML form) from the database to validate something. How do I retrieve this client object?

      Could you send me a sample application context configuration (or images of the Spring bean graph) for a middle-sized application? (simon dot niederberger at want dot ch). We'll have around 50 business classes, approx. 80 JSP pages.
      I feel the Spring tutorials which just show a "login" or something fall short of showing how to handle larger applications.

      Thanks
      Simon

      Comment


      • #4
        Originally posted by sniederb
        Andreas,

        thank you very much for your feedback. I feel I understand the "Spring way" more or less, but I can't understand how it's possible to write large applications where ALL beans are wired together in the context XML.
        You don't wire all beans up in the application context. In most cases you just need to wire the 'singleton' beans: Managers, Dao, Controllers etc.

        Comment


        • #5
          Originally posted by sniederb
          I feel I understand the "Spring way" more or less, but I can't understand how it's possible to write large applications where ALL beans are wired together in the context XML.
          Think of it like that: Without Spring you wire the objects constituting your application programmatically. Spring allows you to do this declaratively, relieving you from singletons and programmatic factories, thus encouraging the use of interfaces.

          Originally posted by sniederb
          Could you send me a sample application context configuration (or images of the Spring bean graph) for a middle-sized application?
          I have no sample application at hand, but have a look at the "samples" folder of your spring distribution. There are some applications which show how spring-apps can be wired.

          Regards,
          Andreas

          Comment


          • #6
            Alarmnummer

            Then, what is the "best practice" to access the singletons from your code?

            Thanks
            Simon

            Comment


            • #7
              Originally posted by sniederb
              Alarmnummer

              Then, what is the "best practice" to access the singletons from your code?

              Thanks
              Simon
              A good example can tell more than a 1000 words.

              example:
              Code:
              class EmployeeManager{
                 	private EmployeeDao employeeDao;
              
               	public void setEmployeeDao(EmployeeDao employeeDao){
               		this.employeeDao = employeeDao;
               	} 
               	
               	public void fire(long employeeId){
               		Employee employee = employeeDao.load(employeeId);
               		.. some fire logic
               		employeeDao.update(employee);
               	} 
              }
              
              class EmployeeDao{
              	Employee load(long id){....}
              	void update(Employee e){....}
              }
              
              class FireController extends SomeSpringMVCController{
              
              	private EmployeeManager employeeManager;
              	
              	public void setEmployeeManager(EmployeeManager employeeManager){
              		this.employeeManager = employeeManager;
              	}
              
              	ModelAndView onSubmit(HttpRequest request, HttpResponse resp){
              		long employeeId = RequestUtils.getRequiredLong(request,"employeeId");
                              employeeManager.fire(employeeId);
                              return new ModelAndView("success");
              	}
              }
              
              
              <bean id="employeeDao" class="EmployeeDao"/>
              
              <bean id="employeeManager class="EmployeeManager">
              	<property name="employeeDao" ref="employeeDao"/>
              </bean>
              
              <bean id="fireController" class="FireController">
              	<property name="employeeManager" ref="employeeManager"/>
              </bean>
              You can see that nobody needs to access the ApplicationContext directly.
              Last edited by Alarmnummer; Jun 8th, 2006, 04:54 AM.

              Comment


              • #8
                Originally posted by sniederb
                Andreas,

                thank you very much for your feedback. I feel I understand the "Spring way" more or less, but I can't understand how it's possible to write large applications where ALL beans are wired together in the context XML.

                Say I need to load a specific client (based on an field from an order provided in a HTML form) from the database to validate something. How do I retrieve this client object?

                Could you send me a sample application context configuration (or images of the Spring bean graph) for a middle-sized application? (simon dot niederberger at want dot ch). We'll have around 50 business classes, approx. 80 JSP pages.
                I feel the Spring tutorials which just show a "login" or something fall short of showing how to handle larger applications.

                Thanks
                Simon

                I have applications in production with over 100 Spring configured beans (120-150).

                It works well if you split context files into logical units, put each context file in the same package with classes that are wired in it (when it's possible) and use <import/> tags.

                Personally, I find it totally unnecessary to try to "visualize" the whole bean graph and I don't use any kind of special Spring support for my IDE. The whole graph may be huge but you are almost always working with one tiny part of it and the wiring of that tiny part is more often then not trivial. (Injecting datasources into daos, for example - it's a pretty big chunk of xml, even when using abstract parent, but it's totally trivial.)

                Comment


                • #9
                  Access application context from code without servlet context

                  I feel like a moron, but here goes...

                  I have a problem similar to the question asked by sneiderb. I feel I've painted myself into a corner 'over-using' dependency injection.

                  I have two web applications. One is a Tapestry user interface program that creates XML requests and sends them to a remote servlet via Hessian. The remote back-end servlet uses Spring to inject dependencies. Being a Spring novice, I naively used singleton mode for all the spring injected beans. Needless to say, this can wreak havoc in the multi-threaded environment that is a web application/servlet.

                  Now I find that I need several of the back-end beans to be prototypes rather than singletons. The problem is, even if I change some of the beans to prototypes, they are injected into singleton's which are in-turn injected into singletons, etc. So my prototype beans will only ever be created once themselves!

                  My first thought was to extend the DispatcherServelet, grab the WebApplicationContext in the servlet, and create a wrapper around the context that other beans 'down stream' from the servlet can create new instances of beans using the 'getBean("beanId")' interface. This doesn't fee right, either.

                  The general architecture is this: The servlet is hooked to a bean whose interface is exported by a HessianExporter. All the spring beans are wired together in the configuration for this front-end exported bean.
                  The exported class contains a reference to a command factory. Commands are retrieved from the command factory and a service manager is used to obtain references to services that are called by the commands. Unfortunately, the command factory, commands, and services are all configured to be singletons.

                  Hopefully, I'm not a unique moron and you folks have seen this type of quandry before. Any advice on how to 'un-paint' myself from this corner would be appreciated.

                  Comment


                  • #10
                    In general the thread-safety issue is best attacked through simply not using prototypes. If you can rewrite your service beans to this model, you probably should - the "base" Spring idiom is to package your services as a set of thread-safe, fully re-entrant singleton "service" beans which are wired together once only at app startup and then afterwards not touched by the framework. The use of "prototypes" or Spring "non-Singletons" can get you out of a couple of tight corners, but as you find in your design, ultimately not terribly many :P

                    As a more general solution to the non-singleton problem, I do find the "request-scope IoC" idiom in something like RSF extremely helpful, and it's worth noting that Spring itself is moving in this direction with the new support for "scoped" beans coming in Spring 2.0. Obviously I am not entirely impartial here :P

                    But, having an explicitly identified and characterised "scope" in which more ephemerally created beans are wired together is worth its weight in gold.

                    You're right that solutions based on interfering with "irrelevant" dependencies like the DispatcherServlet, and using explicit fetch of beans using "getBean()" is not right. Explicit bean fetches "by name" should occur in at most one point in a Spring application, at some major integration boundary with a foreign technology, and ideally should not occur at all (since this integration code is in general already written for you by Spring for most major technologies).

                    In the general context of the thread, I'm not sure your question actually *is* the same as sneiderb's. In his case the issue simply seems to be making the necessary conceptual shift to working with indeed *all* of your (singleton) beans wired together in the application context. For example he asks, "how do I access the sessionFactory from my DAOFactories", to which the answer is simply "inject it there". And if you find yourself with a pattern where you have "too many" (i.e. an "auto-definition" requirement) products to be configured into the Spring context, simply inject the dependency one higher up. I.e. at the point you want to leave Spring behind, terminate the managed bean tree in a "DAOFactoryFactory" which has the sessionFactory injected into it, which it supplies in the usual way (via constructor arguments, or properties), in code, to its products. This solution is not "short-sighted", you merely see as far as you need to :P
                    Last edited by Bosmon; Jul 2nd, 2006, 07:29 PM.

                    Comment


                    • #11
                      Access application context from code without servlet context

                      Bosman,

                      Thanks for the quick reply.

                      I endeavored to wire everything and I did use nothing but singleton instances, so I guess I've got the spirit but I think I need to rethink the design.

                      Perhaps I've attempted to inject too much. Should I be injecting only those classes that can be singletons? Is that the gist of your suggestion that I redesign the services to be singletons?

                      The nature of several of our services is that they are very stateful. In addition to database queries, they often must calculate statistics on the result set and then trim the results based on those statistics. Obviously, this requires some stateful accumulator objects that can't be singletons.

                      I guess the question is, what should be spring injected and what shouldn't be spring injected? Should I look to injecting more factories rather than single instances of beans?

                      Comment


                      • #12
                        In general, "vanilla Spring" is most suited to a design where those things which are injected are singletons. You should be able to rework your design such that either it consists of these entirely, or that the "stateful" beans are only one or perhaps 2 layers deep. Yes, as you mention, a key strategy is to remodel services as "factories" or even "factories of factories" in order to effect this transformation - Spring is set up to make this kind of thing quite idiomatic. If the resulting design is still too complex/messy, I do invite you to consider the request-scope injection approach :P

                        Comment


                        • #13
                          I've gotten this far: I've added a service/manager layer on top of my DAO classes, the DAO classes as well as the service beans are singletons. Essentially, the service layer represents business fuctions by packaging a sequence of DAO requests while taking the DTO bean to run the DAO methods on as argument.

                          I then have defined "business" beans injecting a service bean reference, but these beans are prototypes. My UI components get an instane of these business beans. This seems to work well, as the prototyp beans are never injected into singletons.

                          However, one thing I wonder about a comment from Bosman is:

                          I.e. at the point you want to leave Spring behind
                          How do my non-Spring beans access Spring beans if not by using the getBean() method? It is my understanding that the best way to go is to wire EVERYTHING together and not have a non-Spring part of code.

                          Cheers and thanks all for their comments and help
                          Simon

                          Comment


                          • #14
                            Sneider - it looks like you have pretty much the correct standard pattern. Here is a more detailed explanation of the "non-Spring beans gaining access to Spring" issues:

                            Any access to Spring beans must ("should") be done via Spring, i.e. via dependency injection. That is, if you have beans in your code which require Spring dependencies, but are created via a non-Spring creational pattern, the Spring dependencies must be injected into the creator/factory for these non-Spring beans, which it delivers to them via normal routes (e.g. via manually calling constructor arguments or calling setters).

                            E.g.
                            Code:
                            public class NonSpringFactory {
                              private LeafDependency leafdep;
                              public void setLeafDependency(LeafDependency leafdep) {
                                 this.leafdep = leafdep;
                                  }
                              public NonSpringBean createNonSpringBean() {
                                 NonSpringBean nonspring = new NonSpringBean(leafdep);
                                 return nonspring;
                                 }
                              }
                            So, NonSpringFactory is configured into your context as a normal Spring bean - LeafDependency is delivered to it via Spring. If for one reason or another (generally most likely as a result of lifetime issues) its product cannot be Spring-configured, and it has LeafDependency as a dependency within Spring, you must use Spring to deliver it to the "closest available point", i.e the nearest Spring-configured bean which in this case is NonSpringFactory. So "LeafDependency" is a "pass-through" dependency which is not a dependency of the Factory, but of its product. At no point should you ever call getBean().

                            In more complex cases, this idea is the same, only there may be more than one layer of non-Spring creation between source and target, and it becomes increasingly onerous to ferry the dependencies. In Spring therefore the pressure is to de-state-ify your design by working as far as possible with stateless beans which can all be placed in the context, and allowing you to deliver the dependencies precisely to the target.

                            Until Spring 2.0, the only support for non-singleton beans was as prototypes, which was unsatisfactory since these could not participate in any further injection. Note that now in Spring 2.0 there is support for arbitrary bean scopes, which will help in a lot of cases, although I suspect the 2.0 request scope will be too slow to be suitable for heavyweight work with the request. I will do further tests once we have a full release.
                            Last edited by Bosmon; Jul 5th, 2006, 09:01 AM.

                            Comment


                            • #15
                              Bosmon - thank you very much for your feedback. One question remains: If I have code wanting to use this NonSpringFactory, how does it get a reference to the factory? By injection? Or by standard Singleton-accessors (getInstance() et al.), assuming Spring has already initialized the bean (possible with lazy-init=false)?

                              In the former case, I'd have Spring beans passing non-Spring beans between them. So there's no non-Spring layer, but merely non-Spring command objects.

                              Generally, I feel Spring can sometimes replace the need for a factory. I started writing a DAO factory and injected the factory into each service bean, but dropped that approach in favor of passing concrete DAO beans into the corresponding service bean. Thus the factory code of deciding which bean to (create and) return was replaced by Spring context configuration.

                              To me, the Spring context definition takes away the direct benefit of a factory. Both approaches "return" a bean instance, with the factory pattern you have to ask for it, with Spring you just get it.

                              Cheers
                              Simon

                              Comment

                              Working...
                              X