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
Vous devez vous connecter pour publier un commentaire.
Après quelques temps, j'ai été capable de comprendre les choses, donc je vais répondre à ma propre question dans le cas d'autres courir dans quelque chose de similaire comme il n'y avait pas beaucoup d'informations disponibles là-bas et il a fallu quelques recherches.
Le problème vient du fait que MapperScannerConfigurer est un BeanDefinitionRegistryPostProcessor. Comme il s'avère, c'est le même mécanisme utilisé pour traiter la @Configuration de fichiers et de registre de la @Bean annoté méthodes. Malheureusement, un BeanDefinitionRegistryPostProcessor ne peut pas faire usage de l'autre, en fonction de ce Printemps Jira billet: https://jira.springsource.org/browse/SPR-7868
La suggestion ici est de créer un fichier XML de configuration pour le processeur et un @ImportResource annotation Java en fonction de la configuration de tirer. Bien que cette proposition n'est pas tout à fait exact. Vous ne pouvez pas il suffit de créer un fichier XML avec la configuration et le tirer vers le Java en fonction de la configuration si vous êtes encore la planification de votre configuration amorcé par le biais d'un AnnotationConfigContextLoader. Au lieu de cela, vous devez revenir en arrière pour le chargement de votre configuration via XML en premier et ensuite la création d'un bean pour votre fichier de configuration(s) "old-fashion". Pour moi, c'était assez trivial.
Nouveau Contexte De L'Application
Je puis amorce le contexte conteneur de façon traditionnelle, en fournissant un ContextConfigLocation. Cela fonctionne pour moi, parce que le ApplicationContextConfig que je référence dans le XML ci-dessus s'occupe de tout le reste - y compris la composante de numérisation qui va ramasser toutes mes autres @Configuration fichiers.
Une fois que je l'ai fait, tous mes problèmes ont disparu. J'ai été en mesure de @Autowire la UserDao comme je m'y attendais et tout était merveilleux.
Remarque:
Quand j'ai essayé de définir manuellement des UserDao par la création d'un MapperFactoryBeancomme dans ma question d'origine du code de l'exemple, il y avait un UserDao bean créé, mais il était de type MapperProxy et ne serait pas @Autowire. Cependant, je pourrais l'obtenir pour charger par le nom à l'aide @Référentiel("userDao")pour ce que ça vaut la peine. Je crois que le MapperFactoryBean souffre d'un problème similaire, comme le MapperScannerConfigurer et est tout simplement pas compatible avec @Configuration fichiers, hélas.
De mybatis.3.2.0 et mybatis-printemps.1.2.0,
au lieu de MapperFactoryBean, vous pouvez utiliser MapperScan pour cela.
Une autre solution peut être trouvée dans le jira coché que Jason a mentionné. Résolu mon problème et je n'ai pas eu à utiliser de configuration XML qui j'essaie d'éviter à tout prix...
https://jira.spring.io/browse/SPR-7868
Vous devez avoir un context:component-scan dans votre printemps configurations pour activer la détection automatique de @Composant . De vérifier la référence.