最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

一、概述

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

二、實(shí)戰(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(啟動(dòng)類加上:@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ù)庫賬號(hào)
spring.datasource.password = 數(shù)據(jù)庫密碼
#redis config
spring.redis.host = redis主機(jī)
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"/>
? ? <!--默認(rèn)緩存策略 -->
? ? <!-- external:是否永久存在,設(shè)置為true則不會(huì)被清除,此時(shí)與timeout沖突,通常設(shè)置為false-->
? ? <!-- diskPersistent:是否啟用磁盤持久化-->
? ? <!-- maxElementsInMemory:最大緩存數(shù)量-->
? ? <!-- overflowToDisk:超過最大緩存數(shù)量是否持久化到磁盤-->
? ? <!-- timeToIdleSeconds:最大不活動(dòng)間隔,設(shè)置過長(zhǎng)緩存容易溢出,設(shè)置過短無效果,單位:秒-->
? ? <!-- timeToLiveSeconds:最大存活時(shí)間,單位:秒-->
? ? <!-- 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注解,也可加在啟動(dòng)類上)

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

5、測(cè)試demo

這里可以將一級(jí)緩存、二級(jí)緩存時(shí)效設(shè)置短一些,方便進(jìn)行測(cè)試。

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

6、啟動(dòng)類上的:@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、導(dǎo)入的:

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);
? ? // 導(dǎo)入了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類(代碼有所簡(jiǎn)化):

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

9、導(dǎo)入的第一個(gè)類看完了,接著看導(dǎo)入的第二個(gè)類: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) {
?? ??? ?// ?構(gòu)建BeanFactoryCacheOperationSourceAdvisor
? ? BeanFactoryCacheOperationSourceAdvisor advisor = new BeanFactoryCacheOperationSourceAdvisor();
?? ??? ?// 設(shè)置緩存注解解析器
? ? advisor.setCacheOperationSource(cacheOperationSource);
?? ??? ?// 設(shè)置緩存攔截器: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) {
? ? ? ? // 解析緩存相關(guān)注解,返回CacheOperation
? ? ? ? // 每個(gè)緩存注解對(duì)應(yīng)一種不同的解析處理操作
? ? ? ? // 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í)行目標(biāo)方法
?? ??? ??? ?returnValue = invokeOperation(invoker);
?? ??? ??? ?cacheValue = unwrapReturnValue(returnValue);
?? ??? ?}
?? ??? ?// 解析處理@CachePut注解
?? ??? ?collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests);
?? ??? ?// 未命中緩存時(shí),會(huì)封裝一個(gè)cachePutRequests
? ?? ?// 然后通過反射執(zhí)行目標(biāo)方法后,執(zhí)行該方法,最終調(diào)用EhCacheCache.put方法將數(shù)據(jù)寫入緩存中
?? ??? ?for (CachePutRequest cachePutRequest : cachePutRequests) {
?? ??? ??? ?cachePutRequest.apply(cacheValue);
?? ??? ?}
?? ??? ?// 解析處理@CacheEvict注解,和上面的方法相同,只不過第二個(gè)參數(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屬性
? ? ? ? // 若未配置則默認(rèn)使用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ù)只有一個(gè),則返回該參數(shù)
?? ??? ?if (params.length == 1) {
?? ??? ??? ?Object param = params[0];
?? ??? ??? ?if (param != null && !param.getClass().isArray()) {
?? ??? ??? ??? ?return param;
?? ??? ??? ?}
?? ??? ?}
? ?? ?// 否則將方法參數(shù)進(jìn)行封裝,返回SimpleKey
?? ??? ?return new SimpleKey(params);
?? ?}
private Cache.ValueWrapper findInCaches(CacheOperationContext context, Object key) {
?? ??? ?for (Cache cache : context.getCaches()) {
? ? ? // 從一級(jí)緩存中獲取數(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,所以最終會(huì)調(diào)用EhCacheCache.get方法獲取緩存中的數(shù)據(jù)
?? ??? ??? ?return cache.get(key);
?? ??? ?}
?? ??? ?catch (RuntimeException ex) {
?? ??? ??? ?getErrorHandler().handleCacheGetError(ex, cache, key);
?? ??? ??? ?return null;
?? ??? ?}
?? ?}

三、總結(jié)

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

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

相關(guān)文章

  • zookeeper集群搭建超詳細(xì)過程

    zookeeper集群搭建超詳細(xì)過程

    這篇文章主要介紹了zookeeper集群搭建超詳細(xì)過程,本文對(duì)zookeeper集群測(cè)試通過圖文并茂的形式給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06
  • Spring Boot Swagger2使用方法過程解析

    Spring Boot Swagger2使用方法過程解析

    這篇文章主要介紹了Spring Boot Swagger2使用方法過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • Spring Boot 中的 @PutMapping 注解原理及使用小結(jié)

    Spring Boot 中的 @PutMapping 注解原理及使用小結(jié)

    在本文中,我們介紹了 Spring Boot 中的 @PutMapping 注解,它可以將 HTTP PUT 請(qǐng)求映射到指定的處理方法上,我們還介紹了 @PutMapping 注解的原理以及如何在 Spring Boot 中使用它,感興趣的朋友跟隨小編一起看看吧
    2023-12-12
  • Java類中this關(guān)鍵字與static關(guān)鍵字的用法解析

    Java類中this關(guān)鍵字與static關(guān)鍵字的用法解析

    這篇文章主要介紹了Java類中this關(guān)鍵字與static關(guān)鍵字的用法解析,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-09-09
  • SpringBoot 中常用注解及各種注解作用

    SpringBoot 中常用注解及各種注解作用

    本篇文章將介紹幾種SpringBoot 中常用注解及各個(gè)注解的作用,感興趣的朋友跟隨腳本之家小編一起學(xué)習(xí)吧
    2018-03-03
  • Spring中的@RefreshScope注解作用

    Spring中的@RefreshScope注解作用

    這篇文章主要介紹了Spring中的@RefreshScope注解作用詳解,@RefreshScope注解是Spring Cloud中的一個(gè)重要注解,用于實(shí)現(xiàn)動(dòng)態(tài)刷新配置的功能,當(dāng)我們?cè)趹?yīng)用程序中使用@Value注解獲取配置屬性時(shí),如果配置發(fā)生變化,需要重啟應(yīng)用程序才能生效,需要的朋友可以參考下
    2023-10-10
  • SpringMvc響應(yīng)數(shù)據(jù)及結(jié)果視圖實(shí)現(xiàn)代碼

    SpringMvc響應(yīng)數(shù)據(jù)及結(jié)果視圖實(shí)現(xiàn)代碼

    這篇文章主要介紹了SpringMvc響應(yīng)數(shù)據(jù)及結(jié)果視圖實(shí)現(xiàn)代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • 基于SpringBoot + Redis實(shí)現(xiàn)密碼暴力破解防護(hù)

    基于SpringBoot + Redis實(shí)現(xiàn)密碼暴力破解防護(hù)

    在現(xiàn)代應(yīng)用程序中,保護(hù)用戶密碼的安全性是至關(guān)重要的,密碼暴力破解是指通過嘗試多個(gè)密碼組合來非法獲取用戶賬戶的密碼,為了保護(hù)用戶密碼不被暴力破解,我們可以使用Spring Boot和Redis來實(shí)現(xiàn)一些防護(hù)措施,本文將介紹如何利用這些技術(shù)來防止密碼暴力破解攻擊
    2023-06-06
  • 實(shí)例講解Java基礎(chǔ)之反射

    實(shí)例講解Java基礎(chǔ)之反射

    今天小編就為大家分享一篇關(guān)于實(shí)例講解Java基礎(chǔ)之反射,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • Struts2數(shù)據(jù)輸入驗(yàn)證教程詳解

    Struts2數(shù)據(jù)輸入驗(yàn)證教程詳解

    這篇文章主要介紹了Struts2數(shù)據(jù)輸入驗(yàn)證教程詳解的相關(guān)資料,輸入數(shù)據(jù)驗(yàn)證的方法有兩種,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2016-10-10

最新評(píng)論

溧阳市| 余江县| 宝应县| 阿鲁科尔沁旗| 兴安盟| 佛教| 吴川市| 三原县| 苗栗市| 磐石市| 开平市| 平乡县| 巴里| 禄劝| 淮南市| 天全县| 丹寨县| 靖远县| 文昌市| 星子县| 大石桥市| 屏南县| 恭城| 桃源县| 铜川市| 灌阳县| 利津县| 白城市| 上林县| 来安县| 义乌市| 广元市| 克山县| 台南市| 文山县| 晋城| 金沙县| 丽江市| 子长县| 中方县| 元氏县|