MyBatis-Spring + @Configuration - Impossible d'autowire mapper beans

J'ai essayé de créer un projet pour le Printemps qui utilise MyBatis pour la couche d'accès aux données comme une preuve de concept pour mon équipe. Je veux vraiment éviter de configuration XML, si possible, donc je suis d'essayer de fil tout à l'aide de annoté @Configuration classes.

Tout semble être câblé correctement, mais mon mapper les haricots ne sont pas Autocâblés dans ma couche de service.

Dans mon exemple, je suis en train de câbler ensemble un UserDao, entité Utilisateur, et un UserService.

UserDao

public interface UserDao {
    @Select("SELECT * FROM users WHERE id = #{userId}")
    User get(@Param("userId") Integer userId);
}

Utilisateur

@Component("User")
public class User implements Entity {
    public Integer userId;
    public String username;

    /** ... getters/setters ommitted **/
}

UserServiceImpl

@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;
    }
}

Je suis de câblage de l'ensemble à l'aide de ces deux classes de configuration.

ApplicationContextConfig

@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 **/
}

DefaultDataAccessConfig

@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;
    }
}

Vous pouvez lire les commentaires ci-dessus les deux dernières méthodes, dans l'extrait de code ci-dessus pour obtenir plus de perspicacité dans la façon dont je suis la création de la UserDao bean.

Une fois que j'ai eu toute la configuration de l'installation, j'ai créé une unité de test pour essayer de tester la UserService à l'aide de la AnnotationConfigContextLoadermais a été immédiatement frappé avec l'exception suivante lorsque vous essayez d'exécuter le test:

Exception

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: {}

Après avoir vu ça, j'ai commenté la @Autocâblés dans le UserService et suis retourné à mon test unitaire et injecté le ApplicationContext afin que je puisse l'inspecter, et le bean nommé "userDao" est en fait un MapperProxy instance.

Donc, c'est ma compréhension de la façon dont la MapperFactoryBean travaux de piste, ou est-il tout simplement pas très compatible avec l'annotation de configuration? En outre, si quelqu'un a une idée de comment faire la MapperScannerConfigurer fonctionne correctement, je l'apprécie beaucoup!

source d'informationauteur Jason McClellan