【发布时间】:2020-04-21 02:04:02
【问题描述】:
我正在尝试在我的 Web 应用程序中配置两个不同的配置类——一个使用 jdbc,另一个使用 hibernate。我将我的配置类定义如下:
@Profile("jdbc")
@Configuration
public class JdbcConfiguration {
...
}
@Profile("hibernate")
@Configuration
public class HibernateConfiguration {
...
}
我还有两个主要的配置类。一个用于服务,一个用于定义 jdbc 和 hibernate 配置类(例如,数据源 bean)所需的一些数据库基础设施。以下是这些类:
@Import({JdbcConfiguration.class, HibernateConfiguration.class})
@Configuration
@EnableTransactionManagement
@PropertySource("classpath:/db.properties")
public class DataAccessConfiguration {
...
}
@Configuration
@Import(DataAccessConfiguration.class)
@ComponentScan(basePackages = {"domain.validation","services"})
public class ServiceConfiguration {
private final UserDao userDao;
private final GroupDao groupDao;
private final TaskDao taskDao;
public ServiceConfiguration(UserDao userDao, GroupDao groupDao, TaskDao taskDao) {
this.userDao = userDao;
this.groupDao = groupDao;
this.taskDao = taskDao;
}
...
}
我想做的是 DataAccessConfiguration 导入 jdbc 和 hibernate 配置。如果 jdbc 配置文件处于活动状态,则只应创建 jdbc 配置中的 bean。否则(如果 hibernate 配置文件处于活动状态),hibernate 的 bean 应该被创建。然后我将 DataAccessConfig 导入 ServiceConfiguration,它在服务中使用 dao bean。 我在文档中读到,为了激活 Web 应用程序中的配置文件,我需要在我的 web.xml 中定义上下文参数 spring.profiles.active 或在启动时以编程方式将其添加到 servletContext。我做了前者。这是我的网站。 xml
<web-app metadata-complete="false" version="4.0" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" >
<display-name>Easy Do Web</display-name>
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>jdbc</param-value>
</context-param>
</web-app>
我不确定这是否重要,但我通过扩展 AbstractAnnotationConfigDispatcherServletInitializer 来配置我的 servletdispatcher。
我尝试启动应用程序时遇到的错误是:
02-Jan-2020 13:29:46.070 INFO [RMI TCP Connection(2)-127.0.0.1] org.apache.catalina.core.ApplicationContext.log 2 Spring WebApplicationInitializers detected on classpath
02-Jan-2020 13:29:48.973 SEVERE [RMI TCP Connection(2)-127.0.0.1] org.apache.catalina.core.StandardContext.listenerStart Exception sending context initialized event to listener instance of class [listeners.ContListener]
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'serviceConfiguration': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'repository.UserDao' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:787)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:226)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1358)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1204)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:400)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207)
at org.springframework.context.support.AbstractApplicationContext.initMessageSource(AbstractApplicationContext.java:732)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:89)
at listeners.ContListener.contextInitialized(ContListener.java:37)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4685)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5146)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:717)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:690)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:705)
at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1728)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:289)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:456)
at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:405)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:289)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
at com.sun.jmx.remote.security.MBeanServerAccessController.invoke(MBeanServerAccessController.java:468)
at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1468)
at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:76)
at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1309)
at java.security.AccessController.doPrivileged(Native Method)
at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1408)
at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:829)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:357)
at sun.rmi.transport.Transport$1.run(Transport.java:200)
at sun.rmi.transport.Transport$1.run(Transport.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:573)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'repository.UserDao' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1695)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1253)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1207)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:874)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:778)
... 69 more
02-Jan-2020 13:29:48.974 INFO [RMI TCP Connection(2)-127.0.0.1] org.apache.catalina.core.ApplicationContext.log Initializing Spring root WebApplicationContext
02-Jan-2020 13:29:52.700 INFO [RMI TCP Connection(2)-127.0.0.1] org.apache.catalina.core.ApplicationContext.log Closing Spring root WebApplicationContext
这里是完整的jdbc配置类(在hibernate配置中定义了相同的三个dao bean,除了类不同):
@Profile("jdbc")
@Configuration
public class JdbcConfiguration {
private final DataSource dataSource;
public JdbcConfiguration(DataSource dataSource) {
this.dataSource = dataSource;
}
@Bean(name = "userDao")
public UserDao userDao(NamedParameterJdbcTemplate template){
return new UserDaoSpringJdbc(dataSource,template);
}
@Bean(name = "groupDao")
public GroupDao groupDao(UserDao userDao,NamedParameterJdbcTemplate template){
return new GroupDaoSpringJdbc(dataSource,userDao,template);
}
@Bean(name="taskDao")
public TaskDao taskDao(UserDao userDao,GroupDao groupDao,NamedParameterJdbcTemplate template){
return new TaskDaoSpringJdbc(dataSource,userDao,groupDao,template);
}
@Bean
NamedParameterJdbcTemplate template() {
return new NamedParameterJdbcTemplate(dataSource);
}
@Bean(name = "transactionManager")
PlatformTransactionManager jdbcTransactionManager() {
DataSourceTransactionManager manager = new DataSourceTransactionManager();
manager.setDataSource(dataSource);
return manager;
}
}
【问题讨论】:
-
尝试改变@Configuration@Profile("jdbc")public class的位置.....
-
@Import注释的目的是什么?当然应该独立检测每个配置 -
您能否发布您的 UserDao 类,因为堆栈跟踪表明在 spring 上下文中没有创建 userDoa bean
-
这是一个非常有趣的问题。我从未听说有人通过配置文件从 JDBC 切换到 Hibernate。我意识到我没有提供任何答案,但是......你打算用这个设置做什么?这种方法能给你带来什么?
-
@FilippoPossenti 我会说原因完全是“教育性的”。目前我正在使用通过spring jdbc支持(jdbc模板)实现的dao层。将来我想切换到hibernate(保留两个实现)。