MyBatis-Spring + @Configuration - Не удается выполнить автоматическое подключение bean-компонентов mapper

Я пытался создать проект Spring, который использует MyBatis для уровня доступа к данным в качестве доказательства концепции для моей команды. Я действительно хочу избежать конфигурации XML, если это вообще возможно, поэтому я пытаюсь связать все вместе, используя аннотированные классы @Configuration .

Кажется, что все подключено правильно, но мои bean-компоненты отображения не подключаются автоматически к моему уровню обслуживания.

В моем примере я пытаюсь связать вместе UserDao, объект User и UserService.

UserDao

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

User

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

Я соединяю их вместе, используя два класса конфигурации.

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

Вы можете прочитать комментарии над двумя последними методами в приведенном выше фрагменте кода, чтобы лучше понять, как я создаю bean-компонент UserDao.

После того, как я получил всю настройку конфигурации, я создал модульный тест, чтобы попытаться протестировать UserService с помощью AnnotationConfigContextLoader , но сразу же получил следующее исключение при попытке запустить тест:

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

Увидев это, я закомментировал @Autowired в UserService , вернулся к своему модульному тесту и ввел ApplicationContext , чтобы я мог его проверить, а bean-компонент с именем «userDao» на самом деле является экземпляром MapperProxy .

Итак, насколько я понимаю, как MapperFactoryBean работает некорректно, или он просто не очень совместим с конфигурацией, управляемой аннотациями? Кроме того, если кто-нибудь знает, как заставить MapperScannerConfigurer работать правильно, я был бы очень признателен!

11
задан Jason McClellan 25 January 2012 в 08:17
поделиться