2

I spent few days fixing bugs in my Spring project. For really long time, my main problems in error log were:

Bean already exists

I have got two files:

WEB-INF/myproject-servlet.xml
WEB-INF/web.xml

in first one, I can put following input (let's assume I have got an application to manage animals in zoo):

<context:component-scan base-package="com.my.package.animals" />

with that (as well as I understand) we are enabling Spring beans auto-discovery. So now, when we run our application, Spring will take all classes from this package, later it will go through all config files in resources directory and will inititliaze all beans (placed in config files, which are associated with a given package).

The second one, web.xml includes lines like this

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/myproject-servlet.xml</param-value>
</context-param>

I can also put path to my config files, for instance:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:animals-config.xml</param-value>
</context-param>

So now, I have 'auto-detecting' in myproject-servlet.xml and I have got context-param in web.xml for the same objects.

My question is, is it possible, that errors "Bean already exists" are coming from this? I am almost sure that yes, I checked all beans ids and there is no duplicates.

So I have another question. What is a good approach of doing that? When I create new config file, where I should inform my application about that? In myproject-servlet.xml or web.xml. I really need to clean up my application and I will start with that.

I checked some examples and people rather do not put more than one <context-param> in web.xml file Simple example

Thank you in advance


Ok, I am really close to solve my problem.

Let's assume I have got two packages:

com.my.pckg.a
com.my.pckg.b

with classes

com.my.pckg.a.ClassA
com.my.pckg.b.ClassB

I added in myproject-servlet.xml following line:

<context:component-scan base-package="com.my.pckg.a" />

I have got a config file myconfig.xml and inside I have got beans based on classes ClassA and ClassB.

Let's say we have got beans with ids as follows:

ClassA: ida1, ida2
ClassB: idb1, idb2

So, I am running my jetty server and the question is:

Which beans will be initialized? I declared only package com.my.pckg.a, so from myconfig.xml, spring should load only ida1 and ida2 but this file includes also beans for another class.

So finally... ?


Finally, I suppose I find a problem. In web.xml file I have got a line:

<context:component-scan base-package="com.dirty.pckg" />

in this package I have got a class DirtyClass with @Controller annotation. One of the fields of this class is:

private static ApplicationContext context = new ClassPathXmlApplicationContext("dirty-config.xml");

So, when my application is getting up, Spring takes DirtyClass (because it has @) and maps it. Because os static modifier of context it triggers reading dirty-config.xml. That's way I could not understand why my code behaves in strange way.

Community
  • 1
  • 1
ruhungry
  • 4,506
  • 20
  • 54
  • 98
  • 1
    what do you have in your animals-config.xml ? If your have the same beans definition than in myproject-servlet.xml and declare both as contextConfigLocation, it can be an issue. – Thomas Apr 02 '14 at 13:26
  • In fact, I have changed a lot of things and now, this case does not exist and there is no error. Finally, I would like to focus on my second question. What should be (considering the **"good taste of Spring")** in `myproject-servlet.xml` and what in `web.xml`? – ruhungry Apr 02 '14 at 13:33

2 Answers2

1

The web.xml file is the configuration of your web application. It is not related to Spring.

The contextConfigLocation context-param is the one spring listener use to search for Spring configuration files. It is spring related.

You can have multiple spring configuration files that you register in your web.xml but these files must not define the same bean (bean id must be different). You can also have only one spring configuration file that will it self include other configuration files as described here : http://www.mkyong.com/spring/load-multiple-spring-bean-configuration-file/


Answer to the other question :

When you added the component scan, you ask spring to scan the package com.my.pckg.a for annotation like @Service, @Component, ... The component scan is not a filter for the rest of the configuration it is a configuration itself. So the fact that you added component scan, will not change the behaviour of myconfig.xml. Both ida1, ida2 and idb1, idb2 will be instanciated.

I don't really get what you are trying to accomplished with your configuration files. Maybe if you explain your needs, we could help you set up the right config for you.

Thomas
  • 1,410
  • 10
  • 24
0

web.xml is configuration file. It has classes(like listeners, filters,filter-mapping, servlet,servlet-mapping), resources and configuration(like context param, diplayname, error-page, session-config) of the application and how the web server uses them to handle web requests. When the web server receives a request for the application, it uses web.xml to map the URL of the request to the code that is supposed to handle the request.

Coming to what should be in web.xml and what should be in myproject-servlet.xml:
1)In Spring, ApplicationContext can be hierarchical. One ApplicationContext can have multiple child ApplicationContexts and can only have one parent. Beans in child ApplicationContext can access the beans in parent.

2)DispatcherServlet dispatches requests to handlers(controllers), with configurable handler mappings, view resolution configuration(what view template you use for the application for example jsp).

Keeping the two points in mind, our web.xml should be like:

    <!--Root web application context(Parent context) - beans for service or persistence layer should be in this -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:service-layer-beans.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <servlet>
        <!--DispatcherServlet loads its configuration into its own context(chile context) and refers Root web application context as a parent, so it have access to beans in parent context and can override it but not vice versa.-->
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/myproject-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>*.htm</url-pattern>
    </servlet-mapping>
Prasad
  • 3,785
  • 2
  • 14
  • 23