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

网站开发平台的定义如何搜索网页关键词

网站开发平台的定义,如何搜索网页关键词,企业模板网站建设优势分析,如何做摄影网站1. 简介 为了体现我们的实力,首先我们要有造轮子的能力。这意味着我们不仅要熟练掌握现有的技术栈和框架,还要具备深厚的技术功底。通过自主设计和实现关键组件,如高性能缓存系统,我们能够深入理解技术背后的原理,掌握…

1. 简介

为了体现我们的实力,首先我们要有造轮子的能力。这意味着我们不仅要熟练掌握现有的技术栈和框架,还要具备深厚的技术功底。通过自主设计和实现关键组件,如高性能缓存系统,我们能够深入理解技术背后的原理,掌握核心技术的精髓,从而在面对复杂问题时能够提出独到见解和解决方案。

本篇文章将带大家实现一个简化版但功能类似Spring Cache的缓存组件。虽然不会像Spring Cache那样全面和复杂,但我们将通过动手实践,掌握缓存机制的核心原理。

2. 实战案例

2.1 环境准备

既然是基于redis实现,那么我们通过引入以下依赖来简化环境配置

<dependency>  
<groupId>org.springframework.boot</groupId>  
<artifactId>spring-boot-starter-data-redis</artifactId></dependency>

通过data-redis,我们需要做的就是配置redis服务器信息即可。

spring:redis:timeout: 10000connectTimeout: 20000host: 127.0.0.1password: xxxooolettuce:pool:maxActive: 8maxIdle: 100minIdle: 10maxWait: -1

通过以上的配置,在项目中我们就可以直接通过SpringBoot自动配置的StringRedisTemplate来实现各种操作。

2.2 自定义注解

这里我们仿照spring-cache定义如下两个注解(@Cacheable 触发缓存, @CacheEvict 删除缓存)。

**@Cacheable:**设置缓存或读取缓存;如果缓存中存在直接返回,如果不存在则将方法返回值设置到缓存中。

**@CacheEvict:**将当前指定key从缓存中删除。

触发缓存:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Cacheable {// 缓存Key;String key() default "" ;// 缓存名称(类似分组)String name() default "" ;
}

删除缓存


@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface CacheEvict {// 缓存KeyString key() default "" ;// 缓存名称(类似分组)String name() default "" ;
}

以上2个注解基本相同,分别完成读写,清除缓存操作。

注:为了灵活,我们需要让上面注解中的key支持SpEL表达式。

2.3 定义切面

该切面用来处理带有上面注解的类或方法,如:方法上有**@Cacheable**注解,那么先从缓存中读取内容,如果缓存中不存在则将当前方法返回值写入缓存中。

@Component
@Aspect
public class CacheAspect {private static final Logger logger = LoggerFactory.getLogger(CacheAspect.class) ;private final StringRedisTemplate stringRedisTemplate ;public CacheAspect(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate = stringRedisTemplate ;}private DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer() ;@Pointcut("@annotation(com.pack.redis.cache.Cacheable)")private void cacheable() {}@Pointcut("@annotation(com.pack.redis.cache.CacheEvict)")private void cacheevict() {}@Around("cacheable() || cacheevict()") public Object proceed(ProceedingJoinPoint pjp) throws Throwable {Object ret = null ;Method method = ((MethodSignature) pjp.getSignature()).getMethod() ;Object[] args = pjp.getArgs() ;// SPEL 表达式解析SpelExpressionParser parser = new SpelExpressionParser() ;StandardEvaluationContext context = new StandardEvaluationContext() ;// 获取参数名称String[] parameterNames = discoverer.getParameterNames(method) ;for (int i = 0, len = parameterNames.length; i < len; i++) {context.setVariable(parameterNames[i], args[i]) ;}// 类上的注解不做处理了;只处理方法上Cacheable cacheable = method.getAnnotation(Cacheable.class) ;if (cacheable != null) {// 假设都配置了name和keyString name = cacheable.name() ;String expression = cacheable.key() ;Object value = parser.parseExpression(expression).getValue(context) ;String cacheKey = name + ":" + value;boolean hasKey = this.stringRedisTemplate.hasKey(cacheKey) ;if (!hasKey) {ret = pjp.proceed() ;this.stringRedisTemplate.opsForValue().set(cacheKey, new ObjectMapper().writeValueAsString(ret)) ;logger.info("写缓存【{}】,数据:{}", cacheKey, ret) ;return ret ; }logger.info("从缓存【{}】获取", cacheKey);String result = this.stringRedisTemplate.opsForValue().get(cacheKey) ;return new ObjectMapper().readValue(result, method.getReturnType()) ;}CacheEvict cacheevict = method.getAnnotation(CacheEvict.class) ;if (cacheevict != null) {String name = cacheevict.name() ;String expression = cacheevict.key() ;Object value = parser.parseExpression(expression).getValue(context) ;String cacheKey = name + ":" + value ;this.stringRedisTemplate.delete(cacheKey) ;}return pjp.proceed() ;}}

上面的环绕通知通过或(||)表达式的方式拦截2个注解,实现比较的简单主要是结合了SpEL表达式。上面的代码我们假设是你key进行了配置,如果没有配置,我们可以通过如下方式去生成key

private String getKey(Class<?> targetType, Method method) {StringBuilder builder = new StringBuilder();builder.append(targetType.getSimpleName());builder.append('#').append(method.getName()).append('(');Class<?>[] types = method.getParameterTypes() ;for (Class<?> clazz : types) {builder.append(clazz.getSimpleName()).append(",") ;}if (method.getParameterTypes().length > 0) {builder.deleteCharAt(builder.length() - 1);}return (builder.append(')').toString()).replaceAll("[^a-zA-Z0-9]", "") ;
}

如果你没有配置key,可以通过当前执行的类及方法生成唯一的key。

2.4 测试

这里我是通过JPA实现CRUD操作

@Service
public class UserService {private final UserRepository userRepository ;public UserService(UserRepository userRepository) {this.userRepository = userRepository ;}@Cacheable(name = "user", key = "#id")public User queryById(Long id) {return this.userRepository.findById(id).orElse(null) ;}@CacheEvict(name = "user", key = "#user.id")public void clearUserById(User user) {this.userRepository.deleteById(user.getId()) ;}
}

这里的clearUserById方法是有意将方法参数设置为User对象,就是为了方便演示SpEL表达式的使用。

测试接口

@GetMapping("/{id}")
public User getUser(@PathVariable("id") Long id) {return this.userService.queryById(id) ;
}@DeleteMapping("/{id}")
public void removeUser(@PathVariable("id") Long id) {User user = new User() ;user.setId(id) ;this.userService.clearUserById(user) ;
}

到此,一个简单的缓存组件就实现了。这里待完善及优化的还是非常多的,比如更新缓存,并发量大时缓存那里是不是应该加锁,不然肯定会有很多的线程都执行查询再存入缓存;我们这里是不是还可以借助本地缓存做多级缓存的优化呢?可以参考下面这篇文章。

[[Redis结合Caffeine实现二级缓存:提高应用程序性能]]

http://www.hkea.cn/news/462498/

相关文章:

  • 跳网站查询的二维码怎么做的关键词排名点击软件网站
  • 兼容手机的网站百度怎么推广自己的视频
  • 宝安中心医院入职体检跟我学seo
  • 企业网站后端模板石家庄疫情最新情况
  • 沈阳哪家网站做的好网络营销是指什么
  • 我的网站模板网站建设主要推广方式
  • 国外app素材网站seo运营是做什么的
  • 企业网站seo怎么做百度帐号个人中心
  • 郑州网站建设亅汉狮网络百度网盘seo优化
  • 模板型网站seo优化平台
  • 官方网站下载免费软件培训机构有哪些?哪个比较好
  • 网站导航怎么做的惠州seo计费管理
  • 建设公司网站模板全国唯一一个没有疫情的城市
  • 网站怎么做seo_南京百度提升优化
  • 旅游网站开发与设计论文怎么样建网站
  • 北京网站推广排名公司企业网站的搜索引擎推广与优化
  • 动态网站期末设计广告营销策略
  • 山东网站营销推广费用旺道seo推广
  • 邢台网站建设服务周到百度数据分析工具
  • 周口网站建设竞价恶意点击犯法吗
  • 网站建设没有预付款seo快速提升排名
  • 网站开发者的设计构想网络推广平台软件
  • 做立体字的网站重庆seo公司排名
  • 电子商务网站的建设包含哪些流程搜索引擎关键词怎么优化
  • 将自己做的网站发布到谷歌推广新手教程
  • 深圳保障性住房管理办法seo排名优化方法
  • 2022注册公司取名推荐网络营销的优化和推广方式
  • 做网站费是多少贵州二级站seo整站优化排名
  • 做网站潍坊培训课程安排
  • python做网站需要什么seo学习论坛