我一直在尝试创建一个Spring项目,它将MyBatis用于数据访问层,作为我团队的概念验证.我真的希望尽可能避免XML配置,所以我试图使用带注释的@Configuration类将所有内容连接在一起.
一切似乎都正确连接,但我的映射器bean没有自动连接到我的服务层.
在我的示例中,我正在尝试将UserDao,User实体和UserService连接在一起.
public interface UserDao {
@Select("SELECT * FROM users WHERE id = #{userId}")
User get(@Param("userId") Integer userId);
}
Run Code Online (Sandbox Code Playgroud)
@Component("User")
public class User implements Entity {
public Integer userId;
public String username;
/** ... getters/setters ommitted **/
}
Run Code Online (Sandbox Code Playgroud)
@Service("UserService")
public class UserServiceImpl {
private UserDao userDao = null;
public User getUserDetails(Integer userId) {
return userDao.get(userId);
}
@Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
Run Code Online (Sandbox Code Playgroud)
我使用两个配置类将它们连接在一起.
@Configuration
@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)
@Import(DefaultDataAccessConfig.class) // I'm importing this because I thought ordering might be important, otherwise I was hoping to just let the component scanning pull in additional configuration files
@ComponentScan(basePackages="com.example.gwtspringpoc.server",
excludeFilters=@Filter(type=FilterType.ANNOTATION,
value=Controller.class))
public class ApplicationContextConfig {
/** No bean definitions needed here **/
}
Run Code Online (Sandbox Code Playgroud)
@Configuration
@EnableTransactionManagement
public class DefaultDataAccessConfig implements TransactionManagementConfigurer {
@Bean
public DataSource dataSource() {
OracleDataSource ods = null;
try {
ods = new OracleDataSource();
} catch (SQLException e) {
throw new RuntimeException(e);
}
ods.setURL("jdbc:oracle:thin:@//localhost:9601/sid");
ods.setUser("user");
ods.setPassword("pass");
return ods;
}
@Override
@Bean(name="transactionManager")
public PlatformTransactionManager annotationDrivenTransactionManager() {
return new DataSourceTransactionManager(dataSource());
}
@Bean
public SqlSessionFactory sqlSessionFactory() {
SqlSessionFactoryBean sf = new SqlSessionFactoryBean();
sf.setDataSource(dataSource());
try {
return (SqlSessionFactory) sf.getObject();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Bean
public SqlSession sqlSessionTemplate() {
return new SqlSessionTemplate(sqlSessionFactory());
}
/*
* This did not work at all. It seems to be configured correctly, but the UserDao bean never
* got created at any stage, which was very disappointing as I was hoping not to have to
* create a bean definition for each DAO manually
*/
/*@Bean
public static MapperScannerConfigurer mapperScannerConfig() {
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("com.ca.spna.gwtspringpoc.server.model.dao");
msc.setAnnotationClass(Repository.class);
return msc;
}*/
/*
* Because the above code did not work, I decided to create the mapping manually.
* This is most likely my problem - something about this setup. My understanding
* is that the MapperFactoryBean once instantiated by Spring, will create a proxy
* object of type UserDao with the name "userDao" that can be injected elsewhere.
*/
@Bean
public MapperFactoryBean<UserDao> userDao() {
MapperFactoryBean<UserDao> mfb = new MapperFactoryBean<UserDao>();
mfb.setMapperInterface(UserDao.class);
return mfb;
}
}
Run Code Online (Sandbox Code Playgroud)
您可以阅读上面代码片段中最后两种方法的注释,以深入了解我是如何创建UserDao bean的.
完成所有配置设置后,我创建了一个单元测试,尝试使用AnnotationConfigContextLoader测试UserService,但在尝试运行测试时立即遇到以下异常:
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void com.example.gwtspringpoc.server.service.UserServiceImpl.setUserDao(com.example.gwtspringpoc.server.model.dao.UserDao); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.example.gwtspringpoc.server.model.dao.UserDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
Run Code Online (Sandbox Code Playgroud)
看到之后,我在UserService中注释了@Autowired并返回我的单元测试并注入了ApplicationContext,以便我可以检查它,而名为"userDao"的bean实际上是一个MapperProxy实例.
那么,我对MapperFactoryBean的工作方式有所了解,还是与注释驱动配置不兼容?此外,如果有人知道如何使MapperScannerConfigurer正常工作,我将非常感激!
Jas*_*lan 14
经过一段时间后,我能够解决问题,所以我会回答我自己的问题,以防其他人碰到类似的东西,因为那里没有很多可用的信息,并且需要进行一些搜索.
问题归结为MapperScannerConfigurer是BeanDefinitionRegistryPostProcessor.事实证明,这与处理@Configuration文件和注册@Bean注释方法的机制相同.不幸的是,根据Spring Jira的这张票,一个BeanDefinitionRegistryPostProcessor不能使用另一个:https://jira.springsource.org/browse/SPR-7868
这里的建议是为处理器创建XML配置,然后在基于Java的配置中包含@ImportResource注释以将其拉入.那么,该建议并不完全准确.如果仍计划通过AnnotationConfigContextLoader引导配置,则不能简单地使用配置创建XML文件并将其拉入基于Java的配置.相反,您必须首先通过XML恢复加载配置,然后以"旧式"方式为配置文件创建bean.对我而言,这非常微不足道.
新的应用背景
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<!--
Because MapperScannerConfigurer is a BeanDefinitionRegistryPostProcessor, it cannot be
configured via @Configuration files with a @Bean annotaiton, because those files are
themselves configured via a BeanDefinitionRegistryPostProcessor which cannot spawn
another one.
-->
<bean id="myBatisMapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.example.gwtspringpoc.server.model.dao"/>
<property name="annotationClass" value="org.springframework.stereotype.Repository"/>
</bean>
<!--
Load the rest of our configuration via our base configuration class
-->
<bean class="com.example.gwtspringpoc.server.spring.config.ApplicationContextConfig" />
</beans>
Run Code Online (Sandbox Code Playgroud)
然后,我通过提供ContextConfigLocation以传统方式引导上下文容器.这对我有用,因为我在上面的XML中引用的ApplicationContextConfig处理其他所有内容 - 包括组件扫描,它将获取我所有其他@Configuration文件.
一旦我这样做,我的所有问题都消失了.我能按照我的预期@Autowire UserDao,一切都很精彩.
注意:
当我尝试通过创建MapperFactoryBean手动定义UserDao时,就像在我原来的问题的代码示例中一样,创建了一个UserDao bean,但它的类型为MapperProxy,而不是@Autowire.但是,我可以使用@Repository("userDao")按名称加载它,这是值得的.我相信MapperFactoryBean遇到与MapperScannerConfigurer类似的问题,并且与@Configuration文件完全不兼容,唉.
小智 5
从mybatis.3.2.0和mybatis-spring.1.2.0,您可以使用MapperScan代替MapperFactoryBean.
@Configuration
@MapperScan("org.mybatis.spring.sample.mapper")
public class AppConfig
{
@Bean
public DataSource dataSource()
{
return new EmbeddedDatabaseBuilder().addScript("schema.sql").build();
}
@Bean
public DataSourceTransactionManager transactionManager()
{
return new DataSourceTransactionManager(dataSource());
}
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception
{
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
return sessionFactory.getObject();
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
40865 次 |
| 最近记录: |