Injecting MyBatis beans
This section will take you through de details of the discovery and injection process.
Producing a Factory
The SqlSessionFactory
is the source of any MyBatis bean so first you need to create one (at least)
and let the container know about it existence. To do so, create a bean with producer method, and make sure
that you add the @ApplicationScoped
annotation to it because we just want to have one instance
of the factory for the whole application.
In order to let the container identify the producers to be used, you must annotate them with @SessionFactoryProvider
.
public class MyProducers {
@Produces
@ApplicationScoped
@SessionFactoryProvider
public SqlSessionFactory produceFactory() {
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
return sqlSessionFactory;
}
}
NOTE
If you forget the @ApplicationScoped
the factory will be created on each injection, what implies
parsing and loading the whole MyBatis xml file set. Your application will not fail but it will be terribly slow.
NOTE
If you forget the @SessionFactoryProvider
the factory will be ignored by mybatis-cdi.
Disvovering and injecting Mappers
There is nothing special more than injecting the mapper as any other CDI dependecy:
public class FooService {
@Inject UserMapper userMapper;
public User doSomeStuff(String userId) {
return this.userMapper.getUser(userId);
}
}
Then it will get an instance (a proxy in fact) of that mapper from the SqlSessionFactory
registered in
the CDI container and inject it into the bean. This proxy is not a normal mapper but a thread safe singleton
so you should not worry about its scope.
Any configuration problem that may happen during the initialization process will make the module throw a
MyBatisCdiConfiurationException
. Given that there is not much to configure, this
exception is only thrown when the SqlSessionFactory
cannot be found or is misconfigured.
Resolving ambiguities
In case you have more than one SqlSessionFactory
you can choose the one you want to use
in any injection point by using:
- One or more qualifiers (defined by you)
- The name of the
SqlSessionFactory
(qualified with@Named
) - Any paranoid combination of both
Follows below an snippet that shows a producer that creates two SqlSessionFactory
s. A qualifier is used
to differentiate them as you would do with any other CDI bean:
@ApplicationScoped
@Produces
@FooQualifier
@SessionFactoryProvider
public SqlSessionFactory createManagerFoo() throws IOException {
...
}
@ApplicationScoped
@Produces
@BarQualifier
@SessionFactoryProvider
public SqlSessionFactory createManagerBar() throws IOException {
...
}
Now that there is no ambiguity you can select what factory you want to inject by adding the qualifier to it:
@Inject @FooQualifier UserMapper userMapper;
You can also give a name to your SqlSessionFactory
:
@ApplicationScoped
@Produces
@Named("fooManager")
@SessionFactoryProvider
public SqlSessionFactory createManager() throws IOException {
...
}
And refer to it by its name in an injection point:
@Inject @Named("fooManager") UserMapper userMapper;
Injecting an SqlSession
You can inject a thread safe SqlSession
by requesting its injection as follows:
@Inject SqlSession sqlSession;
The factory selection criteria we saw for mappers apply also to SqlSession
injection.
NOTE
MyBatis-CDI controls the lifecycle of the injected SqlSession
so you must not call any transactional method
like commit()
or rollback()
, nor any lifecycle method like close()
.