簡體   English   中英

在ServletContext和ContextLoaderListener中組織bean

[英]Organizing beans in ServletContext and ContextLoaderListener

我有一個spring-webmvc + spring-security應用程序,並且遇到了bean注入問題。 首先, org.springframework.web.servlet.DispatcherServletorg.springframework.web.filter.DelegatingFilterProxyorg.springframework.web.context.ContextLoaderListener都在web.xml定義,servlet上下文稱為servlet-context.xml和應用程序上下文application-context.xml

現在,當我創建使用org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping服務時,就會出現問題。 如果我在application-context.xml創建此bean,則找不到RequestMappingHandlerMapping類型的bean。 但是,如果將其放在servlet-context.xml ,找到了RequestMappingHandlerMapping則可以在Controllers中使用我的服務,但是不能在application-context.xml創建的其他服務中使用它。

我的問題是如何在這種應用程序配置中組織Bean創建。 我覺得這里缺少一些簡單的東西。

編輯:使用特定配置文件啟動應用程序時,會將過濾器添加到過濾器鏈,從而可以模擬API調用。 該過濾器是在應用程序上下文中定義的,因為這是定義彈簧安全性的地方。 它還需要訪問服務,該服務可以提供所有請求映射的列表以及與之關聯的我們的自定義權限(不,它們不能很好地轉換為spring角色)。 但是,此服務需要在Servlet上下文中定義,因為它需要訪問RequestMappingHandlerMapping

編輯#2:我公司生產的MWE(可能768,16是最小的工作實例?)這里: https://github.com/guilty/separate-spring-contexts

現在,有一個ExampleControllerCoreService 它們都是在單獨的上下文中創建的,需要訪問MappedUrlsService ,而后者又希望可訪問RequestMappingHandlerMapping bean。 根據實際創建MappedUrlsService Bean的位置,您可以獲取到未找到RequestMappingHandlerMapping Bean,或者未找到MappedUrlsService Bean。 這是未找到RequestMappingHandlerMapping的堆棧跟蹤:

SEVERE: Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.github.guilty.spring.service.CoreServiceImpl#0': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.github.guilty.spring.service.MappedUrlsService com.github.guilty.spring.service.CoreServiceImpl.mappedUrlsService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.github.guilty.spring.service.MappedUrlsService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:292)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1185)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:703)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
        at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:403)
        at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
        at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
        at org.eclipse.jetty.server.handler.ContextHandler.callContextInitialized(ContextHandler.java:800)
        at org.eclipse.jetty.servlet.ServletContextHandler.callContextInitialized(ServletContextHandler.java:446)
        at org.eclipse.jetty.server.handler.ContextHandler.startContext(ContextHandler.java:792)
        at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:296)
        at org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1341)
        at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1334)
        at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:744)
        at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:497)
        at org.eclipse.jetty.maven.plugin.JettyWebAppContext.doStart(JettyWebAppContext.java:281)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
        at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132)
        at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:114)
        at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:60)
        at org.eclipse.jetty.server.handler.ContextHandlerCollection.doStart(ContextHandlerCollection.java:154)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
        at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132)
        at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:114)
        at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:60)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
        at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132)
        at org.eclipse.jetty.server.Server.start(Server.java:357)
        at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:114)
        at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:60)
        at org.eclipse.jetty.server.Server.doStart(Server.java:324)
        at org.eclipse.jetty.maven.plugin.JettyServer.doStart(JettyServer.java:68)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
        at org.eclipse.jetty.maven.plugin.AbstractJettyMojo.startJetty(AbstractJettyMojo.java:564)
        at org.eclipse.jetty.maven.plugin.AbstractJettyMojo.execute(AbstractJettyMojo.java:360)
        at org.eclipse.jetty.maven.plugin.JettyRunMojo.execute(JettyRunMojo.java:168)
        at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:133)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:208)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
        at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:108)
        at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:76)
        at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
        at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:116)
        at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:361)
        at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:155)
        at org.apache.maven.cli.MavenCli.execute(MavenCli.java:584)
        at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:213)
        at org.apache.maven.cli.MavenCli.main(MavenCli.java:157)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
        at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
        at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
        at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.github.guilty.spring.service.MappedUrlsService com.github.guilty.spring.service.CoreServiceImpl.mappedUrlsService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.github.guilty.spring.service.MappedUrlsService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:508)
        at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:289)
        ... 63 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.github.guilty.spring.service.MappedUrlsService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1103)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:963)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:858)
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:480)
        ... 65 more

使用mvn jetty:run示例。 請注意,運行它需要Java 7Maven

RequestMappingHandlerMapping設計為僅在控制器層中使用(通常與<mvc:annotation-driven/> ),因此應僅在servlet-context.xml中使用

您是否有理由在服務層中需要此服務?

DispatcherServlet的上下文中創建一個RequestMappingHandlerMapping ,它可以訪問在根上下文(application-context.xml)中定義的bean,但不能進行其他操作。 但是,您可以在根上下文中定義一個RequestMappingHandlerMapping bean。 Spring MVC應該可以毫無問題地進行處理。 但這在servlet上下文之外確實沒有任何意義。

好吧,我不會討論您的bean組織的原因,而只會討論如何。

您可以從servlet上下文的bean中注入來自根上下文的bean,但不能相反,因為servlet上下文是作為根上下文作為其父級創建的。

恕我直言,在服務層中依賴於控制器層中的bean確實是一個糟糕的設計,在現實世界中,您應盡量避免使用它。 但讓我們繼續。

我建議您在控制器程序包和servlet上下文中創建一個中繼bean,並將MappedUrlsService在服務程序包和根上下文中。 然后,您將服務注入中繼,但實際上要在服務中編寫一個指向中繼的指針:

public class MappedUrlsRelayImpl {

    @SuppressWarnings("SpringJavaAutowiringInspection")
    @Autowired private RequestMappingHandlerMapping requestMappingHandlerMapping;

    // all the stuff that is presently in MappedUrlsServiceImpl
    // ...

    @Autowired
    private void setMappedUrlsServiceImpl (MappedUrlsServiceImpl serviceImpl) {
        serviceImpl.setMappedUrlsRelayImpl(this);
    }
}

您的服務bean就是:

public class MappedUrlsServiceImpl implements MappedUrlsService {

    @SuppressWarnings("SpringJavaAutowiringInspection")
    private MappedUrlsRelayImpl relay;

    @Override
    public Set<String> getMappedUrls() {
        return relay.getMappedUrls();
    }

    public void setMappedUrlsRelayImpl(MappedUrlsRelayImpl relay) {
        this.relay = relay;
    }
}

這非常丑陋,因為服務依賴於控制器層類,並且我顛倒了Spring注入的依賴關系,但是它可以工作。

要完成servlet上下文中的bean

<bean class="com.github.guilty.spring.controller.ExampleController" />
<bean class="com.github.guilty.spring.controller.MappedUrlsRelayImpl" />

並在根上下文中

<bean class="com.github.guilty.spring.service.CoreServiceImpl" />
<bean class="com.github.guilty.spring.service.MappedUrlsServiceImpl" />

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM