布线豆时如何思考

时间:2013-08-30 07:36:02

标签: java spring

我正试图更好地处理Spring处理依赖注入的方式,但我已经面临一个(至少对我而言)非常奇怪的情况。

我有一个分层的应用程序,可以直观地描述如下: web - business - domainmodel - dal ...单独模块中的每一层。

我正在使用注释来注入我的类中所需的东西,并且为了使事情变得更复杂我在业务层使用黄瓜,这意味着我需要在测试时显式地注入test-bean,而在实时测试时需要注入一个真正的bean不测试。

Everything编译得很好,甚至运行并注入(@Inject)一切都很好...... 直到我将这一行添加到web层的context.xml中:

<context:component-scan base-package="com.foo.bar.baz.bleep.bll" />

......这是我的问题开始的地方。添加该行后,编译成功完成,但是当我在Tomcat中运行它时出现此错误:

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)

容器中突然出现dao(?)。

我想使用Web层中业务层的业务服务,但是一旦我尝试将bll上的扫描添加到Web层,业务层就会中断。是什么给了什么?

我在网络图层中的web-context.xml

<context:component-scan base-package="com.foo.bar.baz.bleep.bll" />
<context:component-scan base-package="com.foo.bar.baz.bleep.domainmodel" />
<context:component-scan base-package="com.foo.bar.baz.bleep.web" />

我在业务层的cucumber.xml

<context:component-scan base-package="com.foo.bar.baz.bleep.bll" />
<context:component-scan base-package="com.foo.bar.baz.bleep.domainmodel" />
<import resource="classpath:business-context.xml" />

我的两个business-context.xml

TEST business-context.xml

<bean id="sampleAppDao" class="com.foo.bar.baz.bleep.dal.inMemorySampleAppDaoImpl"></bean>

REAL business-context.xml

<bean id="sampleAppDao" class="com.foo.bar.baz.bleep.dal.sampleAppDaoImpl"></bean>

我的实现都使用适当的组件注释进行注释(即web-servlet上的@Controller,业务服务上的@Service和dao上的@Repository) 所有模块都与pom.xml中的其他模块具有必要的依赖关系。

我有两个问题:

  1. 我做错了什么?显然=)

  2. 我的自动接线业务是否全部错了?我以为我只扫描每个模块特别需要的软件包,而不是一切(context:component-scan base-package="com.foo" />),就像我在很多教程中看到的那样。有一点需要注意:我曾尝试在其他项目中扫描所有内容,但遇到了同样的问题,这就是为什么我开始扫描每个模块所需的内容。

  3. 请告诉我如何完成这项工作!

    更新1

    的web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <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">
    
        <display-name>Display Name Here</display-name>
    
        <!-- Spring -->
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
        <listener>
            <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
        </listener>
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/web-context.xml</param-value>
        </context-param>
    
        <!-- Vaadin servlet -->
        <servlet>
            <servlet-name>Coconut Scooter</servlet-name>
            <servlet-class>ru.xpoft.vaadin.SpringVaadinServlet</servlet-class>
            <init-param>
                <description>Vaadin UI to display</description>
                <param-name>beanName</param-name>
                <param-value>mainUI</param-value>
            </init-param>
            <init-param>
                <description>Application widgetset</description>
                <param-name>widgetset</param-name>
                <param-value>com.foo.bar.baz.bleep.common.widgetset.AppWidgetSet</param-value>
            </init-param>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>Coconut Scooter</servlet-name>
            <url-pattern>/*</url-pattern>
        </servlet-mapping>
        <servlet-mapping>
            <servlet-name>Coconut Scooter</servlet-name>
            <url-pattern>/VAADIN/*</url-pattern>
        </servlet-mapping>
    
        <context-param>
            <description>Vaadin production mode</description>
            <param-name>productionMode</param-name>
            <param-value>false</param-value>
        </context-param>
    
    </web-app>
    

    网络context.xml中

    <context:component-scan base-package="com.foo.bar.baz.bleep"
        use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    </context:component-scan>
    

    cucumber.xml

    <context:component-scan base-package="com.foo.bar.baz.bleep">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    </context:component-scan>
    
    <import resource="classpath:business-context.xml" />
    

    更新2

    正如M. Deinum的回答一样,当既不使用Spring MVC也不使用dispatcherservlet时,您可以安全地在ContextLoaderListener中加载所有上下文文件,以便将bean加载到单个ApplicationContext中。这可以通过简单地使用扫描所有包的组件扫描来完成。请参阅下面的更新上下文文件。

    网络context.xml中

    <context:component-scan base-package="com.foo.bar.baz.bleep" />
    

    cucumber.xml

    <context:component-scan base-package="com.foo.bar.baz.bleep" />
    
    <import resource="classpath:business-context.xml" />
    

1 个答案:

答案 0 :(得分:1)

您的配置错误,您的网络层应该只扫描与网络相关的bean,您还在扫描您在其他应用程序上下文中扫描的其他类型的bean。基本上你创建了2个yuor服务实例,第二个是失败的,因为它无法满足它的依赖性。

所以基本上你的网站应该这样做

<context:component-scan base-package="com.foo.bar.baz.bleep.web" />

没有更多,没有更少。另一个可以保持原样。

请参阅我的相关回答here