Introduction
Core components are contained in the org.mybatis.guice.* package, providing a set of reusable Google Guice jakarta.inject.Providers and com.google.inject.Modules that alleviate users the task to create MyBatis objects.
MyBatis Bootstrap
MyBatis offers an excellent APIs layer for the Bootstrap configuration that makes it easy to write custom bootstrap - by default MyBatis comes with the XML loader - and integrating 3rd part components.
The core component of the Guice approach is represented by the org.mybatis.guice.MyBatisModule that's able to create the core MyBatis org.apache.ibatis.session.SqlSessionFactory, org.apache.ibatis.session.SqlSessionManager and the user defined Mappers.
The best way to start is just adding the org.mybatis.guice.MyBatisModule into the com.google.inject.Injector as shown in the example below and explain details step by step:
Class<? extends Provider<DataSource>> dataSourceProviderType = [...];
Class<? extends TransactionFactory> txFactoryClass = [...];
Injector injector = Guice.createInjector(
new MyBatisModule() {
@Override
protected void initialize() {
environmentId("development");
bindDataSourceProviderType(dataSourceProviderType);
bindTransactionFactoryType(txFactoryClass);
}
},
...
);
SqlSessionFactory sessionFactory = injector.getInstance(SqlSessionFactory.class);
SqlSessionManager sessionManager = injector.getInstance(SqlSessionManager.class);
MyMapper mapper = injector.getInstance(MyMapper.class);
Let's have a look now at the MyBatis module components and features:
MyBatis properties
By design, we choose to reuse the default configuration properties provided by Guice to let users feel free to read and set them in any way you prefer; we suggest to put it in a properties file, maybe filtered and set depending on which environment users are building the application.
By default, if a configuration property is not specified, it will be ignored and MyBatis will take care about proper default initialization. Users can initialize properties using the proper setters OR by following method (please don't bind properties twice!):
binder.bindConstant()
.annotatedWith(Names.named("mybatis.configuration.XXX"))
.to(XXXvalue);
The MyBatis module supports the following parameters:
Property | Setter | Default |
---|---|---|
mybatis.environment.id | environmentId(String) | Not set, it is required |
mybatis.configuration.lazyLoadingEnabled | lazyLoadingEnabled(boolean) | false |
mybatis.configuration.aggressiveLazyLoading | aggressiveLazyLoading(boolean) | true |
mybatis.configuration.multipleResultSetsEnabled | multipleResultSetsEnabled(boolean) | true |
mybatis.configuration.useGeneratedKeys | useGeneratedKeys(boolean) | false |
mybatis.configuration.useColumnLabel | useColumnLabel(boolean) | true |
mybatis.configuration.cacheEnabled | useCacheEnabled(boolean) | true |
mybatis.configuration.defaultExecutorType | executorType(ExecutorType) | ExecutorType.SIMPLE |
mybatis.configuration.autoMappingBehavior | autoMappingBehavior(AutoMappingBehavior) | AutoMappingBehavior.PARTIAL |
mybatis.configuration.failFast | failFast(boolean) | false |
The DataSource Provider
The javax.sql.DataSource Provider is one of the two required providers that takes care about building and injecting the used javax.sql.DataSource.
The mybatis-guice framework comes with some providers that support the MyBatis-native Data Sources and other well known Data Sources, C3P0, Apache Commons DBCP and HikariCP but users are free to implement their own javax.sql.DataSource Provider and reference it in the org.mybatis.guice.MyBatisModule.
Please read the following chapter Data Source Providers to obtain more informations about natively supported providers.
The Transaction Factory
Users are free to plug their preferred org.apache.ibatis.transaction.TransactionFactory:
Class<? extends org.apache.ibatis.transaction.TransactionFactory> txFactoryType = ...
Module module = new MyBatisModule() {
@Override
protected void initialize() {
...
bindTransactionFactoryType(txFactoryType);
...
}
}
Configuring aliases
Once users create the org.mybatis.guice.MyBatisModule.Builder, it's quite easy plugging optional MyBatis components, like aliases: here users can define simple aliases, for example Foo that stands for com.acme.Foo, or custom aliases, for example MyFoo that stands for com.acme.Foo.
We found it very useful to add simple aliases because it helped us reduce errors during development; just call:
MyBatisModule module = new MyBatisModule() {
@Override
protected void initialize() {
...
addSimpleAlias(com.acme.Foo.class);
addSimpleAlias(com.acme.Bar.class);
addSimpleAlias(...);
...
}
}
If you prefer custom aliases, just invoke:
MyBatisModule module = new MyBatisModule() {
@Override
protected void initialize() {
...
addAlias("MyFoo").to(com.acme.Foo.class);
addAlias("MyBar").to(com.acme.Bar.class);
...
}
}
Configuring Type Handlers
Users can also configure type handlers: given the com.acme.Foo type, that has to be handled by the type handler com.acme.dao.FooHandler, just invoke
MyBatisModule module = new MyBatisModule() {
@Override
protected void initialize() {
...
handleType(com.acme.Foo.class).with(com.acme.dao.FooHandler.class);
handleType(com.acme.Bar.class).with(com.acme.dao.BarHandler.class);
...
}
}
and let Google Guice create the handlers instances and bind them to be injected to MyBatis components.
Constructor injection will not work, so use field or setter injection for type handler dependencies.
Configuring Interceptor Plugins
Users can easily add their preferred org.apache.ibatis.plugin.Interceptor by invoking:
MyBatisModule module = new MyBatisModule() {
@Override
protected void initialize() {
...
addInterceptorClass(com.acme.dao.FooInterceptor.class);
addInterceptorClass(com.acme.dao.BarInterceptor.class);
...
}
}
and let Google Guice create the interceptors instances and bind them to be injected to MyBatis components.
Configuring Mappers
Users can add Mapper classes to the module by invoking:
MyBatisModule module = new MyBatisModule() {
@Override
protected void initialize() {
...
addMapperClass(com.acme.dao.FooMapper.class);
addMapperClass(com.acme.dao.BarMapper.class);
...
}
};
and let Google Guice create the mappers instance and bind them to be injected to MyBatis components.
Configuring the Object Factory
Simply define your own org.apache.ibatis.reflection.factory.ObjectFactory and communicate it to the module and let Google Guice create it:
MyBatisModule module = new MyBatisModule() {
@Override
protected void initialize() {
...
bindObjectFactoryType(com.acme.MyObjectFactory.class);
...
}
};
Multiple Datasources
It often happens that users need to interact with multiple schemas in the same application, that means to have separate MyBatis configurations.
Fortunately, the Google Guice com.google.inject.PrivateModule comes to help us in a very simple and smart way, that will be shown in the following example.
Let's take in consideration, to simplify the example, we have only two datasources (but the same concept can be extended for an arbitrary data sources number) one for the contacts schema and another one for the companies schema. So, all it has to do is installing the org.mybatis.guice.MyBatisModule modules into the Google Guice com.google.inject.PrivateModule as shown below:
Injector injector = Guice.createInjector(
new PrivateModule() {
@Override
protected void configure() {
install(new MyBatisModule() {
@Override
protected void initialize() {
bindDataSourceProviderType(PooledDataSourceProvider.class);
bindTransactionFactoryType(JdbcTransactionFactory.class);
addMapperClass(ContactMapper.class);
addSimpleAlias(Contact.class);
}
});
Names.bindProperties(this.binder(),
getConnectionProperties("contacts"));
// binds Mappers/DAOs here
bind(ContactDao.class).to(ContactDaoImpl.class);
...
// exposes Mappers/DAOs here
expose(ContactDao.class);
...
}
}, new PrivateModule() {
@Override
protected void configure() {
install(new MyBatisModule() {
@Override
protected void initialize() {
bindDataSourceProviderType(PooledDataSourceProvider.class);
bindTransactionFactoryType(JdbcTransactionFactory.class);
}
});
Names.bindProperties(this.binder(),
getConnectionProperties("trades"));
// binds Mappers/DAOs here
bind(CompanyDao.class).to(CompanyDaoImpl.class);
...
// exposes Mappers/DAOs here
expose(CompanyDao.class);
...
}
}
);
The example shows how to use the org.mybatis.guice.MyBatisModule to create two different MyBatis configurations in the same context. Feel free to implement the getConnectionProperties() method in the way you prefer! It could be, for example:
private final static Properties getConnectionProperties(String schema) {
final Properties myBatisProperties = new Properties();
myBatisProperties.setProperty("mybatis.environment.id", "test");
myBatisProperties.setProperty("JDBC.driver",
"org.apache.derby.jdbc.EmbeddedDriver");
myBatisProperties.setProperty("JDBC.url",
"jdbc:mysql://localhost:3306/" + schema);
myBatisProperties.setProperty("JDBC.username", "mybatis-user");
myBatisProperties.setProperty("JDBC.password", "changeme");
myBatisProperties.setProperty("JDBC.autoCommit", "true");
return myBatisProperties;
}
MyBatis XML Bootstrap
Users that want configure the MyBatis via the XML configuration, without loosing any single feature of the org.mybatis.guice.MyBatisModule, can create their Injector using the org.mybatis.guice.XMLMyBatisModule.
XMLMyBatisModule clients have just to instantiate it specifying
-
the MyBatis XML configuration file, located in the classpath, by default the module will look for mybatis-config.xml in the root in the classpath;
-
the optional MyBatis environmentId, defaults to the default attribute of <environments> element;
-
the optional java.util.Properties to fill placeholders in the MyBatis XML configuration, empty by default.
A typical use case could be identified in the following code snippet:
Properties props = new Properties();
props.setProperty("JDBC.username", "mybatis-user");
props.setProperty("JDBC.password", "changeme");
Injector injector = Guice.createInjector(
new XMLMyBatisModule() {
@Override
protected void initialize() {
setEnvironmentId("test");
setClassPathResource("my/path/to/mybatis-config.xml");
addProperties(props);
}
},
...
);
Important Google Guice will inject dependencies, if required, in the TypeHandlers and Interceptors.