当前位置: 首页 > news >正文

Mybatis-plus 源码解读

简述

本篇主要针对MybatisPlus源码进行解读。

案例

上一篇已经讲了Springboot如何集成MybatisPlus:
springboot-mybatis-plus集成篇

源码解析

和Springboot集成Mybatis一样,
在这里插入图片描述
依赖了mybatis-plus-spring-boot3-starter,其中主要关注spring.factories和org.springframework.boot.autoconfigure.AutoConfiguration.imports

spring.factories

# Auto Configure
org.springframework.boot.env.EnvironmentPostProcessor=\com.baomidou.mybatisplus.autoconfigure.SafetyEncryptProcessor
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.baomidou.mybatisplus.autoconfigure.MybatisPlusInnerInterceptorAutoConfiguration,\com.baomidou.mybatisplus.autoconfigure.IdentifierGeneratorAutoConfiguration,\com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration,\com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration,\com.baomidou.mybatisplus.autoconfigure.DdlAutoConfiguration
# Depends On Database Initialization Detectors
org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector=\
com.baomidou.mybatisplus.autoconfigure.MybatisDependsOnDatabaseInitializationDetector

org.springframework.boot.autoconfigure.AutoConfiguration.imports

com.baomidou.mybatisplus.autoconfigure.MybatisPlusInnerInterceptorAutoConfiguration
com.baomidou.mybatisplus.autoconfigure.IdentifierGeneratorAutoConfiguration
com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration
com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration
com.baomidou.mybatisplus.autoconfigure.DdlAutoConfiguration

MybatisPlusInnerInterceptorAutoConfiguration:拦截器自动配置,主要用来扩展插件功能,例如mybatis分页组件,mybatis-plus中的租户组件
MybatisPlusAutoConfiguration: 这个自动配置类和Mybatis-starter中的MybatisAutoConfiguration功能作用是一样的

MybatisPlusInnerInterceptorAutoConfiguration.java

@Configuration(proxyBeanMethods = false
)
@ConditionalOnBean({InnerInterceptor.class})
@ConditionalOnMissingBean({MybatisPlusInterceptor.class})
public class MybatisPlusInnerInterceptorAutoConfiguration {public MybatisPlusInnerInterceptorAutoConfiguration() {}@Beanpublic MybatisPlusInterceptor defaultMybatisPlusInterceptor(List<InnerInterceptor> innerInterceptorList) {MybatisPlusInterceptor plusInterceptor = new MybatisPlusInterceptor();plusInterceptor.setInterceptors(innerInterceptorList);return plusInterceptor;}
}

MybatisAutoConfiguration.java

Configuration(proxyBeanMethods = false)
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(MybatisPlusProperties.class)
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisPlusLanguageDriverAutoConfiguration.class})
public class MybatisPlusAutoConfiguration implements InitializingBean {private static final Logger logger = LoggerFactory.getLogger(MybatisPlusAutoConfiguration.class);private final MybatisPlusProperties properties;private final Interceptor[] interceptors;private final TypeHandler[] typeHandlers;private final LanguageDriver[] languageDrivers;private final ResourceLoader resourceLoader;private final DatabaseIdProvider databaseIdProvider;private final List<ConfigurationCustomizer> configurationCustomizers;private final List<SqlSessionFactoryBeanCustomizer> sqlSessionFactoryBeanCustomizers;private final List<MybatisPlusPropertiesCustomizer> mybatisPlusPropertiesCustomizers;private final ApplicationContext applicationContext;public MybatisPlusAutoConfiguration(MybatisPlusProperties properties,ObjectProvider<Interceptor[]> interceptorsProvider,ObjectProvider<TypeHandler[]> typeHandlersProvider,ObjectProvider<LanguageDriver[]> languageDriversProvider,ResourceLoader resourceLoader,ObjectProvider<DatabaseIdProvider> databaseIdProvider,ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider,ObjectProvider<List<SqlSessionFactoryBeanCustomizer>> sqlSessionFactoryBeanCustomizers,ObjectProvider<List<MybatisPlusPropertiesCustomizer>> mybatisPlusPropertiesCustomizerProvider,ApplicationContext applicationContext) {this.properties = properties;this.interceptors = interceptorsProvider.getIfAvailable();this.typeHandlers = typeHandlersProvider.getIfAvailable();this.languageDrivers = languageDriversProvider.getIfAvailable();this.resourceLoader = resourceLoader;this.databaseIdProvider = databaseIdProvider.getIfAvailable();this.configurationCustomizers = configurationCustomizersProvider.getIfAvailable();this.sqlSessionFactoryBeanCustomizers = sqlSessionFactoryBeanCustomizers.getIfAvailable();this.mybatisPlusPropertiesCustomizers = mybatisPlusPropertiesCustomizerProvider.getIfAvailable();this.applicationContext = applicationContext;}@Overridepublic void afterPropertiesSet() {if (!CollectionUtils.isEmpty(mybatisPlusPropertiesCustomizers)) {mybatisPlusPropertiesCustomizers.forEach(i -> i.customize(properties));}checkConfigFileExists();}private void checkConfigFileExists() {if (this.properties.isCheckConfigLocation() && StringUtils.hasText(this.properties.getConfigLocation())) {Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation());Assert.state(resource.exists(),"Cannot find config location: " + resource + " (please add config file or check your Mybatis configuration)");}}/*** 和Springboot集成Mybatis很相似,需要定义SqlSessionFactory Bean* @param dataSource* @return* @throws Exception*/@Bean@ConditionalOnMissingBeanpublic SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {// MybatisPlus自定义了MybatisSqlSessionFactoryBeanMybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();factory.setDataSource(dataSource);factory.setVfs(SpringBootVFS.class);if (StringUtils.hasText(this.properties.getConfigLocation())) {factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));}// 应用Mybatis相关配置,这里和Mybatis是有一些区别applyConfiguration(factory);if (this.properties.getConfigurationProperties() != null) {factory.setConfigurationProperties(this.properties.getConfigurationProperties());}if (!ObjectUtils.isEmpty(this.interceptors)) {factory.setPlugins(this.interceptors);}if (this.databaseIdProvider != null) {factory.setDatabaseIdProvider(this.databaseIdProvider);}if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());}if (this.properties.getTypeAliasesSuperType() != null) {factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());}if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());}if (!ObjectUtils.isEmpty(this.typeHandlers)) {factory.setTypeHandlers(this.typeHandlers);}if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {factory.setMapperLocations(this.properties.resolveMapperLocations());}this.getBeanThen(TransactionFactory.class, factory::setTransactionFactory);Class<? extends LanguageDriver> defaultLanguageDriver = this.properties.getDefaultScriptingLanguageDriver();if (!ObjectUtils.isEmpty(this.languageDrivers)) {factory.setScriptingLanguageDrivers(this.languageDrivers);}Optional.ofNullable(defaultLanguageDriver).ifPresent(factory::setDefaultScriptingLanguageDriver);applySqlSessionFactoryBeanCustomizers(factory);// 增加了全局配置GlobalConfig globalConfig = this.properties.getGlobalConfig();this.getBeanThen(MetaObjectHandler.class, globalConfig::setMetaObjectHandler);this.getBeanThen(AnnotationHandler.class, globalConfig::setAnnotationHandler);this.getBeanThen(PostInitTableInfoHandler.class, globalConfig::setPostInitTableInfoHandler);this.getBeansThen(IKeyGenerator.class, i -> globalConfig.getDbConfig().setKeyGenerators(i));this.getBeanThen(ISqlInjector.class, globalConfig::setSqlInjector);this.getBeanThen(IdentifierGenerator.class, globalConfig::setIdentifierGenerator);factory.setGlobalConfig(globalConfig);return factory.getObject();}/*** 检查spring容器里是否有对应的bean,有则进行消费** @param clazz    class* @param consumer 消费* @param <T>      泛型*/private <T> void getBeanThen(Class<T> clazz, Consumer<T> consumer) {if (this.applicationContext.getBeanNamesForType(clazz, false, false).length > 0) {consumer.accept(this.applicationContext.getBean(clazz));}}/*** 检查spring容器里是否有对应的bean,有则进行消费** @param clazz    class* @param consumer 消费* @param <T>      泛型*/private <T> void getBeansThen(Class<T> clazz, Consumer<List<T>> consumer) {if (this.applicationContext.getBeanNamesForType(clazz, false, false).length > 0) {final Map<String, T> beansOfType = this.applicationContext.getBeansOfType(clazz);List<T> clazzList = new ArrayList<>();beansOfType.forEach((k, v) -> clazzList.add(v));consumer.accept(clazzList);}}private void applyConfiguration(MybatisSqlSessionFactoryBean factory) {MybatisPlusProperties.CoreConfiguration coreConfiguration = this.properties.getConfiguration();MybatisConfiguration configuration = null;// 如果没有相关Mybatis配置文件,则使用MybatisPlus自定的MybatisConfiguration配置,而MybatisConfiguration是继承Configuration类if (coreConfiguration != null || !StringUtils.hasText(this.properties.getConfigLocation())) {configuration = new MybatisConfiguration();}if (configuration != null && coreConfiguration != null) {// 增加mybatisPlus核心配置coreConfiguration.applyTo(configuration);}if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {for (ConfigurationCustomizer customizer : this.configurationCustomizers) {customizer.customize(configuration);}}factory.setConfiguration(configuration);}private void applySqlSessionFactoryBeanCustomizers(MybatisSqlSessionFactoryBean factory) {if (!CollectionUtils.isEmpty(this.sqlSessionFactoryBeanCustomizers)) {for (SqlSessionFactoryBeanCustomizer customizer : this.sqlSessionFactoryBeanCustomizers) {customizer.customize(factory);}}}@Bean@ConditionalOnMissingBeanpublic SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {ExecutorType executorType = this.properties.getExecutorType();if (executorType != null) {return new SqlSessionTemplate(sqlSessionFactory, executorType);} else {return new SqlSessionTemplate(sqlSessionFactory);}}/*** 自动扫描器和Mybatis的相似,扫描Mapper,自动注入SpringContext,不过Mapper自动扫描出来代理生成的Bean是MybatisSqlSessionFactoryBean类型的,* 而不是之前Mybatis中的SqlSessionFactoryBean,这是区别* This will just scan the same base package as Spring Boot does. If you want more power, you can explicitly use* {@link org.mybatis.spring.annotation.MapperScan} but this will get typed mappers working correctly, out-of-the-box,* similar to using Spring Data JPA repositories.*/public static class AutoConfiguredMapperScannerRegistrarimplements BeanFactoryAware, EnvironmentAware, ImportBeanDefinitionRegistrar {private BeanFactory beanFactory;private Environment environment;@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {if (!AutoConfigurationPackages.has(this.beanFactory)) {logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.");return;}logger.debug("Searching for mappers annotated with @Mapper");List<String> packages = AutoConfigurationPackages.get(this.beanFactory);if (logger.isDebugEnabled()) {packages.forEach(pkg -> logger.debug("Using auto-configuration base package '{}'", pkg));}BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);builder.addPropertyValue("processPropertyPlaceHolders", true);builder.addPropertyValue("annotationClass", Mapper.class);builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(packages));BeanWrapper beanWrapper = new BeanWrapperImpl(MapperScannerConfigurer.class);Set<String> propertyNames = Stream.of(beanWrapper.getPropertyDescriptors()).map(PropertyDescriptor::getName).collect(Collectors.toSet());if (propertyNames.contains("lazyInitialization")) {// Need to mybatis-spring 2.0.2+builder.addPropertyValue("lazyInitialization", "${mybatis-plus.lazy-initialization:${mybatis.lazy-initialization:false}}");}if (propertyNames.contains("defaultScope")) {// Need to mybatis-spring 2.0.6+builder.addPropertyValue("defaultScope", "${mybatis-plus.mapper-default-scope:}");}// for spring-nativeBoolean injectSqlSession = environment.getProperty("mybatis-plus.inject-sql-session-on-mapper-scan", Boolean.class);if (injectSqlSession == null) {injectSqlSession = environment.getProperty("mybatis.inject-sql-session-on-mapper-scan", Boolean.class, Boolean.TRUE);}if (injectSqlSession && this.beanFactory instanceof ListableBeanFactory) {ListableBeanFactory listableBeanFactory = (ListableBeanFactory) this.beanFactory;Optional<String> sqlSessionTemplateBeanName = Optional.ofNullable(getBeanNameForType(SqlSessionTemplate.class, listableBeanFactory));// 获取MybatisPlus定义的SqlSessionFactory,其中的sqlSessionFactoryBeanName=MybatisSqlSessionFactoryBeanOptional<String> sqlSessionFactoryBeanName = Optional.ofNullable(getBeanNameForType(SqlSessionFactory.class, listableBeanFactory));if (sqlSessionTemplateBeanName.isPresent() || !sqlSessionFactoryBeanName.isPresent()) {builder.addPropertyValue("sqlSessionTemplateBeanName",sqlSessionTemplateBeanName.orElse("sqlSessionTemplate"));} else {builder.addPropertyValue("sqlSessionFactoryBeanName", sqlSessionFactoryBeanName.get());}}builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition());}@Overridepublic void setBeanFactory(BeanFactory beanFactory) {this.beanFactory = beanFactory;}@Overridepublic void setEnvironment(Environment environment) {this.environment = environment;}private String getBeanNameForType(Class<?> type, ListableBeanFactory factory) {String[] beanNames = factory.getBeanNamesForType(type);return beanNames.length > 0 ? beanNames[0] : null;}}/*** If mapper registering configuration or mapper scanning configuration not present, this configuration allow to scan* mappers based on the same component-scanning path as Spring Boot itself.*/@org.springframework.context.annotation.Configuration(proxyBeanMethods = false)@Import(AutoConfiguredMapperScannerRegistrar.class)@ConditionalOnMissingBean({MapperFactoryBean.class, MapperScannerConfigurer.class})public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {@Overridepublic void afterPropertiesSet() {logger.debug("Not found configuration for registering mapper bean using @MapperScan, MapperFactoryBean and MapperScannerConfigurer.");}}}

MapperFactoryBean.java

public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {private Class<T> mapperInterface;private boolean addToConfig = true;public MapperFactoryBean() {}public MapperFactoryBean(Class<T> mapperInterface) {this.mapperInterface = mapperInterface;}protected void checkDaoConfig() {super.checkDaoConfig();Assert.notNull(this.mapperInterface, "Property 'mapperInterface' is required");Configuration configuration = this.getSqlSession().getConfiguration();if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {try {// 这个是MybatisConfigurationconfiguration.addMapper(this.mapperInterface);} catch (Exception var6) {this.logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", var6);throw new IllegalArgumentException(var6);} finally {ErrorContext.instance().reset();}}}public T getObject() throws Exception {return this.getSqlSession().getMapper(this.mapperInterface);}public Class<T> getObjectType() {return this.mapperInterface;}public boolean isSingleton() {return true;}public void setMapperInterface(Class<T> mapperInterface) {this.mapperInterface = mapperInterface;}public Class<T> getMapperInterface() {return this.mapperInterface;}public void setAddToConfig(boolean addToConfig) {this.addToConfig = addToConfig;}public boolean isAddToConfig() {return this.addToConfig;}
}

MybatisConfiguration.java

/** Copyright (c) 2011-2024, baomidou (jobob@qq.com).** 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**     http://www.apache.org/licenses/LICENSE-2.0** 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.core;import com.baomidou.mybatisplus.core.handlers.CompositeEnumTypeHandler;
import com.baomidou.mybatisplus.core.mapper.Mapper;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import lombok.Getter;
import lombok.Setter;
import org.apache.ibatis.binding.MapperRegistry;
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMap;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.parsing.XNode;
import org.apache.ibatis.scripting.LanguageDriver;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.transaction.Transaction;
import org.apache.ibatis.type.TypeHandler;import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;
import java.util.stream.Collectors;/*** replace default Configuration class* <p>Caratacus 2016/9/25 replace mapperRegistry</p>** @author hubin* @since 2016-01-23*/
public class MybatisConfiguration extends Configuration {private static final Log logger = LogFactory.getLog(MybatisConfiguration.class);/*** Mapper 注册*/protected final MybatisMapperRegistry mybatisMapperRegistry = new MybatisMapperRegistry(this);protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");protected final Map<String, ResultMap> resultMaps = new StrictMap<>("Result Maps collection");protected final Map<String, ParameterMap> parameterMaps = new StrictMap<>("Parameter Maps collection");protected final Map<String, KeyGenerator> keyGenerators = new StrictMap<>("Key Generators collection");protected final Map<String, XNode> sqlFragments = new StrictMap<>("XML fragments parsed from previous mappers");protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection").conflictMessageProducer((savedValue, targetValue) ->". please check " + savedValue.getResource() + " and " + targetValue.getResource());/*** 是否生成短key缓存** @since 3.4.0*/@Setter@Getterprivate boolean useGeneratedShortKey = true;public MybatisConfiguration(Environment environment) {this();this.environment = environment;}/*** 初始化调用*/public MybatisConfiguration() {super();this.mapUnderscoreToCamelCase = true;typeHandlerRegistry.setDefaultEnumTypeHandler(CompositeEnumTypeHandler.class);languageRegistry.setDefaultDriverClass(MybatisXMLLanguageDriver.class);}/*** MybatisPlus 加载 SQL 顺序:* <p> 1、加载 XML中的 SQL </p>* <p> 2、加载 SqlProvider 中的 SQL </p>* <p> 3、XmlSql 与 SqlProvider不能包含相同的 SQL </p>* <p>调整后的 SQL优先级:XmlSql > sqlProvider > CurdSql </p>*/@Overridepublic void addMappedStatement(MappedStatement ms) {if (mappedStatements.containsKey(ms.getId())) {/** 说明已加载了xml中的节点; 忽略mapper中的 SqlProvider 数据*/logger.error("mapper[" + ms.getId() + "] is ignored, because it exists, maybe from xml file");return;}mappedStatements.put(ms.getId(), ms);}/*** 使用自己的 MybatisMapperRegistry*/@Overridepublic MapperRegistry getMapperRegistry() {return mybatisMapperRegistry;}/*** 使用自己的 MybatisMapperRegistry*/@Overridepublic <T> void addMapper(Class<T> type) {mybatisMapperRegistry.addMapper(type);}/*** 新增注入新的 Mapper 信息,新增前会清理之前的缓存信息** @param type Mapper Type* @deprecated 3.5.8 不建议在实际生产环境中使用.*/@Deprecatedpublic <T> void addNewMapper(Class<T> type) {this.removeMapper(type);this.addMapper(type);}/*** 移除 Mapper 相关缓存,支持 GroovyClassLoader 动态注入 Mapper** @param type Mapper Type* @deprecated 3.5.8 不建议在实际生产环境中使用.*/@Deprecatedpublic <T> void removeMapper(Class<T> type) {Set<String> mapperRegistryCache = GlobalConfigUtils.getGlobalConfig(this).getMapperRegistryCache();final String mapperType = type.toString();if (mapperRegistryCache.contains(mapperType)) {// 清空实体表信息映射信息TableInfoHelper.remove(ReflectionKit.getSuperClassGenericType(type, Mapper.class, 0));// 清空 Mapper 缓存信息this.mybatisMapperRegistry.removeMapper(type);this.loadedResources.remove(type.toString());this.loadedResources.remove(type.getName().replace(StringPool.DOT, StringPool.SLASH) + ".xml");mapperRegistryCache.remove(mapperType);// 清空 Mapper 方法 mappedStatement 缓存信息String typeKey = type.getName() + StringPool.DOT;String simpleName = type.getSimpleName();mappedStatements.keySet().stream().filter(ms -> ms.startsWith(typeKey) || ms.equals(simpleName)).collect(Collectors.toSet()).forEach(mappedStatements::remove);resultMaps.keySet().stream().filter(r -> r.startsWith(typeKey)).collect(Collectors.toSet()).forEach(resultMaps::remove);parameterMaps.keySet().stream().filter(p -> p.startsWith(typeKey)).collect(Collectors.toSet()).forEach(parameterMaps::remove);keyGenerators.keySet().stream().filter(k -> k.startsWith(typeKey)).collect(Collectors.toSet()).forEach(keyGenerators::remove);sqlFragments.keySet().stream().filter(s -> s.startsWith(typeKey)).collect(Collectors.toSet()).forEach(sqlFragments::remove);caches.keySet().stream().filter(p -> p.equals(type.getName()) || p.equals(simpleName)).collect(Collectors.toSet()).forEach(caches::remove);}}/*** 使用自己的 MybatisMapperRegistry*/@Overridepublic void addMappers(String packageName, Class<?> superType) {mybatisMapperRegistry.addMappers(packageName, superType);}/*** 使用自己的 MybatisMapperRegistry*/@Overridepublic void addMappers(String packageName) {mybatisMapperRegistry.addMappers(packageName);}/*** 使用自己的 MybatisMapperRegistry*/@Overridepublic <T> T getMapper(Class<T> type, SqlSession sqlSession) {return mybatisMapperRegistry.getMapper(type, sqlSession);}/*** 使用自己的 MybatisMapperRegistry*/@Overridepublic boolean hasMapper(Class<?> type) {return mybatisMapperRegistry.hasMapper(type);}/*** 指定动态SQL生成的默认语言** @param driver LanguageDriver*/@Overridepublic void setDefaultScriptingLanguage(Class<? extends LanguageDriver> driver) {if (driver == null) {driver = MybatisXMLLanguageDriver.class;}getLanguageRegistry().setDefaultDriverClass(driver);}@Overridepublic void setDefaultEnumTypeHandler(Class<? extends TypeHandler> typeHandler) {if (typeHandler != null) {CompositeEnumTypeHandler.setDefaultEnumTypeHandler(typeHandler);}}@Overridepublic void addKeyGenerator(String id, KeyGenerator keyGenerator) {keyGenerators.put(id, keyGenerator);}@Overridepublic Collection<String> getKeyGeneratorNames() {return keyGenerators.keySet();}@Overridepublic Collection<KeyGenerator> getKeyGenerators() {return keyGenerators.values();}@Overridepublic KeyGenerator getKeyGenerator(String id) {return keyGenerators.get(id);}@Overridepublic boolean hasKeyGenerator(String id) {return keyGenerators.containsKey(id);}@Overridepublic void addCache(Cache cache) {caches.put(cache.getId(), cache);}@Overridepublic Collection<String> getCacheNames() {return caches.keySet();}@Overridepublic Collection<Cache> getCaches() {return caches.values();}@Overridepublic Cache getCache(String id) {return caches.get(id);}@Overridepublic boolean hasCache(String id) {return caches.containsKey(id);}@Overridepublic void addResultMap(ResultMap rm) {resultMaps.put(rm.getId(), rm);checkLocallyForDiscriminatedNestedResultMaps(rm);checkGloballyForDiscriminatedNestedResultMaps(rm);}@Overridepublic Collection<String> getResultMapNames() {return resultMaps.keySet();}@Overridepublic Collection<ResultMap> getResultMaps() {return resultMaps.values();}@Overridepublic ResultMap getResultMap(String id) {return resultMaps.get(id);}@Overridepublic boolean hasResultMap(String id) {return resultMaps.containsKey(id);}@Overridepublic void addParameterMap(ParameterMap pm) {parameterMaps.put(pm.getId(), pm);}@Overridepublic Collection<String> getParameterMapNames() {return parameterMaps.keySet();}@Overridepublic Collection<ParameterMap> getParameterMaps() {return parameterMaps.values();}@Overridepublic ParameterMap getParameterMap(String id) {return parameterMaps.get(id);}@Overridepublic boolean hasParameterMap(String id) {return parameterMaps.containsKey(id);}@Overridepublic Map<String, XNode> getSqlFragments() {return sqlFragments;}@Overridepublic Collection<String> getMappedStatementNames() {buildAllStatements();return mappedStatements.keySet();}@Overridepublic Collection<MappedStatement> getMappedStatements() {buildAllStatements();return mappedStatements.values();}@Overridepublic MappedStatement getMappedStatement(String id) {return this.getMappedStatement(id, true);}@Overridepublic MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) {if (validateIncompleteStatements) {buildAllStatements();}return mappedStatements.get(id);}@Overridepublic boolean hasStatement(String statementName, boolean validateIncompleteStatements) {if (validateIncompleteStatements) {buildAllStatements();}return mappedStatements.containsKey(statementName);}@Overridepublic Executor newExecutor(Transaction transaction, ExecutorType executorType) {return super.newExecutor(transaction, executorType);}// Slow but a one time cost. A better solution is welcome.@Overridepublic void checkGloballyForDiscriminatedNestedResultMaps(ResultMap rm) {if (rm.hasNestedResultMaps()) {final String resultMapId = rm.getId();for (Object resultMapObject : resultMaps.values()) {if (resultMapObject instanceof ResultMap) {ResultMap entryResultMap = (ResultMap) resultMapObject;if (!entryResultMap.hasNestedResultMaps() && entryResultMap.getDiscriminator() != null) {Collection<String> discriminatedResultMapNames = entryResultMap.getDiscriminator().getDiscriminatorMap().values();if (discriminatedResultMapNames.contains(resultMapId)) {entryResultMap.forceNestedResultMaps();}}}}}}// Slow but a one time cost. A better solution is welcome.@Overrideprotected void checkLocallyForDiscriminatedNestedResultMaps(ResultMap rm) {if (!rm.hasNestedResultMaps() && rm.getDiscriminator() != null) {for (String discriminatedResultMapName : rm.getDiscriminator().getDiscriminatorMap().values()) {if (hasResultMap(discriminatedResultMapName)) {ResultMap discriminatedResultMap = resultMaps.get(discriminatedResultMapName);if (discriminatedResultMap.hasNestedResultMaps()) {rm.forceNestedResultMaps();break;}}}}}protected class StrictMap<V> extends ConcurrentHashMap<String, V> {private static final long serialVersionUID = -4950446264854982944L;private final String name;private BiFunction<V, V, String> conflictMessageProducer;private final Object AMBIGUITY_INSTANCE = new Object();public StrictMap(String name, int initialCapacity, float loadFactor) {super(initialCapacity, loadFactor);this.name = name;}public StrictMap(String name, int initialCapacity) {super(initialCapacity);this.name = name;}public StrictMap(String name) {super();this.name = name;}public StrictMap(String name, Map<String, ? extends V> m) {super(m);this.name = name;}/*** Assign a function for producing a conflict error message when contains value with the same key.* <p>* function arguments are 1st is saved value and 2nd is target value.** @param conflictMessageProducer A function for producing a conflict error message* @return a conflict error message* @since 3.5.0*/public StrictMap<V> conflictMessageProducer(BiFunction<V, V, String> conflictMessageProducer) {this.conflictMessageProducer = conflictMessageProducer;return this;}@Override@SuppressWarnings("unchecked")public V put(String key, V value) {if (containsKey(key)) {throw new IllegalArgumentException(name + " already contains value for " + key+ (conflictMessageProducer == null ? StringPool.EMPTY : conflictMessageProducer.apply(super.get(key), value)));}if (useGeneratedShortKey) {if (key.contains(StringPool.DOT)) {final String shortKey = getShortName(key);if (super.get(shortKey) == null) {super.put(shortKey, value);} else {super.put(shortKey, (V) AMBIGUITY_INSTANCE);}}}return super.put(key, value);}@Overridepublic boolean containsKey(Object key) {if (key == null) {return false;}return super.get(key) != null;}@Overridepublic V get(Object key) {V value = super.get(key);if (value == null) {throw new IllegalArgumentException(name + " does not contain value for " + key);}if (useGeneratedShortKey && AMBIGUITY_INSTANCE == value) {throw new IllegalArgumentException(key + " is ambiguous in " + name+ " (try using the full name including the namespace, or rename one of the entries)");}return value;}private String getShortName(String key) {final String[] keyParts = key.split("\\.");return keyParts[keyParts.length - 1];}}
}

MybatisMapperRegistry.java

public class MybatisMapperRegistry extends MapperRegistry {private final Configuration config;private final Map<Class<?>, MybatisMapperProxyFactory<?>> knownMappers = new ConcurrentHashMap<>();public MybatisMapperRegistry(Configuration config) {super(config);this.config = config;}@SuppressWarnings("unchecked")@Overridepublic <T> T getMapper(Class<T> type, SqlSession sqlSession) {// fix https://github.com/baomidou/mybatis-plus/issues/4247MybatisMapperProxyFactory<T> mapperProxyFactory = (MybatisMapperProxyFactory<T>) knownMappers.get(type);if (mapperProxyFactory == null) {mapperProxyFactory = (MybatisMapperProxyFactory<T>) knownMappers.entrySet().stream().filter(t -> t.getKey().getName().equals(type.getName())).findFirst().map(Map.Entry::getValue).orElseThrow(() -> new BindingException("Type " + type + " is not known to the MybatisPlusMapperRegistry."));}try {return mapperProxyFactory.newInstance(sqlSession);} catch (Exception e) {throw new BindingException("Error getting mapper instance. Cause: " + e, e);}}@Overridepublic <T> boolean hasMapper(Class<T> type) {return knownMappers.containsKey(type);}/*** 清空 Mapper 缓存信息*/protected <T> void removeMapper(Class<T> type) {knownMappers.entrySet().stream().filter(t -> t.getKey().getName().equals(type.getName())).findFirst().ifPresent(t -> knownMappers.remove(t.getKey()));}@Overridepublic <T> void addMapper(Class<T> type) {if (type.isInterface()) {if (hasMapper(type)) {return;
//                throw new BindingException("Type " + type + " is already known to the MapperRegistry.");}boolean loadCompleted = false;try {knownMappers.put(type, new MybatisMapperProxyFactory<>(type));// It's important that the type is added before the parser is run// otherwise the binding may automatically be attempted by the// mapper parser. If the type is already known, it won't try.// MybatisPlus注解解析器MybatisMapperAnnotationBuilder parser = new MybatisMapperAnnotationBuilder(config, type);parser.parse();loadCompleted = true;} finally {if (!loadCompleted) {knownMappers.remove(type);}}}}/*** 使用自己的 knownMappers*/@Overridepublic Collection<Class<?>> getMappers() {return Collections.unmodifiableCollection(knownMappers.keySet());}}

MybatisMapperAnnotationBuilder.java MybatisPlus核心构造器,主要解析相关实体类的信息,例如TableName、Id、TableFiled;MybatisPlus自己相关的注解;

/*** 核心方法*/@Overridepublic void parse() {String resource = type.toString();if (!configuration.isResourceLoaded(resource)) {loadXmlResource();configuration.addLoadedResource(resource);String mapperName = type.getName();assistant.setCurrentNamespace(mapperName);parseCache();parseCacheRef();IgnoreStrategy ignoreStrategy = InterceptorIgnoreHelper.initSqlParserInfoCache(type);for (Method method : type.getMethods()) {if (!canHaveStatement(method)) {continue;}if (getAnnotationWrapper(method, false, Select.class, SelectProvider.class).isPresent()&& method.getAnnotation(ResultMap.class) == null) {parseResultMap(method);}try {InterceptorIgnoreHelper.initSqlParserInfoCache(ignoreStrategy, mapperName, method);parseStatement(method);} catch (IncompleteElementException e) {configuration.addIncompleteMethod(new MybatisMethodResolver(this, method));}}try {// https://github.com/baomidou/mybatis-plus/issues/3038if (GlobalConfigUtils.isSupperMapperChildren(configuration, type)) {//  是否继承了MybatisPlus Mapper类,如果继承了,才会解析MybatisPlus自带的相关方法;例如:selectById、deleteByIdparserInjector();}} catch (IncompleteElementException e) {configuration.addIncompleteMethod(new InjectorResolver(this));}}configuration.parsePendingMethods(false);}// 解析MybatisPlus 默认的注入器void parserInjector() {GlobalConfigUtils.getSqlInjector(configuration).inspectInject(assistant, type);}

AbstractSqlInjector.java

 /*** 核心方法* @param builderAssistant mapper 信息* @param mapperClass      mapper 接口的 class 对象*/@Overridepublic void inspectInject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass) {Class<?> modelClass = ReflectionKit.getSuperClassGenericType(mapperClass, Mapper.class, 0);if (modelClass != null) {String className = mapperClass.toString();Set<String> mapperRegistryCache = GlobalConfigUtils.getMapperRegistryCache(builderAssistant.getConfiguration());if (!mapperRegistryCache.contains(className)) {// 实体类对应的表信息TableInfo tableInfo = TableInfoHelper.initTableInfo(builderAssistant, modelClass);// 相关默认方法。这里是MybatisPlus提供的默认方法;例如selectById,selectCount方法List<AbstractMethod> methodList = this.getMethodList(mapperClass, tableInfo);// 兼容旧代码if (CollectionUtils.isEmpty(methodList)) {methodList = this.getMethodList(builderAssistant.getConfiguration(), mapperClass, tableInfo);}if (CollectionUtils.isNotEmpty(methodList)) {// 循环注入自定义方法methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo));} else {logger.debug(className + ", No effective injection method was found.");}mapperRegistryCache.add(className);}}}

AbstractMethod
可以看一下类的继承关系:
在这里插入图片描述
简单介绍其中一个类:
SelectList.java

public class SelectList extends AbstractMethod {public SelectList() {this(SqlMethod.SELECT_LIST.getMethod());}/*** @param name 方法名* @since 3.5.0*/public SelectList(String name) {super(name);}@Overridepublic MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {SqlMethod sqlMethod = SqlMethod.SELECT_LIST;//<script>%s SELECT %s FROM %s %s %s %s</script>String sql = String.format(sqlMethod.getSql(), sqlFirst(), sqlSelectColumns(tableInfo, true), tableInfo.getTableName(),// 这里自动解析QueryWrapper相关信息sqlWhereEntityWrapper(true, tableInfo), sqlOrderBy(tableInfo), sqlComment());SqlSource sqlSource = super.createSqlSource(configuration, sql, modelClass);return this.addSelectMappedStatementForTable(mapperClass, methodName, sqlSource, tableInfo);}
}

在这里插入图片描述
可以看到sql相关信息

总结

MybatisPlus是延用Mybatis相关特性,可以说是Mybatis的一种加强版。因为它增加了自定义类来减少相关代码。主要类有:MybatisPlusAutoConfiguration、MybatisConfiguration、MybatisMapperAnnotationBuilder、AbstractSqlInjector、DefaultSqlInjector、Wrapper

MybatisPlusAutoConfiguration: MybatisPlus自动装配器
MybatisConfiguration: MybatisPlus配置类继承Mybatis配置类,主要是对Mybatis配置的增强
MybatisMapperAnnotationBuilder: 核心类之一,主要用来解析MybatisPlus自己的注解。
AbstractSqlInjector: Sql注入器,MybatisPlus提供了相关默认的方法。
Wrapper: 条件包裹器

相关文章:

Mybatis-plus 源码解读

简述 本篇主要针对MybatisPlus源码进行解读。 案例 上一篇已经讲了Springboot如何集成MybatisPlus&#xff1a; springboot-mybatis-plus集成篇 源码解析 和Springboot集成Mybatis一样&#xff0c; 依赖了mybatis-plus-spring-boot3-starter&#xff0c;其中主要关注spri…...

web 期末作业简单设计网页——“我的家乡”网站简单设计

1、网页效果 首页 七彩云南页 旅游攻略页 用户页面 2、源代码 首页 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>首页</title><link rel"stylesheet" href"out.css&quo…...

Redis篇-3--原理篇2--Redis事务

1、概述 Redis 提供了简单的事务机制&#xff0c;Redis 事务的本质是一组命令的集合。当执行redis事务时&#xff0c;即一次性按照添加顺序依次执行这些命令&#xff0c;中间不会被打断或者干扰。 Redis 的事务机制并不像关系型数据库中的事务那样提供完整的ACID特性&#xf…...

GEE:CCDC 分类组件,对每个分段进行分类

作者:CSDN @ _养乐多_ 连续变化检测与分类(Continuous Change Detection and Classification, CCDC) 利用了时间序列拟合来对影像中的像素值随时间的变化趋势建模。每一段模型代表一个时间段内的地表覆盖类型和状态。 本文将解释如何在谷歌地球引擎(Google Earth Engine,…...

常见排序算法总结 (四) - 快速排序与随机选择

快速排序 算法思想 每一轮在数组相应的范围上随机找一个元素进行划分&#xff0c;将不大于它的所有元素都放到左边&#xff0c;将大于它的元素都放到右边。在左右两个子数组上不断地递归&#xff0c;直到整个数组上有序。 注意&#xff1a;实现时选择的时参考荷兰国旗问题优化…...

[创业之路-187]:《华为战略管理法-DSTE实战体系》-1-从UTStarcom的发展历程,如何辩证的看企业初期发展太顺利中的危机

目录 一、UTStarcom&#xff08;UT斯达康&#xff09;的发展历程 1、创立与初期发展 2、快速成长与上市 3、技术创新与业务拓展 4、战略调整与持续发展 二、从UTStarcom的发展历程&#xff0c;如何辩证的看企业初期发展太顺利中的危机 1、企业初期发展的顺利表现 2、顺…...

C缺陷与陷阱 — 3 深入理解表达式

目录 1 表达式的运算次序 1.1 自增或自减操作符 1.2 函数参数 1.3 函数指针 1.4 函数调用 1.5 嵌套赋值语句 2 函数调用不作为函数参数 3 赋值语句的谨慎使用 1 表达式的运算次序 除了少数操作符&#xff08;函数调用操作符 ( )、&&、| |、? : 和 ,&#xff…...

Next.js 系统性教学:中间件与国际化功能深入剖析

更多有关Next.js教程&#xff0c;请查阅&#xff1a; 【目录】Next.js 独立开发系列教程-CSDN博客 目录 一、Next.js 中间件 (Middleware) 功能解析 1.1 什么是中间件&#xff1f; 1.2 Next.js 中间件的工作机制 1.3 中间件的功能应用 身份验证与授权 请求重定向 修改请…...

openWebUI+ollamawindows+不用docker+webLite本地安装

openWebUI & ollama & windows & 不用docker & webLite 本地安装 总结一下安装教程 10核CPU16G内存 两个web框架都可以&#xff0c;先说简单的 ollama-webui-lite(https://github.com/ollama-webui/ollama-webui-lite) 轻量级&#xff0c;只使用nodejs 先装…...

动态规划——机器分配、01背包问题

一、机器分配 题目名称&#xff1a;机器分配 题目描述&#xff1a; 总公司拥有高效设备M台&#xff0c;准备分给下属的N个分公司。 各分公司若获得这些设备&#xff0c;可以为国家提供一定的盈利。 问&#xff1a;如何分配这M台设备才能使国家得到的盈利最大&#xff1f;求出最…...

leetcode——哈希表1

242.有效的字母异位词 给定两个字符串 s 和 t &#xff0c;编写一个函数来判断 t 是否是 s 的 字母异位词 。 示例 1: 输入: s "anagram", t "nagaram" 输出: true示例 2: 输入: s "rat", t "car" 输出: false 提示: 1 < s.le…...

STM32+模拟或硬件IIC+SHT20驱动问题:接上拉电阻、BUSY死锁?

主要问题&#xff1a; 1&#xff0c;使用STM32F103C8T6&#xff0c;模拟IIC&#xff0c;SCL和SDA口配置为推挽输出上拉&#xff0c;主要是SDA脚&#xff0c;每次都要输出输入模式重新配置&#xff0c;虽然也能通信&#xff0c;但不稳定&#xff0c;出错率大&#xff1b; 2&…...

Android四大组件——Activity(二)

一、Activity之间传递消息 在&#xff08;一&#xff09;中&#xff0c;我们把数据作为独立的键值对进行传递&#xff0c;那么现在把多条数据打包成一个对象进行传递&#xff1a; 1.假设有一个User类的对象&#xff0c;我们先使用putExtra进行传递 activity_demo06.xml <…...

PHP实现华为OBS存储

一&#xff1a;华为OBS存储文档地址 官方文档&#xff1a;https://support.huaweicloud.com/obs/index.html github地址&#xff1a;https://github.com/huaweicloud/huaweicloud-sdk-php-obs 二&#xff1a;安装华为OBS拓展 composer require obs/esdk-obs-php 三&#x…...

SQL连续登录问题(详细案例分析)

如果要统计用户活跃度&#xff0c;那就涉及连续登录问题&#xff0c;接下来将举一个简单的例子来详细说明这个问题&#xff1a; 一、创建一些模拟数据 一些测试数据如下&#xff1a; deviceid1,2022-10-26,2022-10-26,2022-11-01 deviceid1,2022-10-26,2022-11-03,2022-11-0…...

OpenCV相机标定与3D重建(9)相机标定函数calibrateCameraRO()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::calibrateCameraRO 是 OpenCV 中用于相机标定的函数&#xff0c;它允许固定某些点来进行更精确的标定。 函数原型 double cv::calibrateCa…...

【一本通】农场派对

【一本通】农场派对 &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; N头牛要去参加一场在编号为x(1≤x≤n)的牛的农场举行的派对(1≤N≤1000)&#xff0c;有M(1≤m≤100000)条有向道路&#xff0c;每条路长ti(1≤ti≤100)&#xff1b;每头牛…...

uniapp中父组件传参到子组件页面渲染不生效问题处理实战记录

上篇文件介绍了,父组件数据更新正常但是页面渲染不生效的问题,详情可以看下:uniapp中父组件数组更新后与页面渲染数组不一致实战记录 本文在此基础上由于新增需求衍生出新的问题.本文只记录一下解决思路. 下面说下新增需求方便理解场景: 商品信息设置中添加抽奖概率设置…...

基础暴力算法

线性枚举 线性枚举&#xff08;Linear Enumeration&#xff09;是一种暴力枚举的方法&#xff0c;它逐一检查每个可能的解&#xff0c;适用于搜索和枚举问题。 其核心思路是&#xff1a;对问题的所有可能情况逐一进行遍历&#xff0c;并针对每种情况判断是否满足条件&#xf…...

【复变函数】三、复变函数的积分

目录 1. 复变函数积分1.1. 复积分1.2. 存在性与计算1.2.1 第二类曲线积分与格林公式1.2.2 第一类曲线积分与参数式 1.3. 性质1.4. 圆径积分 2. 柯西积分定理2.1. 柯西&#xff08;Cauchy&#xff09;基本定理与莫雷拉&#xff08;Morrera&#xff09;定理2.2. 复合闭路定理2.3.…...

ChatGPT Pro是什么

ChatGPT Pro 和 ChatGPT Plus 的区别主要体现在功能范围、适用场景和目标用户上。 ChatGPT Plus 功能 • 价格&#xff1a;20美元/月。 • 目标用户&#xff1a;针对个人用户设计。 • 主要特点&#xff1a; • 在高峰期响应速度更快。 • 使用高级模型&#xff08;如 GPT-4…...

React - echarts 世界地图,中国地图绘制

中国地图 首先需要一个包含中国所有省份名称的 json&#xff0c;这个好多网站都能找到。 我传到资源里了&#xff0c;放百度网盘怕太长时间不登录给我删掉了。 中国地图中文版json 我把地图抽出来单独做成了组件&#xff0c;这样用的时候比较方便. 使用的时候&#xff1a; …...

knife4j-openapi3 4.5 最基本的使用 openAPI

最基本的使用&#xff0c;配置太多懒得研究 SpringBoot 整合 knfe4j &#xff0c;使用 OpenAPI3 规范&#xff0c;这个兄弟写的挺好 环境&#xff1a; spring-boot-starter-parent&#xff1a;3.4.0 1. 依赖 <dependency><groupId>com.github.xiaoymin</gr…...

如何在 Ubuntu 22.04 上安装和使用 Apache Kafka

简介 Apache Kafka是一个高性能、低延迟的分布式流处理平台&#xff0c;广泛用于构建实时数据管道和流式应用。本文将指导你如何在Ubuntu 22.04系统上快速部署Apache Kafka&#xff0c;让你体验到Kafka在处理大规模实时数据流方面的强大能力。通过本教程&#xff0c;你将学会如…...

Linux:network:添加ip的时候自动添加一个本地路由

文章目录 问题问题 最近在看一个路由的问题,顺便看内核代码,发现在添加IP的时候,内核会自动添加一个local route。 net/ipv4/devinet.c inet_rtm_newaddr->__inet_insert_ifa /* Send message first, then call notifier.Notifier will trigger FIB update, so thatlis…...

Android 10、11、12存储适配相关

AndroidQ(10)分区存储完美适配 - 简书前言 最近时间在做AndroidQ的适配&#xff0c;截止到今天AndroidQ分区存储适配完成&#xff0c;期间出现很多坑&#xff0c;目前网上的帖子大部分都是概述变更内容&#xff0c;接下来的几篇帖子都是对分区存储实际...https://www.jianshu.c…...

如何将视频转化为音频?五个方法策略

在日常生活中&#xff0c;我们经常需要将视频中的音频提取出来&#xff0c;以便在特定的场合使用。无论是为了制作铃声、背景音乐&#xff0c;还是为了进行语音转文字处理&#xff0c;视频转音频的需求都非常普遍。如何将视频转化为音频&#xff1f;本文将详细介绍多种将视频转…...

ecovadis评估最新标准

EcoVadis评估的最新标准主要包括奖牌评估规则和新增的徽章规则&#xff0c;以下是对这两方面的详细阐述&#xff1a; 一、奖牌评估规则 评估范围&#xff1a;EcoVadis的评估总分为100分&#xff0c;评估内容涵盖环境、劳工与人权、商业道德、可持续采购等四大主题。 奖牌等级…...

Java版-图论-最小生成树-Kruskal算法

实现描述 为了造出一棵最小生成树&#xff0c;我们从最小边权的边开始&#xff0c;按边权从小到大依次加入&#xff0c;如果某次加边产生了环&#xff0c;就扔掉这条边&#xff0c;直到加入了 n-1 条边&#xff0c;即形成了一棵树。 实现代码 首选我们对所有的边&#xff0c…...

【单片机开发】MCU三种启动方式(Boot选择)[主Flash/系统存储器(BootLoader)/嵌入式SRAM]

目录 参考资料&#xff1a; 利用 Boot 选择不同的启动方式&#xff1a; 单片机的存储结构(主 FLASH/系统存储器/嵌入式 SRAM)&#xff1a; 1. Cortex-M 内核芯片——启动原理&#xff1a; 1.1. 启动流程&#xff1a; 1.2. 根据单片机的存储器映射和架构图&#xff1a;启动…...

实验15 验证LSTM模型的长程依赖

本次实验依托上个实验 一 模型构建 创建LSTM模型&#xff0c;里面包括初始化init函数、初始化权重函数_init_weights、初始化状态函数init_state、前向传播函数forward。 init函数&#xff1a;虽然每个时间的输入和隐层都是一样的&#xff0c;但是他们会有四组不同的权重&am…...

Charles功能说明

1.扫把(clear the current Session) (前头方向) 作用:清除所有抓取的包(正方形框) 2.中心圈-未启用显示(Star Recording)点击启动 -启动之后显示(Stop Recording)点击停止 作用:启动之后开始抓取包(刷新一次页面或跳转抓取内容) 3.锁-未启动显示(Star SSL Proxying)点击启动 -启…...

自动秒收录程序与自动秒收录网站源码论坛版本下载

自动秒收录程序与自动秒收录网站源码论坛版本下载 随着互联网的快速发展&#xff0c;网站优化已成为众多企业和个人博主提升在线影响力的关键手段。其中&#xff0c;SEO&#xff08;搜索引擎优化&#xff09;作为提升网站排名的核心策略&#xff0c;备受关注。而SEO优化的一个…...

HTML颜色-HTML脚本

HTML脚本 js使得HTML页面具有更强的动态和交互性 HTML<script>标签 标签用于定义客户端脚本&#xff0c;比如javascript 可包含脚本语句&#xff0c;也可以通过src属性指向外部的脚本文件 JavaScript最常用于图片操作&#xff0c;表单验证以及动态的内容更新 HTML<n…...

【WRF理论第十三期】详细介绍 Registry 的作用、结构和内容

目录 1. Introduction&#xff1a;介绍 Registry 的作用和功能。2. Registry Contents&#xff1a;详细描述 Registry 的结构和内容&#xff0c;包括各个部分的条目类型。2.1. DIMSPEC ENTRIES&#xff08;维度规格条目&#xff09;2.2. STATE ENTRIES&#xff08;状态变量条目…...

使用Kimi开发自己的问答应用

概述 Kimi是大家常用的一个人工智能助手&#xff0c;本文使用Kimi开发文档&#xff0c;以node作为后端&#xff0c;开发与一个问答系统 实现效果 Kimi简介 Kimi是由Moonshot AI开发的人工智能助手&#xff0c;擅长中文和英文对话。目标是帮助用户解决问题、提供信息和执行任…...

Vue前端开发-路由其他配置

在路由文件中&#xff0c;除了跳转配置外&#xff0c;还可以进行路径重定向配置&#xff0c;如果没有找到对应的地址&#xff0c;还可以实现404的配置&#xff0c;同时&#xff0c;如果某个页面需要权限登录&#xff0c;还可以进行路由守卫配置&#xff0c;接下来&#xff0c;分…...

AI与遥感的融合:构建新一代智能监测作业平台

在测绘地理信息与遥感领域&#xff0c;人工智能&#xff08;AI&#xff09;技术的融合正推动着一场监测作业模式的革命。AI不仅提升了数据处理的效率&#xff0c;还极大地扩展了遥感技术的应用范围和深度。 遥感监测的智能化趋势 随着遥感数据量的激增&#xff0c;传统的人工…...

3D 视觉定位技术:汽车零部件制造的智能变革引擎

在汽车零部件制造领域&#xff0c;传统工艺正面临着前所未有的挑战。市场对于零部件精度与生产效率近乎苛刻的要求&#xff0c;促使企业寻求突破之道。而 3D 视觉定位技术&#xff0c;为汽车零部件制造开启了精准定位与智能化生产的新纪元。 3D 视觉定位系统的核心技术原理 3…...

git提交时出现merge branch main of xxx

git提交时出现merge branch main of xxx 原因&#xff1a; 1、同事commit了一个修改A&#xff0c;push到remote 2、我把这个修改直接pull了下来&#xff08;pull是fetchmerge的操作&#xff0c;自动合并到本地workspace&#xff09; 3、同事因为后续的commit有冲突&#xff0c…...

重生之我在异世界学编程之C语言:深入结构体篇(上)

大家好&#xff0c;这里是小编的博客频道 小编的博客&#xff1a;就爱学编程 很高兴在CSDN这个大家庭与大家相识&#xff0c;希望能在这里与大家共同进步&#xff0c;共同收获更好的自己&#xff01;&#xff01;&#xff01; 本文目录 引言正文《1》 结构体的两种声明一、结构…...

到达率和服务率在python中实现

到达率和服务率在python中实现 概念理解 到达率(Arrival Rate):是指顾客(或任务、事件等)到达服务系统的平均速率,通常用单位时间内到达的数量来表示。例如,在一个客服中心,每小时平均有10个客户来电咨询,这里的每小时10个客户就是到达率。服务率(Service Rate):是…...

重视猫艾滋:宠物健康的隐秘挑战

猫艾滋&#xff0c;全称为猫获得性免疫缺陷综合征&#xff08;Feline Acquired Immunodeficiency Syndrome&#xff09;&#xff0c;是由猫免疫缺陷病毒&#xff08;FIV&#xff09;感染引起的一种严重危害猫类健康的疾病。虽然其名称与人类艾滋病相似&#xff0c;但猫艾滋仅在…...

使用长轮询解决某些场景的实时消息推送需求

需求来源 最近做一个需求实现在移动端通过按钮&#xff0c;远程控制大屏幕上展示的资源进行实时切换&#xff0c;可以展示一个大屏页面&#xff0c;可以展示一段视频&#xff0c;也可以展示一张图片。 解决思路 大屏幕上打开一个游览器&#xff0c;访问指定动态资源展示页面…...

uniapp-内部项目使用文档

uniapp-内部项目使用文档 目录 uniapp-内部项目使用文档阶段1自行实现内容&#xff1a;阶段1问题记录&#xff1a; 阶段2自行实现内容&#xff1a; 阶段3 APP项目介绍及规范阶段4 公共组件方法UseList 列表页面HooksListItem 列表项uni-load-more 列表加载更多组件CardTitle 列…...

linux搭建NFS服务和autofs自动挂载NFS

文章目录 1、nfs服务1、nfs原理2、RPC和NFS通讯原理3、RPC和NFS流程4、NFS工作流程5、服务端搭建6、客户端搭建7、autofs自动挂载 1、nfs服务 1、nfs原理 是一个NAS的存储&#xff0c;通过网络来进行文件的共享&#xff0c;表现出来的形式就是一个文件夹 可以支持多个linux挂…...

springboot415社区网格化管理平台的构建-(论文+源码)_kaic

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本社区网格化管理平台就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据…...

ubuntu下open-webui + ollama本地大模型部署

文章目录 nvidia gpu驱动安装 安装卸载 ollama 部署 添加docker秘钥docker配置添加国内镜像源ollama安装 从源拉取ollama镜像。启动一个ollama容器 通过ollama下载模型到本地检验本地模型 open-webui 部署 安装容器和镜像下载webui使用查看模型运行时内存、cpu、gpu占用 业余…...

自动化运维-配置Mysql、emqx、redis、nginx等通用性Linux日志分割工具 - logrotate

前言&#xff1a;logrotate 是一个在 Linux 系统中用于管理和轮转日志文件的工具。它的主要目的是帮助系统管理员自动执行日志文件的轮转、压缩、删除和邮件通知等任务&#xff0c;以防止日志文件占用过多的磁盘空间&#xff0c;同时保持日志文件的可管理性。 参考命令&#x…...

71、docker镜像制作上传/下载到阿里云

基本思想:简单学习一下如何制作镜像和上传下载到私有阿里云,然后构建一个gpu的训练/推理环境,以备后续使用 一、配置环境 ubuntu@ubuntu:~$ sudo apt-get install docker.ioubuntu@ubuntu:~$ sudo docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS P…...