123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596 |
- /**
- * Copyright (c) 2011-2014, hubin (jobob@qq.com).
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
- package com.baomidou.mybatisplus.spring;
- import static org.springframework.util.Assert.notNull;
- import static org.springframework.util.Assert.state;
- import static org.springframework.util.ObjectUtils.isEmpty;
- import static org.springframework.util.StringUtils.hasLength;
- import static org.springframework.util.StringUtils.tokenizeToStringArray;
- import java.io.IOException;
- import java.sql.SQLException;
- import java.util.Properties;
- import javax.sql.DataSource;
- import org.apache.ibatis.builder.xml.XMLMapperBuilder;
- import org.apache.ibatis.cache.Cache;
- import org.apache.ibatis.executor.ErrorContext;
- import org.apache.ibatis.io.VFS;
- import org.apache.ibatis.logging.Log;
- import org.apache.ibatis.logging.LogFactory;
- import org.apache.ibatis.mapping.DatabaseIdProvider;
- import org.apache.ibatis.mapping.Environment;
- import org.apache.ibatis.plugin.Interceptor;
- import org.apache.ibatis.reflection.factory.ObjectFactory;
- import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
- import org.apache.ibatis.session.Configuration;
- import org.apache.ibatis.session.SqlSessionFactory;
- import org.apache.ibatis.session.SqlSessionFactoryBuilder;
- import org.apache.ibatis.transaction.TransactionFactory;
- import org.apache.ibatis.type.TypeHandler;
- import org.mybatis.spring.SqlSessionFactoryBean;
- import org.mybatis.spring.transaction.SpringManagedTransactionFactory;
- import org.springframework.beans.factory.FactoryBean;
- import org.springframework.beans.factory.InitializingBean;
- import org.springframework.context.ApplicationEvent;
- import org.springframework.context.ApplicationListener;
- import org.springframework.context.ConfigurableApplicationContext;
- import org.springframework.context.event.ContextRefreshedEvent;
- import org.springframework.core.NestedIOException;
- import org.springframework.core.io.Resource;
- import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
- import com.baomidou.mybatisplus.MybatisConfiguration;
- import com.baomidou.mybatisplus.MybatisXMLConfigBuilder;
- import com.baomidou.mybatisplus.entity.GlobalConfiguration;
- import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
- import com.baomidou.mybatisplus.mapper.SqlRunner;
- import com.baomidou.mybatisplus.toolkit.PackageHelper;
- /**
- * <p>
- * 拷贝类 org.mybatis.spring.SqlSessionFactoryBean 修改方法 buildSqlSessionFactory()
- * 加载自定义 MybatisXmlConfigBuilder
- * </p>
- *
- * @author hubin
- * @Date 2017-01-04
- */
- public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
- private static final Log LOGGER = LogFactory.getLog(SqlSessionFactoryBean.class);
- private Resource configLocation;
- private Configuration configuration;
- private Resource[] mapperLocations;
- private DataSource dataSource;
- private TransactionFactory transactionFactory;
- private Properties configurationProperties;
- private SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
- private SqlSessionFactory sqlSessionFactory;
- //EnvironmentAware requires spring 3.1
- private String environment = MybatisSqlSessionFactoryBean.class.getSimpleName();
- private boolean failFast;
- private Interceptor[] plugins;
- private TypeHandler<?>[] typeHandlers;
- private String typeHandlersPackage;
- private Class<?>[] typeAliases;
- private String typeAliasesPackage;
- private Class<?> typeAliasesSuperType;
- //issue #19. No default provider.
- private DatabaseIdProvider databaseIdProvider;
- private Class<? extends VFS> vfs;
- private Cache cache;
- private ObjectFactory objectFactory;
- private ObjectWrapperFactory objectWrapperFactory;
- private GlobalConfiguration globalConfig = GlobalConfiguration.defaults();
- // TODO 注入全局配置
- public void setGlobalConfig(GlobalConfiguration globalConfig) {
- this.globalConfig = globalConfig;
- }
- /**
- * Sets the ObjectFactory.
- *
- * @param objectFactory
- * @since 1.1.2
- */
- public void setObjectFactory(ObjectFactory objectFactory) {
- this.objectFactory = objectFactory;
- }
- /**
- * Sets the ObjectWrapperFactory.
- *
- * @param objectWrapperFactory
- * @since 1.1.2
- */
- public void setObjectWrapperFactory(ObjectWrapperFactory objectWrapperFactory) {
- this.objectWrapperFactory = objectWrapperFactory;
- }
- /**
- * Gets the DatabaseIdProvider
- *
- * @return
- * @since 1.1.0
- */
- public DatabaseIdProvider getDatabaseIdProvider() {
- return databaseIdProvider;
- }
- /**
- * Sets the DatabaseIdProvider.
- * As of version 1.2.2 this variable is not initialized by default.
- *
- * @param databaseIdProvider
- * @since 1.1.0
- */
- public void setDatabaseIdProvider(DatabaseIdProvider databaseIdProvider) {
- this.databaseIdProvider = databaseIdProvider;
- }
- public Class<? extends VFS> getVfs() {
- return this.vfs;
- }
- public void setVfs(Class<? extends VFS> vfs) {
- this.vfs = vfs;
- }
- public Cache getCache() {
- return this.cache;
- }
- public void setCache(Cache cache) {
- this.cache = cache;
- }
- /**
- * Mybatis plugin list.
- *
- * @param plugins list of plugins
- * @since 1.0.1
- */
- public void setPlugins(Interceptor[] plugins) {
- this.plugins = plugins;
- }
- /**
- * Packages to search for type aliases.
- *
- * @param typeAliasesPackage package to scan for domain objects
- * @since 1.0.1
- */
- public void setTypeAliasesPackage(String typeAliasesPackage) {
- this.typeAliasesPackage = typeAliasesPackage;
- }
- /**
- * Super class which domain objects have to extend to have a type alias created.
- * No effect if there is no package to scan configured.
- *
- * @param typeAliasesSuperType super class for domain objects
- * @since 1.1.2
- */
- public void setTypeAliasesSuperType(Class<?> typeAliasesSuperType) {
- this.typeAliasesSuperType = typeAliasesSuperType;
- }
- /**
- * Packages to search for type handlers.
- *
- * @param typeHandlersPackage package to scan for type handlers
- * @since 1.0.1
- */
- public void setTypeHandlersPackage(String typeHandlersPackage) {
- this.typeHandlersPackage = typeHandlersPackage;
- }
- /**
- * Set type handlers. They must be annotated with {@code MappedTypes} and optionally with {@code MappedJdbcTypes}
- *
- * @param typeHandlers Type handler list
- * @since 1.0.1
- */
- public void setTypeHandlers(TypeHandler<?>[] typeHandlers) {
- this.typeHandlers = typeHandlers;
- }
- /**
- * List of type aliases to register. They can be annotated with {@code Alias}
- *
- * @param typeAliases Type aliases list
- * @since 1.0.1
- */
- public void setTypeAliases(Class<?>[] typeAliases) {
- this.typeAliases = typeAliases;
- }
- /**
- * If true, a final check is done on Configuration to assure that all mapped
- * statements are fully loaded and there is no one still pending to resolve
- * includes. Defaults to false.
- *
- * @param failFast enable failFast
- * @since 1.0.1
- */
- public void setFailFast(boolean failFast) {
- this.failFast = failFast;
- }
- /**
- * Set the location of the MyBatis {@code SqlSessionFactory} config file. A typical value is
- * "WEB-INF/mybatis-configuration.xml".
- */
- public void setConfigLocation(Resource configLocation) {
- this.configLocation = configLocation;
- }
- /**
- * Set a customized MyBatis configuration.
- *
- * @param configuration MyBatis configuration
- * @since 1.3.0
- */
- public void setConfiguration(Configuration configuration) {
- this.configuration = configuration;
- }
- /**
- * Set locations of MyBatis mapper files that are going to be merged into the {@code SqlSessionFactory}
- * configuration at runtime.
- * <p>
- * This is an alternative to specifying "<sqlmapper>" entries in an MyBatis config file.
- * This property being based on Spring's resource abstraction also allows for specifying
- * resource patterns here: e.g. "classpath*:sqlmap/*-mapper.xml".
- */
- public void setMapperLocations(Resource[] mapperLocations) {
- this.mapperLocations = mapperLocations;
- }
- /**
- * Set optional properties to be passed into the SqlSession configuration, as alternative to a
- * {@code <properties>} tag in the configuration xml file. This will be used to
- * resolve placeholders in the config file.
- */
- public void setConfigurationProperties(Properties sqlSessionFactoryProperties) {
- this.configurationProperties = sqlSessionFactoryProperties;
- }
- /**
- * Set the JDBC {@code DataSource} that this instance should manage transactions for. The {@code DataSource}
- * should match the one used by the {@code SqlSessionFactory}: for example, you could specify the same
- * JNDI DataSource for both.
- * <p>
- * A transactional JDBC {@code Connection} for this {@code DataSource} will be provided to application code
- * accessing this {@code DataSource} directly via {@code DataSourceUtils} or {@code DataSourceTransactionManager}.
- * <p>
- * The {@code DataSource} specified here should be the target {@code DataSource} to manage transactions for, not
- * a {@code TransactionAwareDataSourceProxy}. Only data access code may work with
- * {@code TransactionAwareDataSourceProxy}, while the transaction manager needs to work on the
- * underlying target {@code DataSource}. If there's nevertheless a {@code TransactionAwareDataSourceProxy}
- * passed in, it will be unwrapped to extract its target {@code DataSource}.
- */
- public void setDataSource(DataSource dataSource) {
- if (dataSource instanceof TransactionAwareDataSourceProxy) {
- // If we got a TransactionAwareDataSourceProxy, we need to perform
- // transactions for its underlying target DataSource, else data
- // access code won't see properly exposed transactions (i.e.
- // transactions for the target DataSource).
- this.dataSource = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource();
- } else {
- this.dataSource = dataSource;
- }
- }
- /**
- * Sets the {@code SqlSessionFactoryBuilder} to use when creating the {@code SqlSessionFactory}.
- * <p>
- * This is mainly meant for testing so that mock SqlSessionFactory classes can be injected. By
- * default, {@code SqlSessionFactoryBuilder} creates {@code DefaultSqlSessionFactory} instances.
- */
- public void setSqlSessionFactoryBuilder(SqlSessionFactoryBuilder sqlSessionFactoryBuilder) {
- this.sqlSessionFactoryBuilder = sqlSessionFactoryBuilder;
- }
- /**
- * Set the MyBatis TransactionFactory to use. Default is {@code SpringManagedTransactionFactory}
- * <p>
- * The default {@code SpringManagedTransactionFactory} should be appropriate for all cases:
- * be it Spring transaction management, EJB CMT or plain JTA. If there is no active transaction,
- * SqlSession operations will execute SQL statements non-transactionally.
- * <p>
- * <b>It is strongly recommended to use the default {@code TransactionFactory}.</b> If not used, any
- * attempt at getting an SqlSession through Spring's MyBatis framework will throw an exception if
- * a transaction is active.
- *
- * @param transactionFactory the MyBatis TransactionFactory
- * @see SpringManagedTransactionFactory
- */
- public void setTransactionFactory(TransactionFactory transactionFactory) {
- this.transactionFactory = transactionFactory;
- }
- /**
- * <b>NOTE:</b> This class <em>overrides</em> any {@code Environment} you have set in the MyBatis
- * config file. This is used only as a placeholder name. The default value is
- * {@code SqlSessionFactoryBean.class.getSimpleName()}.
- *
- * @param environment the environment name
- */
- public void setEnvironment(String environment) {
- this.environment = environment;
- }
- /**
- * {@inheritDoc}
- */
- @Override
- public void afterPropertiesSet() throws Exception {
- notNull(dataSource, "Property 'dataSource' is required");
- notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
- state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
- "Property 'configuration' and 'configLocation' can not specified with together");
- this.sqlSessionFactory = buildSqlSessionFactory();
- }
- /**
- * Build a {@code SqlSessionFactory} instance.
- * <p>
- * The default implementation uses the standard MyBatis {@code XMLConfigBuilder} API to build a
- * {@code SqlSessionFactory} instance based on an Reader.
- * Since 1.3.0, it can be specified a {@link Configuration} instance directly(without config file).
- *
- * @return SqlSessionFactory
- * @throws IOException if loading the config file failed
- */
- protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
- Configuration configuration;
- // TODO 加载自定义 MybatisXmlConfigBuilder
- MybatisXMLConfigBuilder xmlConfigBuilder = null;
- if (this.configuration != null) {
- configuration = this.configuration;
- if (configuration.getVariables() == null) {
- configuration.setVariables(this.configurationProperties);
- } else if (this.configurationProperties != null) {
- configuration.getVariables().putAll(this.configurationProperties);
- }
- } else if (this.configLocation != null) {
- xmlConfigBuilder = new MybatisXMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
- configuration = xmlConfigBuilder.getConfiguration();
- } else {
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration");
- }
- // TODO 使用自定义配置
- configuration = new MybatisConfiguration();
- if (this.configurationProperties != null) {
- configuration.setVariables(this.configurationProperties);
- }
- }
- if (this.objectFactory != null) {
- configuration.setObjectFactory(this.objectFactory);
- }
- if (this.objectWrapperFactory != null) {
- configuration.setObjectWrapperFactory(this.objectWrapperFactory);
- }
- if (this.vfs != null) {
- configuration.setVfsImpl(this.vfs);
- }
- if (hasLength(this.typeAliasesPackage)) {
- // TODO 支持自定义通配符
- String[] typeAliasPackageArray;
- if (typeAliasesPackage.contains("*")) {
- typeAliasPackageArray = PackageHelper.convertTypeAliasesPackage(typeAliasesPackage);
- } else {
- typeAliasPackageArray = tokenizeToStringArray(this.typeAliasesPackage,
- ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
- }
- if (typeAliasPackageArray == null) {
- throw new MybatisPlusException("not find typeAliasesPackage:" + typeAliasesPackage);
- }
- for (String packageToScan : typeAliasPackageArray) {
- configuration.getTypeAliasRegistry().registerAliases(packageToScan,
- typeAliasesSuperType == null ? Object.class : typeAliasesSuperType);
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Scanned package: '" + packageToScan + "' for aliases");
- }
- }
- }
- if (!isEmpty(this.typeAliases)) {
- for (Class<?> typeAlias : this.typeAliases) {
- configuration.getTypeAliasRegistry().registerAlias(typeAlias);
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Registered type alias: '" + typeAlias + "'");
- }
- }
- }
- if (!isEmpty(this.plugins)) {
- for (Interceptor plugin : this.plugins) {
- configuration.addInterceptor(plugin);
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Registered plugin: '" + plugin + "'");
- }
- }
- }
- if (hasLength(this.typeHandlersPackage)) {
- String[] typeHandlersPackageArray = tokenizeToStringArray(this.typeHandlersPackage,
- ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
- for (String packageToScan : typeHandlersPackageArray) {
- configuration.getTypeHandlerRegistry().register(packageToScan);
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Scanned package: '" + packageToScan + "' for type handlers");
- }
- }
- }
- if (!isEmpty(this.typeHandlers)) {
- for (TypeHandler<?> typeHandler : this.typeHandlers) {
- configuration.getTypeHandlerRegistry().register(typeHandler);
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Registered type handler: '" + typeHandler + "'");
- }
- }
- }
- if (this.databaseIdProvider != null) {//fix #64 set databaseId before parse mapper xmls
- try {
- configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
- } catch (SQLException e) {
- throw new NestedIOException("Failed getting a databaseId", e);
- }
- }
- if (this.cache != null) {
- configuration.addCache(this.cache);
- }
- if (xmlConfigBuilder != null) {
- try {
- xmlConfigBuilder.parse();
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Parsed configuration file: '" + this.configLocation + "'");
- }
- } catch (Exception ex) {
- throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);
- } finally {
- ErrorContext.instance().reset();
- }
- }
- if (this.transactionFactory == null) {
- this.transactionFactory = new SpringManagedTransactionFactory();
- }
- configuration.setEnvironment(new Environment(this.environment, this.transactionFactory, this.dataSource));
- // 设置元数据相关
- GlobalConfiguration.setMetaData(dataSource, globalConfig);
- SqlSessionFactory sqlSessionFactory = this.sqlSessionFactoryBuilder.build(configuration);
- // TODO SqlRunner
- SqlRunner.FACTORY = sqlSessionFactory;
- // TODO 缓存 sqlSessionFactory
- globalConfig.setSqlSessionFactory(sqlSessionFactory);
- // TODO 设置全局参数属性
- globalConfig.signGlobalConfig(sqlSessionFactory);
- if (!isEmpty(this.mapperLocations)) {
- if (globalConfig.isRefresh()) {
- //TODO 设置自动刷新配置 减少配置
- new MybatisMapperRefresh(sqlSessionFactory, 2,
- 2, true);
- }
- for (Resource mapperLocation : this.mapperLocations) {
- if (mapperLocation == null) {
- continue;
- }
- try {
- // TODO 这里也换了噢噢噢噢
- XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
- configuration, mapperLocation.toString(), configuration.getSqlFragments());
- xmlMapperBuilder.parse();
- } catch (Exception e) {
- throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
- } finally {
- ErrorContext.instance().reset();
- }
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Parsed mapper file: '" + mapperLocation + "'");
- }
- }
- } else {
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Property 'mapperLocations' was not specified or no matching resources found");
- }
- }
- return sqlSessionFactory;
- }
- /**
- * {@inheritDoc}
- */
- @Override
- public SqlSessionFactory getObject() throws Exception {
- if (this.sqlSessionFactory == null) {
- afterPropertiesSet();
- }
- return this.sqlSessionFactory;
- }
- /**
- * {@inheritDoc}
- */
- @Override
- public Class<? extends SqlSessionFactory> getObjectType() {
- return this.sqlSessionFactory == null ? SqlSessionFactory.class : this.sqlSessionFactory.getClass();
- }
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean isSingleton() {
- return true;
- }
- /**
- * {@inheritDoc}
- */
- @Override
- public void onApplicationEvent(ApplicationEvent event) {
- if (failFast && event instanceof ContextRefreshedEvent) {
- // fail-fast -> check all statements are completed
- this.sqlSessionFactory.getConfiguration().getMappedStatementNames();
- }
- }
- }
|