MyBatis-Spring + @Configuration - Can't autowire mapper beans

后端 未结 4 1834
感情败类
感情败类 2020-12-24 09:15

I have been trying to create a Spring project that uses MyBatis for the data access layer as a proof of concept for my team. I really want to avoid XML configuration if at a

相关标签:
4条回答
  • 2020-12-24 09:29

    You'll have to have a context:component-scan in your spring configurations to enable auto detection of @Component . Check the reference.

    0 讨论(0)
  • 2020-12-24 09:34

    Another possible solution can be found in the jira ticked that Jason mentioned. Solved my problem and I did not have to use XML configuration which I try to avoid at any cost...

    https://jira.spring.io/browse/SPR-7868

    @Configuration 
    public class A implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
    
        @Override
        public void postProcessBeanDefinitionRegistry(...) {
             ...
        }
    
        @Override
        public void postProcessBeanFactory(...) {
            ...
        }
    
        @Override
        public int getOrder() {
            return 0;
        }
    }
    
    0 讨论(0)
  • 2020-12-24 09:46

    After some time I was able to figure things out, so I'll answer my own question in case others run into something similar as there wasn't a whole lot of information available out there and it took some searching.

    The problem comes down to the fact that MapperScannerConfigurer is a BeanDefinitionRegistryPostProcessor. As it turns out, this is the same mechanism used to process the @Configuration files and register the @Bean annotated methods. Unfortunately, one BeanDefinitionRegistryPostProcessor cannot make use of another, according to this Spring Jira ticket: https://jira.springsource.org/browse/SPR-7868

    The suggestion here was to create an XML configuration for the processor and then include an @ImportResource annotation in the Java based configuration to pull it in. Well, that suggestion isn't fully accurate. You can't simply create an XML file with the configuration and pull it into the Java based configuration if you are still planning to have your configuration bootstrapped via an AnnotationConfigContextLoader. Instead, you have to revert back to loading your configuration via XML first and then creating a bean for your configuration file(s) the "old-fashion" way. For me this, was pretty trivial.

    New Application Context

    <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>
    

    I then bootstrap the context container the traditional way, by providing a ContextConfigLocation. This works for me because the ApplicationContextConfig that I reference in the above XML handles everything else - including component scanning which will pick up all of my other @Configuration files.

    Once I did this, all of my problems went away. I was able to @Autowire the UserDao as I expected and all was wonderful.

    Note:

    When I tried manually defining UserDao by creating a MapperFactoryBean, like in my original question's code example, there was a UserDao bean created but it was of type MapperProxy and would not @Autowire. However, I could get it to load by name using @Repository("userDao"), for what that's worth. I believe that the MapperFactoryBean suffers from a similar problem as the MapperScannerConfigurer and is simply not compatible with @Configuration files, alas.

    0 讨论(0)
  • 2020-12-24 09:52

    From mybatis.3.2.0 and mybatis-spring.1.2.0, instead of MapperFactoryBean, you can use MapperScan for this.

    @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();   
       } 
    }
    
    0 讨论(0)
提交回复
热议问题