Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to think when wiring beans
    primarykey
    data
    text
    <p>I'm trying to get a better hang of the way Spring handles dependency injection, but I have come to face a (at least for me) quite weird situation.</p> <p>I have a layered application which can be visually described something like this: web - business - domainmodel - dal ... every layer in separate modules.</p> <p>I'm using annotations to inject whats needed in my classes, and to make things more complicated I'm using cucumber in the business layer, which means I need to explicitly inject a test-bean when testing and the real bean when not testing.</p> <p>Everything compiles just fine, and even runs and injects (<code>@Inject</code>) everything just fine... <em>until</em> I add this line to the context.xml in the web layer:</p> <pre><code>&lt;context:component-scan base-package="com.foo.bar.baz.bleep.bll" /&gt; </code></pre> <p>... this is where my problems start. When that line is added, compile completes successfully, but when I run it in Tomcat I get this error:</p> <pre><code>Context initialization failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sampleAppServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.foo.bar.baz.bleep.dal.SampleAppDao com.foo.bar.baz.bleep.bll.SampleAppServiceImpl.sampleAppDao; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.foo.bar.baz.bleep.dal.SampleAppDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@javax.inject.Inject()} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:287) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1106) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464) at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:385) at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:284) at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:111) at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4797) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5291) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) at java.util.concurrent.FutureTask.run(FutureTask.java:138) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918) at java.lang.Thread.run(Thread.java:662) </code></pre> <p>All of a sudden the dao is missing from the container (?).</p> <p>I want to use the business services from the business layer in the web layer, but as soon as I'm trying to add the scan on the bll to the web layer, the business layer breaks. What gives?</p> <p>my <code>web-context.xml</code> in the web layer</p> <pre><code>&lt;context:component-scan base-package="com.foo.bar.baz.bleep.bll" /&gt; &lt;context:component-scan base-package="com.foo.bar.baz.bleep.domainmodel" /&gt; &lt;context:component-scan base-package="com.foo.bar.baz.bleep.web" /&gt; </code></pre> <p>my <code>cucumber.xml</code> in the business layer</p> <pre><code>&lt;context:component-scan base-package="com.foo.bar.baz.bleep.bll" /&gt; &lt;context:component-scan base-package="com.foo.bar.baz.bleep.domainmodel" /&gt; &lt;import resource="classpath:business-context.xml" /&gt; </code></pre> <p>my two <code>business-context.xml</code></p> <p>TEST <code>business-context.xml</code></p> <pre><code>&lt;bean id="sampleAppDao" class="com.foo.bar.baz.bleep.dal.inMemorySampleAppDaoImpl"&gt;&lt;/bean&gt; </code></pre> <p>REAL <code>business-context.xml</code></p> <pre><code>&lt;bean id="sampleAppDao" class="com.foo.bar.baz.bleep.dal.sampleAppDaoImpl"&gt;&lt;/bean&gt; </code></pre> <p>My implementations are all annotated with the appropriate component annotation (i.e. @Controller on the web-servlet, @Service on the business service and @Repository on the dao) All modules have the necessary dependencies to other modules in the pom.xml.</p> <p><strong>I have two questions:</strong></p> <ol> <li><p>What am I doing wrong? Obviously =)</p></li> <li><p>Have I gotten this auto-wiring business all wrong? I was thinking I'd only scan the packages that each module specifically needed, not EVERYTHING (<code>context:component-scan base-package="com.foo" /&gt;</code>), like I have seen in many tutorials. One thing to note there: I have tried scanning everything before in other projects, but ran into the same problem, that is why I started scanning just what was necessary for each module.</p></li> </ol> <p>Please advice me in how to make this work!</p> <p><strong>UPDATE 1</strong></p> <p>web.xml</p> <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"&gt; &lt;display-name&gt;Display Name Here&lt;/display-name&gt; &lt;!-- Spring --&gt; &lt;listener&gt; &lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt; &lt;/listener&gt; &lt;listener&gt; &lt;listener-class&gt;org.springframework.web.context.request.RequestContextListener&lt;/listener-class&gt; &lt;/listener&gt; &lt;context-param&gt; &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt; &lt;param-value&gt;/WEB-INF/web-context.xml&lt;/param-value&gt; &lt;/context-param&gt; &lt;!-- Vaadin servlet --&gt; &lt;servlet&gt; &lt;servlet-name&gt;Coconut Scooter&lt;/servlet-name&gt; &lt;servlet-class&gt;ru.xpoft.vaadin.SpringVaadinServlet&lt;/servlet-class&gt; &lt;init-param&gt; &lt;description&gt;Vaadin UI to display&lt;/description&gt; &lt;param-name&gt;beanName&lt;/param-name&gt; &lt;param-value&gt;mainUI&lt;/param-value&gt; &lt;/init-param&gt; &lt;init-param&gt; &lt;description&gt;Application widgetset&lt;/description&gt; &lt;param-name&gt;widgetset&lt;/param-name&gt; &lt;param-value&gt;com.foo.bar.baz.bleep.common.widgetset.AppWidgetSet&lt;/param-value&gt; &lt;/init-param&gt; &lt;/servlet&gt; &lt;servlet-mapping&gt; &lt;servlet-name&gt;Coconut Scooter&lt;/servlet-name&gt; &lt;url-pattern&gt;/*&lt;/url-pattern&gt; &lt;/servlet-mapping&gt; &lt;servlet-mapping&gt; &lt;servlet-name&gt;Coconut Scooter&lt;/servlet-name&gt; &lt;url-pattern&gt;/VAADIN/*&lt;/url-pattern&gt; &lt;/servlet-mapping&gt; &lt;context-param&gt; &lt;description&gt;Vaadin production mode&lt;/description&gt; &lt;param-name&gt;productionMode&lt;/param-name&gt; &lt;param-value&gt;false&lt;/param-value&gt; &lt;/context-param&gt; &lt;/web-app&gt; </code></pre> <p>web-context.xml</p> <pre><code>&lt;context:component-scan base-package="com.foo.bar.baz.bleep" use-default-filters="false"&gt; &lt;context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /&gt; &lt;/context:component-scan&gt; </code></pre> <p>cucumber.xml</p> <pre><code>&lt;context:component-scan base-package="com.foo.bar.baz.bleep"&gt; &lt;context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" /&gt; &lt;/context:component-scan&gt; &lt;import resource="classpath:business-context.xml" /&gt; </code></pre> <p><strong>UPDATE 2</strong></p> <p>As in the comments of M. Deinum's answer, when neither using Spring MVC nor dispatcherservlet you can safely load all of your context-files in the ContextLoaderListener in order for your beans to be loaded into a single ApplicationContext. This can be done by simply using component-scan that scans all your packages. See updated context-files below.</p> <p>web-context.xml</p> <pre><code>&lt;context:component-scan base-package="com.foo.bar.baz.bleep" /&gt; </code></pre> <p>cucumber.xml</p> <pre><code>&lt;context:component-scan base-package="com.foo.bar.baz.bleep" /&gt; &lt;import resource="classpath:business-context.xml" /&gt; </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload