8

我正在以编程方式进行 Spring 配置。我没有得到我期望的注入结果,所以我查看了日志,出于某种原因,Spring 两次生成了我的单例 bean。

我在 Tomcat 启动日志中得到了这个

INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@74b1128c: defining beans <LIST OF BEANS>

...little further

INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@61de76d0: defining beans <SAME LIST OF BEANS>

这是正常行为吗?

这是我的应用程序上下文

@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages = {"com.application.shiro",
                   "com.business.dao.impl", 
                   "com.business.services"})
public class AppRootContext {    
    /* Beans */
}

这是我的 Servlet 上下文

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.application.controllers"})
public class AppServletContext extends WebMvcConfigurerAdapter {
    /* Beans */
}

我的 Servlet Initializer 类称为 BidAppInitializer

@Override
public void onStartup(ServletContext container) throws ServletException {
    AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
    rootContext.register(AppRootContext.class);

    container.addListener(new ContextLoaderListener(rootContext));

    AnnotationConfigWebApplicationContext servletContext = new AnnotationConfigWebApplicationContext();
    servletContext.register(AppServletContext.class);

    ServletRegistration.Dynamic appServlet = container.addServlet("bidapp", new DispatcherServlet(servletContext));
    appServlet.setLoadOnStartup(1);
    appServlet.addMapping("/");
}

这是我完整的 Tomcat 启动日志:

Feb 26, 2013 11:32:21 PM org.apache.catalina.core.AprLifecycleListener init
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: C:\Program Files\Java\jre7\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\MATLAB\R2010b\runtime\win64;C:\Program Files\MATLAB\R2010b\bin;C:\Users\Soto\Desktop\android-sdk-windows\tools;C:\Program Files (x86)\Common Files\Teleca Shared;C:\Program Files\TortoiseSVN\bin;C:\Program Files (x86)\QuickTime\QTSystem\;C:\Program Files\TortoiseHg\;C:\MinGW\bin;C:\Program Files\nodejs\; C:\PostgreSQL\9.2\bin\;C:\Program Files\MySQL\MySQL Server 5.5\bin;C:\MySQL\MySQL Server 5.5\bin;C:\Ruby193\bin;C:\Program Files (x86)\SSH Communications Security\SSH Secure Shell;C:\Users\Soto\Desktop\android-sdk-windows\tools;C:\MinGW\bin;C:\Users\Soto\AppData\Roaming\npm\;C:\apache-maven-3.0.4\bin;C:\Program Files\Java\jdk1.7.0_02\bin;C:\PostgreSQL\9.2\bin;.
Feb 26, 2013 11:32:21 PM org.apache.tomcat.util.digester.SetPropertiesRule begin
WARNING: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.eclipse.jst.j2ee.server:BidApp' did not find a matching property.
Feb 26, 2013 11:32:21 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-bio-8080"]
Feb 26, 2013 11:32:21 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["ajp-bio-8009"]
Feb 26, 2013 11:32:21 PM org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 824 ms
Feb 26, 2013 11:32:21 PM org.apache.catalina.core.StandardService startInternal
INFO: Starting service Catalina
Feb 26, 2013 11:32:21 PM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/7.0.22
Feb 26, 2013 11:32:29 PM org.apache.catalina.core.ApplicationContext log
INFO: Spring WebApplicationInitializers detected on classpath: [com.bidapp.bootstrap.BidAppInitializer@60515c64]
Feb 26, 2013 11:32:32 PM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring root WebApplicationContext
Feb 26, 2013 11:32:32 PM org.springframework.web.context.ContextLoader initWebApplicationContext
INFO: Root WebApplicationContext: initialization started
Feb 26, 2013 11:32:32 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing Root WebApplicationContext: startup date [Tue Feb 26 23:32:32 EST 2013]; root of context hierarchy
Feb 26, 2013 11:32:33 PM org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider registerDefaultFilters
INFO: JSR-330 'javax.inject.Named' annotation found and supported for component scanning
Feb 26, 2013 11:32:33 PM org.springframework.web.context.support.AnnotationConfigWebApplicationContext loadBeanDefinitions
INFO: Registering annotated classes: [class com.bidapp.bootstrap.AppRootContext]
Feb 26, 2013 11:32:33 PM org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider registerDefaultFilters
INFO: JSR-330 'javax.inject.Named' annotation found and supported for component scanning
Feb 26, 2013 11:32:36 PM org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor <init>
INFO: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring

SDASD <--- Logged by my Root Context class constructor

Feb 26, 2013 11:33:49 PM org.springframework.context.support.AbstractApplicationContext$BeanPostProcessorChecker postProcessAfterInitialization
INFO: Bean 'appRootContext' of type [class com.bidapp.bootstrap.AppRootContext$$EnhancerByCGLIB$$84ad5432] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
Feb 26, 2013 11:33:52 PM org.springframework.context.support.AbstractApplicationContext$BeanPostProcessorChecker postProcessAfterInitialization
INFO: Bean 'proxyAsyncConfiguration' of type [class org.springframework.scheduling.annotation.ProxyAsyncConfiguration$$EnhancerByCGLIB$$f08c92c2] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
Feb 26, 2013 11:33:54 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@6393d737: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,appRootContext,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0,accountActivationDaoHibernateImpl,accountDao,auctionDaoHibernateImpl,categoryDao,accountService,emailService,org.springframework.aop.config.internalAutoProxyCreator,proxyTransactionManagementConfiguration,org.springframework.transaction.config.internalTransactionAdvisor,transactionAttributeSource,transactionInterceptor,proxyAsyncConfiguration,org.springframework.context.annotation.internalAsyncAnnotationProcessor,securityManager,credentialsMatcher,sessionFactory,transactionManager,hibernateRealm,lifecycleBeanPostProcessor,webTemplateResolver,emailTemplateResolver,templateEngine,shiroFilter,taskExecutor,dataSource,mailSender,viewResolver]; root of factory hierarchy
Feb 26, 2013 11:33:56 PM com.mchange.v2.log.MLog <clinit>
INFO: MLog clients using java 1.4+ standard logging.
Feb 26, 2013 11:33:56 PM com.mchange.v2.c3p0.C3P0Registry banner
INFO: Initializing c3p0-0.9.1 [built 16-January-2007 14:46:42; debug? true; trace: 10]
Feb 26, 2013 11:34:45 PM com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource getPoolManager
INFO: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 10, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> 1hge15x8t76zmwq1uj2ed9|6cfb984, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 1hge15x8t76zmwq1uj2ed9|6cfb984, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/bidapp, lastAcquisitionFailureDefaultUser -> null, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 1800, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 20, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 5, numHelperThreads -> 3, numThreadsAwaitingCheckoutDefaultUser -> 0, preferredTestQuery -> null, properties -> {user=******, password=******}, propertyCycle -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false ]
Feb 26, 2013 11:35:33 PM org.springframework.orm.hibernate4.HibernateTransactionManager afterPropertiesSet
INFO: Using DataSource [com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 10, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> 1hge15x8t76zmwq1uj2ed9|6cfb984, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 1hge15x8t76zmwq1uj2ed9|6cfb984, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/bidapp, lastAcquisitionFailureDefaultUser -> null, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 1800, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 20, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 5, numHelperThreads -> 3, numThreadsAwaitingCheckoutDefaultUser -> 0, preferredTestQuery -> null, properties -> {user=******, password=******}, propertyCycle -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false ]] of Hibernate SessionFactory for HibernateTransactionManager
Feb 26, 2013 11:35:36 PM org.springframework.web.context.ContextLoader initWebApplicationContext
INFO: Root WebApplicationContext: initialization completed in 183726 ms
Feb 26, 2013 11:35:36 PM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring FrameworkServlet 'bidapp'
Feb 26, 2013 11:35:36 PM org.springframework.web.servlet.FrameworkServlet initServletBean
INFO: FrameworkServlet 'bidapp': initialization started
Feb 26, 2013 11:35:36 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing WebApplicationContext for namespace 'bidapp-servlet': startup date [Tue Feb 26 23:35:36 EST 2013]; parent: Root WebApplicationContext
Feb 26, 2013 11:35:36 PM org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider registerDefaultFilters
INFO: JSR-330 'javax.inject.Named' annotation found and supported for component scanning
Feb 26, 2013 11:35:36 PM org.springframework.web.context.support.AnnotationConfigWebApplicationContext loadBeanDefinitions
INFO: Registering annotated classes: [class com.bidapp.bootstrap.AppServletContext]
Feb 26, 2013 11:35:37 PM org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider registerDefaultFilters
INFO: JSR-330 'javax.inject.Named' annotation found and supported for component scanning
Feb 26, 2013 11:35:40 PM org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor <init>
INFO: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
Feb 26, 2013 11:35:42 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@2c8ff601: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,appServletContext,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0,accountController,auctionController,indexPagesController,delegatingWebMvcConfiguration,requestMappingHandlerMapping,viewControllerHandlerMapping,beanNameHandlerMapping,resourceHandlerMapping,defaultServletHandlerMapping,requestMappingHandlerAdapter,mvcConversionService,mvcValidator,httpRequestHandlerAdapter,simpleControllerHandlerAdapter,handlerExceptionResolver]; parent: org.springframework.beans.factory.support.DefaultListableBeanFactory@6393d737
Feb 26, 2013 11:35:52 PM org.springframework.web.servlet.handler.AbstractHandlerMethodMapping registerHandlerMethod
...Controller handler method mappings
4

2 回答 2

13

Singleton 保证 Spring 容器内的单个实例。这意味着您可以拥有与singleton容器一样多的实例(即使它们使用相同的 JVM 类加载器)。请参阅单例范围和单例设计模式与单例 Bean的答案

在您的情况下,您正在实例化两个上下文 - rootContext 和 servletContext ,它们是来自日志语句。

如果您想拥有每个单例的单个实例 - 您可以合并这两个上下文。


说明这种行为的小型 java 类(对奇怪的代码格式表示歉意 - 想让它更简洁):

package singleton;

import java.util.UUID;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

public class AppMain {

    public static void main(String[] args) {
        final AnnotationConfigApplicationContext rootContext = new AnnotationConfigApplicationContext();
        rootContext.register(AppRootContext.class);
        rootContext.refresh();

        final AnnotationConfigApplicationContext servletContext = new AnnotationConfigApplicationContext();
        servletContext.register(AppServletContext.class);
        servletContext.refresh();

        final Singleton one = (Singleton) rootContext.getBean("singleton");
        final Singleton andAnotherOne = (Singleton) servletContext.getBean("singleton");

        System.out.println("Singletons are " + (one.ID.equals(andAnotherOne.ID) ? "equal" : "different"));
    }
}

@Component
class Singleton {public String ID = UUID.randomUUID().toString();}

@Configuration
@ComponentScan(basePackages = { "singleton" })
class AppRootContext {}

@Configuration
@ComponentScan(basePackages = { "singleton" })
class AppServletContext {}
于 2013-02-27T05:29:18.350 回答
0

有两种类型的上下文,一种是根上下文,另一种是 Web 应用程序上下文。

如果在扩展 AbstractAnnotationConfigDispatcherServletInitializer 类的 WebAppInitalizer 中,请确保

您覆盖以下方法并确保在两个方法中不重复类定义。

@Override protected Class[] getServletConfigClasses() { return new Class[] { MvcConfig.class}; }

@Override
protected Class<?>[] getRootConfigClasses() {
    return new Class[] {RooTContextAppConfig.class };
}
于 2016-11-24T16:07:26.557 回答