亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

springboot整合ehcache和redis實現(xiàn)多級緩存實戰(zhàn)案例

 更新時間:2023年08月09日 09:20:59   作者:qq_21305943  
這篇文章主要介紹了springboot整合ehcache和redis實現(xiàn)多級緩存實戰(zhàn)案例,從源碼角度分析下多級緩存實現(xiàn)原理,本文通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下

一、概述

在實際的工作中,我們通常會使用多級緩存機制,將本地緩存和分布式緩存結合起來,從而提高系統(tǒng)性能和響應速度。本文通過springboot整合ehcache和redis實現(xiàn)多級緩存案例實戰(zhàn),從源碼角度分析下多級緩存實現(xiàn)原理。

二、實戰(zhàn)案例

1、pom依賴(注意引入cache和ehcache組件依賴)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
? ? ? ? ?xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
? ? ? ? ?xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
? ? <modelVersion>4.0.0</modelVersion>
? ? <groupId>org.example</groupId>
? ? <artifactId>cache-demo</artifactId>
? ? <version>1.0-SNAPSHOT</version>
? ? <properties>
? ? ? ? <maven.compiler.source>8</maven.compiler.source>
? ? ? ? <maven.compiler.target>8</maven.compiler.target>
? ? </properties>
? ? <parent>
? ? ? ? <groupId>org.springframework.boot</groupId>
? ? ? ? <artifactId>spring-boot-starter-parent</artifactId>
? ? ? ? <version>2.5.0</version>
? ? </parent>
? ? <dependencies>
? ? ? ? <dependency>
? ? ? ? ? ? <groupId>org.springframework.boot</groupId>
? ? ? ? ? ? <artifactId>spring-boot-starter-web</artifactId>
? ? ? ? </dependency>
? ? ? ? <dependency>
? ? ? ? ? ? <groupId>junit</groupId>
? ? ? ? ? ? <artifactId>junit</artifactId>
? ? ? ? ? ? <version>4.12</version>
? ? ? ? </dependency>
? ? ? ? <dependency>
? ? ? ? ? ? <groupId>org.springframework.boot</groupId>
? ? ? ? ? ? <artifactId>spring-boot-starter-test</artifactId>
? ? ? ? ? ? <scope>test</scope>
? ? ? ? </dependency>
? ? ? ? <dependency>
? ? ? ? ? ? <groupId>com.baomidou</groupId>
? ? ? ? ? ? <artifactId>mybatis-plus-boot-starter</artifactId>
? ? ? ? ? ? <version>3.4.3</version>
? ? ? ? </dependency>
? ? ? ? <dependency>
? ? ? ? ? ? <groupId>mysql</groupId>
? ? ? ? ? ? <artifactId>mysql-connector-java</artifactId>
? ? ? ? </dependency>
? ? ? ? <dependency>
? ? ? ? ? ? <groupId>com.alibaba</groupId>
? ? ? ? ? ? <artifactId>druid-spring-boot-starter</artifactId>
? ? ? ? ? ? <version>1.2.1</version>
? ? ? ? </dependency>
? ? ? ? <dependency>
? ? ? ? ? ? <groupId>org.projectlombok</groupId>
? ? ? ? ? ? <artifactId>lombok</artifactId>
? ? ? ? </dependency>
? ? ? ? <dependency>
? ? ? ? ? ? <groupId>com.alibaba</groupId>
? ? ? ? ? ? <artifactId>fastjson</artifactId>
? ? ? ? ? ? <version>1.2.76</version>
? ? ? ? </dependency>
? ? ? ? <dependency>
? ? ? ? ? ? <groupId>com.alibaba</groupId>
? ? ? ? ? ? <artifactId>druid</artifactId>
? ? ? ? ? ? <version>1.1.23</version>
? ? ? ? </dependency>
? ? ? ? <dependency>
? ? ? ? ? ? <groupId>com.google.guava</groupId>
? ? ? ? ? ? <artifactId>guava</artifactId>
? ? ? ? ? ? <version>23.0</version>
? ? ? ? </dependency>
? ? ? ? <dependency>
? ? ? ? ? ? <groupId>org.springframework.boot</groupId>
? ? ? ? ? ? <artifactId>spring-boot-starter-data-redis</artifactId>
? ? ? ? </dependency>
? ? ? ? <dependency>
? ? ? ? ? ? <groupId>org.springframework.boot</groupId>
? ? ? ? ? ? <artifactId>spring-boot-starter-cache</artifactId>
? ? ? ? </dependency>
? ? ? ? <dependency>
? ? ? ? ? ? <groupId>net.sf.ehcache</groupId>
? ? ? ? ? ? <artifactId>ehcache</artifactId>
? ? ? ? ? ? <version>2.10.8</version>
? ? ? ? </dependency>
? ? ? ? <dependency>
? ? ? ? ? ? <groupId>org.springframework.boot</groupId>
? ? ? ? ? ? <artifactId>spring-boot-starter-aop</artifactId>
? ? ? ? </dependency>
? ? </dependencies>
</project>

2、application.properties(啟動類加上:@EnableCaching注解)

server.port = 7001
spring.application.name = cache-demo
#log config
logging.config = classpath:log/logback.xml
debug = false
#mp config
mybatis-plus.mapper-locations = classpath*:mapper/*.xml
mybatis-plus.configuration.log-impl = org.apache.ibatis.logging.stdout.StdOutImpl
spring.datasource.type = com.alibaba.druid.pool.DruidDataSource
spring.datasource.druid.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.url = jdbc:mysql://localhost:3306/數(shù)據(jù)庫?characterEncoding=utf-8
spring.datasource.username = 數(shù)據(jù)庫賬號
spring.datasource.password = 數(shù)據(jù)庫密碼
#redis config
spring.redis.host = redis主機
spring.redis.port = 6379
spring.redis.password=redis密碼,沒有就刪掉該配置
# ehcache config
spring.cache.type = ehcache
spring.cache.ehcache.config = classpath:ehcache.xml

3、ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
? ? ? ? ?xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
? ? ? ? ?updateCheck="false">
? ? <diskStore path="D:\ehcache"/>
? ? <!--默認緩存策略 -->
? ? <!-- external:是否永久存在,設置為true則不會被清除,此時與timeout沖突,通常設置為false-->
? ? <!-- diskPersistent:是否啟用磁盤持久化-->
? ? <!-- maxElementsInMemory:最大緩存數(shù)量-->
? ? <!-- overflowToDisk:超過最大緩存數(shù)量是否持久化到磁盤-->
? ? <!-- timeToIdleSeconds:最大不活動間隔,設置過長緩存容易溢出,設置過短無效果,單位:秒-->
? ? <!-- timeToLiveSeconds:最大存活時間,單位:秒-->
? ? <!-- memoryStoreEvictionPolicy:緩存清除策略-->
? ? <defaultCache
? ? ? ? ? ? eternal="false"
? ? ? ? ? ? diskPersistent="false"
? ? ? ? ? ? maxElementsInMemory="1000"
? ? ? ? ? ? overflowToDisk="false"
? ? ? ? ? ? timeToIdleSeconds="60"
? ? ? ? ? ? timeToLiveSeconds="60"
? ? ? ? ? ? memoryStoreEvictionPolicy="LRU"/>
? ? <cache
? ? ? ? ? ? name="studentCache"
? ? ? ? ? ? eternal="false"
? ? ? ? ? ? diskPersistent="false"
? ? ? ? ? ? maxElementsInMemory="1000"
? ? ? ? ? ? overflowToDisk="false"
? ? ? ? ? ? timeToIdleSeconds="100"
? ? ? ? ? ? timeToLiveSeconds="100"
? ? ? ? ? ? memoryStoreEvictionPolicy="LRU"/>
</ehcache>

4、MybatisPlusConfig類(注意:@MapperScan注解,也可加在啟動類上)

@Configuration
@MapperScan("com.cache.demo.mapper")
public class MybatisPlusConfig {
? ? @Bean
? ? public MybatisPlusInterceptor mybatisPlusInterceptor() {
? ? ? ? //分頁插件
? ? ? ? MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
? ? ? ? mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
? ? ? ? return mybatisPlusInterceptor;
? ? }
}

5、測試demo

這里可以將一級緩存、二級緩存時效設置短一些,方便進行測試。

@Slf4j
@RestController
@RequestMapping("/cache")
public class CacheController {
? ? @Resource
? ? private StudentMapper studentMapper;
? ? @Autowired
? ? private StringRedisTemplate stringRedisTemplate;
? ?? ?// 添加緩存注解(一級緩存:ehcache)
? ? @Cacheable(value = "studentCache", key = "#id+'getStudentById'")
? ? @GetMapping("/getStudentById")
? ? public String getStudentById(Integer id) {
? ? ? ? String key = "student:" + id;
? ? ? ?? ?// 一級緩存中不存在,則從二級緩存:redis中查找
? ? ? ? String studentRedis = stringRedisTemplate.opsForValue().get(key);
? ? ? ? if (StringUtils.isNotBlank(studentRedis)) {
? ? ? ? ? ? return JSON.toJSONString(JSON.parseObject(studentRedis, Student.class));
? ? ? ? }
? ? ? ? // 二級緩存中不存在則查詢數(shù)據(jù)庫,并更新二級緩存、一級緩存
? ? ? ? Student student = studentMapper.selectStudentById(id);
? ? ? ? if (null != student) {
? ? ? ? ? ? stringRedisTemplate.opsForValue().set(key, JSON.toJSONString(student));
? ? ? ? }
? ? ? ? return JSON.toJSONString(student);
? ? }
}

6、啟動類上的:@EnableCaching注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(CachingConfigurationSelector.class)
public @interface EnableCaching {
?? ?boolean proxyTargetClass() default false;
?? ?AdviceMode mode() default AdviceMode.PROXY;
? int order() default Ordered.LOWEST_PRECEDENCE;
}

7、導入的:

CachingConfigurationSelector類:

public class CachingConfigurationSelector extends AdviceModeImportSelector<EnableCaching> {
?? ?@Override
?? ?public String[] selectImports(AdviceMode adviceMode) {
?? ??? ?switch (adviceMode) {
?? ??? ??? ?case PROXY:
? ? ? ? // 此處走的是:PROXY
?? ??? ??? ??? ?return getProxyImports();
?? ??? ??? ?case ASPECTJ:
?? ??? ??? ??? ?return getAspectJImports();
?? ??? ??? ?default:
?? ??? ??? ??? ?return null;
?? ??? ?}
?? ?}
?? ?private String[] getProxyImports() {
?? ??? ?List<String> result = new ArrayList<>(3);
? ? // 導入了AutoProxyRegistrar類和ProxyCachingConfiguration類
?? ??? ?result.add(AutoProxyRegistrar.class.getName());
?? ??? ?result.add(ProxyCachingConfiguration.class.getName());
?? ??? ?if (jsr107Present && jcacheImplPresent) {
?? ??? ??? ?result.add(PROXY_JCACHE_CONFIGURATION_CLASS);
?? ??? ?}
?? ??? ?return StringUtils.toStringArray(result);
?? ?}
}

8、AutoProxyRegistrar類(代碼有所簡化):

public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
?? ?private final Log logger = LogFactory.getLog(getClass());
?? ?@Override
?? ?public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
?? ??? ??? ??? ?// 最終注冊了:InfrastructureAdvisorAutoProxyCreator(BeanPostProcessor接口實現(xiàn)類)
? ? ?? ??? ?// 通過重寫postProcessAfterInitialization接口創(chuàng)建代理對象
? ? ? ?? ?AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
?? ?}
}
@Nullable
?? ?public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {
?? ??? ?return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
?? ?}

9、導入的第一個類看完了,接著看導入的第二個類:ProxyCachingConfiguration

@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyCachingConfiguration extends AbstractCachingConfiguration {
?? ?@Bean(name = CacheManagementConfigUtils.CACHE_ADVISOR_BEAN_NAME)
?? ?@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
?? ?public BeanFactoryCacheOperationSourceAdvisor cacheAdvisor(CacheOperationSource cacheOperationSource, CacheInterceptor cacheInterceptor) {
?? ??? ?// ?構建BeanFactoryCacheOperationSourceAdvisor
? ? BeanFactoryCacheOperationSourceAdvisor advisor = new BeanFactoryCacheOperationSourceAdvisor();
?? ??? ?// 設置緩存注解解析器
? ? advisor.setCacheOperationSource(cacheOperationSource);
?? ??? ?// 設置緩存攔截器:cacheInterceptor
? ? advisor.setAdvice(cacheInterceptor);
?? ??? ?if (this.enableCaching != null) {
?? ??? ??? ?advisor.setOrder(this.enableCaching.<Integer>getNumber("order"));
?? ??? ?}
?? ??? ?return advisor;
?? ?}
?? ?@Bean
?? ?@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
?? ?public CacheOperationSource cacheOperationSource() {
? ? // 緩存注解解析器
?? ??? ?return new AnnotationCacheOperationSource();
?? ?}
?? ?@Bean
?? ?@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
?? ?public CacheInterceptor cacheInterceptor(CacheOperationSource cacheOperationSource) {
?? ??? ?// 緩存攔截器
? ? CacheInterceptor interceptor = new CacheInterceptor();
?? ??? ?interceptor.configure(this.errorHandler, this.keyGenerator, this.cacheResolver, this.cacheManager);
?? ??? ?interceptor.setCacheOperationSource(cacheOperationSource);
?? ??? ?return interceptor;
?? ?}
}

10、繼續(xù)看下CacheInterceptor類(重要):

public class CacheInterceptor extends CacheAspectSupport implements MethodInterceptor, Serializable {
?? ?@Override
?? ?@Nullable
?? ?public Object invoke(final MethodInvocation invocation) throws Throwable {
?? ??? ?Method method = invocation.getMethod();
?? ??? ?CacheOperationInvoker aopAllianceInvoker = () -> {
?? ??? ??? ?try {
?? ??? ??? ??? ?return invocation.proceed();
?? ??? ??? ?}
?? ??? ??? ?catch (Throwable ex) {
?? ??? ??? ??? ?throw new CacheOperationInvoker.ThrowableWrapper(ex);
?? ??? ??? ?}
?? ??? ?};
?? ??? ?Object target = invocation.getThis();
?? ??? ?Assert.state(target != null, "Target must not be null");
?? ??? ?try {
? ? ? // 緩存執(zhí)行邏輯
?? ??? ??? ?return execute(aopAllianceInvoker, target, method, invocation.getArguments());
?? ??? ?}
?? ??? ?catch (CacheOperationInvoker.ThrowableWrapper th) {
?? ??? ??? ?throw th.getOriginal();
?? ??? ?}
?? ?}
}
@Nullable
?? ?protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) {
?? ??? ?if (this.initialized) {
?? ??? ??? ?Class<?> targetClass = getTargetClass(target);
?? ??? ??? ?CacheOperationSource cacheOperationSource = getCacheOperationSource();
?? ??? ??? ?if (cacheOperationSource != null) {
? ? ? ? // 解析緩存相關注解,返回CacheOperation
? ? ? ? // 每個緩存注解對應一種不同的解析處理操作
? ? ? ? // CacheEvictOperation、CachePutOperation、CacheableOperation等
?? ??? ??? ??? ?Collection<CacheOperation> operations = cacheOperationSource.getCacheOperations(method, targetClass);
?? ??? ??? ??? ?if (!CollectionUtils.isEmpty(operations)) {
? ? ? ? ? // 執(zhí)行緩存邏輯
?? ??? ??? ??? ??? ?return execute(invoker, method,
?? ??? ??? ??? ??? ??? ??? ?new CacheOperationContexts(operations, method, args, target, targetClass));
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ?}
?? ??? ?return invoker.invoke();
?? ?}
private Object execute(final CacheOperationInvoker invoker, Method method, CacheOperationContexts contexts) {
?? ??? ?// 解析處理@CacheEvict注解
? ? processCacheEvicts(contexts.get(CacheEvictOperation.class), true,?? ?CacheOperationExpressionEvaluator.NO_RESULT);
?? ??? ?// 解析處理@Cacheable注解
?? ??? ?Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));
?? ??? ?List<CachePutRequest> cachePutRequests = new ArrayList<>();
?? ??? ?if (cacheHit == null) {
?? ??? ??? ?collectPutRequests(contexts.get(CacheableOperation.class),?? ?CacheOperationExpressionEvaluator.NO_RESULT, cachePutRequests);
?? ??? ?}
?? ??? ?Object cacheValue;
?? ??? ?Object returnValue;
?? ??? ?if (cacheHit != null && !hasCachePut(contexts)) {
?? ??? ??? ?// 命中緩存,則從緩存中獲取數(shù)據(jù)
?? ??? ??? ?cacheValue = cacheHit.get();
?? ??? ??? ?returnValue = wrapCacheValue(method, cacheValue);
?? ??? ?} else {
?? ??? ??? ?// 未命中緩存,則通過反射執(zhí)行目標方法
?? ??? ??? ?returnValue = invokeOperation(invoker);
?? ??? ??? ?cacheValue = unwrapReturnValue(returnValue);
?? ??? ?}
?? ??? ?// 解析處理@CachePut注解
?? ??? ?collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests);
?? ??? ?// 未命中緩存時,會封裝一個cachePutRequests
? ?? ?// 然后通過反射執(zhí)行目標方法后,執(zhí)行該方法,最終調用EhCacheCache.put方法將數(shù)據(jù)寫入緩存中
?? ??? ?for (CachePutRequest cachePutRequest : cachePutRequests) {
?? ??? ??? ?cachePutRequest.apply(cacheValue);
?? ??? ?}
?? ??? ?// 解析處理@CacheEvict注解,和上面的方法相同,只不過第二個參數(shù)不同
?? ??? ?processCacheEvicts(contexts.get(CacheEvictOperation.class), false, cacheValue);
?? ??? ?return returnValue;
?? ?}

11、接著看下findCachedItem方法

private Cache.ValueWrapper findCachedItem(Collection<CacheOperationContext> contexts) {
?? ??? ?Object result = CacheOperationExpressionEvaluator.NO_RESULT;
?? ??? ?for (CacheOperationContext context : contexts) {
?? ??? ??? ?if (isConditionPassing(context, result)) {
? ? ? ? // 生成key策略:解析@Cacheable注解中的key屬性
? ? ? ? // 若未配置則默認使用SimpleKeyGenerator#generateKey方法生成key
?? ??? ??? ??? ?Object key = generateKey(context, result);
?? ??? ??? ??? ?Cache.ValueWrapper cached = findInCaches(context, key);
?? ??? ??? ??? ?if (cached != null) {
?? ??? ??? ??? ??? ?return cached;
?? ??? ??? ??? ?}?? ?else {
?? ??? ??? ??? ??? ?if (logger.isTraceEnabled()) {
?? ??? ??? ??? ??? ??? ?logger.trace("No cache entry for key '" + key + "' in cache(s) " + context.getCacheNames());
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ?}
?? ??? ?return null;
?? ?}
// SimpleKeyGenerator#generateKey
public static Object generateKey(Object... params) {
? ?? ?// 方法沒有參數(shù),則返回空的SimpleKey
?? ??? ?if (params.length == 0) {
?? ??? ??? ?return SimpleKey.EMPTY;
?? ??? ?}
? ?? ?// 方法參數(shù)只有一個,則返回該參數(shù)
?? ??? ?if (params.length == 1) {
?? ??? ??? ?Object param = params[0];
?? ??? ??? ?if (param != null && !param.getClass().isArray()) {
?? ??? ??? ??? ?return param;
?? ??? ??? ?}
?? ??? ?}
? ?? ?// 否則將方法參數(shù)進行封裝,返回SimpleKey
?? ??? ?return new SimpleKey(params);
?? ?}
private Cache.ValueWrapper findInCaches(CacheOperationContext context, Object key) {
?? ??? ?for (Cache cache : context.getCaches()) {
? ? ? // 從一級緩存中獲取數(shù)據(jù)
?? ??? ??? ?Cache.ValueWrapper wrapper = doGet(cache, key);
?? ??? ??? ?if (wrapper != null) {
?? ??? ??? ??? ?if (logger.isTraceEnabled()) {
?? ??? ??? ??? ??? ?logger.trace("Cache entry for key '" + key + "' found in cache '" + cache.getName() + "'");
?? ??? ??? ??? ?}
?? ??? ??? ??? ?return wrapper;
?? ??? ??? ?}
?? ??? ?}
?? ??? ?return null;
?? ?}
protected Cache.ValueWrapper doGet(Cache cache, Object key) {
?? ??? ?try {
? ? ? // 這里我們使用的是:EhCacheCache,所以最終會調用EhCacheCache.get方法獲取緩存中的數(shù)據(jù)
?? ??? ??? ?return cache.get(key);
?? ??? ?}
?? ??? ?catch (RuntimeException ex) {
?? ??? ??? ?getErrorHandler().handleCacheGetError(ex, cache, key);
?? ??? ??? ?return null;
?? ??? ?}
?? ?}

三、總結

@EnableCaching和@Transactional等實現(xiàn)邏輯大體相同,看的多了,則一通百通。

到此這篇關于springboot整合ehcache和redis實現(xiàn)多級緩存實戰(zhàn)案例的文章就介紹到這了,更多相關springboot多級緩存內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java封裝實現(xiàn)自適應的單位轉換工具類

    Java封裝實現(xiàn)自適應的單位轉換工具類

    這篇文章主要為大家詳細介紹了如何使用Java封裝實現(xiàn)一個自適應的單位轉換工具類,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2025-03-03
  • Spring IOC 三種配置方式詳解

    Spring IOC 三種配置方式詳解

    這篇文章主要介紹了Spring IOC 三種配置方式,基于xml配置方式組件管理,基于注解方式管理和配置類方式管理,這三種方式,通過圖文講解的非常詳細,需要的朋友可以參考下
    2024-05-05
  • Java操作minio刪除文件夾及其文件方法(MinIO基本使用)

    Java操作minio刪除文件夾及其文件方法(MinIO基本使用)

    MinIO是一個高性能、無限擴展的開源對象存儲服務器,它以對象的形式存儲數(shù)據(jù),并兼容Amazon S3接口,它適用于大規(guī)模數(shù)據(jù)存儲、大數(shù)據(jù)分析、文件共享和備份等應用場景,這篇文章主要介紹了java操作minio刪除文件夾及其文件方法,需要的朋友可以參考下
    2024-02-02
  • Java的集合LinkedHashSet詳解

    Java的集合LinkedHashSet詳解

    這篇文章主要介紹了Java的集合LinkedHashSet詳解,LinkedHashSet介于HashSet和TreeSet之間,它也是一個hash表,但是同時維護了一個雙鏈表來記錄插入的順序,需要的朋友可以參考下
    2023-09-09
  • Java數(shù)據(jù)結構之鏈表、棧、隊列、樹的實現(xiàn)方法示例

    Java數(shù)據(jù)結構之鏈表、棧、隊列、樹的實現(xiàn)方法示例

    這篇文章主要介紹了Java數(shù)據(jù)結構之鏈表、棧、隊列、樹的實現(xiàn)方法,結合實例形式分析了Java數(shù)據(jù)結構中鏈表、棧、隊列、樹的功能、定義及使用方法,需要的朋友可以參考下
    2019-03-03
  • 通過jxl.jar 讀取、導出excel的實例代碼

    通過jxl.jar 讀取、導出excel的實例代碼

    通過jxl.jar 讀取、導出excel的實例代碼,需要的朋友可以參考一下
    2013-03-03
  • spring cloud實現(xiàn)前端跨域問題的解決方案

    spring cloud實現(xiàn)前端跨域問題的解決方案

    這篇文章主要介紹了 spring cloud實現(xiàn)前端跨域問題的解決方案,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • JAVA中Collections工具類sort()排序方法

    JAVA中Collections工具類sort()排序方法

    這篇文章主要介紹了JAVA中Collections工具類sort()排序方法,非常具有實用價值,需要的朋友可以參考下。
    2016-11-11
  • Java泛型實現(xiàn)類型安全的通用類型轉換器

    Java泛型實現(xiàn)類型安全的通用類型轉換器

    在開發(fā)中,我們常常需要在不同類型之間進行轉換,為了提高代碼的可讀性與安全性,Java的泛型機制提供了強大的類型檢查能力,下面我們就來看看如何通過泛型實現(xiàn)類型安全的通用轉換器
    2024-11-11
  • Java實現(xiàn)冒泡排序

    Java實現(xiàn)冒泡排序

    這篇文章主要為大家詳細介紹了Java實現(xiàn)冒泡排序,把一列數(shù)組按從小到大或從大到小排序,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08

最新評論