撸完Spring源码,我为Spring写了个分布式缓存插件,现已开源,快要裂开了!!

最后

码字不易,觉得有帮助的可以帮忙点个赞,让更多有需要的人看到

又是一年求职季,在这里,我为各位准备了一套Java程序员精选高频面试笔试真题,来帮助大家攻下BAT的offer,题目范围从初级的Java基础到高级的分布式架构等等一系列的面试题和答案,用于给大家作为参考

以下是部分内容截图
架构面试专题及架构学习笔记导图.png

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

属性值的加载顺序为:优先加载自定义的redis配置文件的redis.cluster.preloadSecondTime属性值,如果自定义的redis配置文件无相关的属性值;则从框架默认的redis配置文件redis-default.properties文件中加载;

3)当 @Cacheable 的Value配置缓存名称、失效时长和距离缓存失效的剩余时长,比如配置为:@Cacheable(value=“test#10#2”)

此时不会加载默认的expireTime和reloadTime,框架会直接使用@Cacheable注解中value属性配置的expireTime和reloadTime;

4)无论@Cacheable的Value属性是否配置了缓存时长信息,则都不会出现只配置reloadTime,没有配置expireTime的情况,框架规定的value属性格式为:缓存名称#expireTime#reloadTime

即只会出现的格式为:

  • 缓存名称

  • 缓存名称#expireTime

  • 缓存名称#expireTime#reloadTime

不会存在单独出现reloadTime的情况,会出现配置了缓存名称#expireTime,reloadTime使用配置文件默认的时长配置的情况;

注意事项

1.mykit-cache-redis-spring-xml引用和mykit-cache-redis-spring-annotation引用是互斥的,即在一个工程中mykit-cache-redis-spring-xml和mykit-cache-redis-spring-annotation只能同时引用一个;

2.mykit-cache-redis-spring-xml和mykit-cache-redis-spring-annotation的功能是一样的,但是mykit-cache-redis-spring-annotation工程兼容Redis集群宕机或其他原因无法连接Redis集群时的情况;

3.如果Redis集群宕机或其他原因无法连接Redis集群时,则mykit-cache-redis-spring-xml会抛出异常,退出执行;而mykit-cache-redis-spring-annotation则会打印相关的异常信息,继续向下执行原来的方法。

4.如果你的项目中以XML配置的方式,配置了Spring容器和SpringMVC,而你想以兼容Redis集群宕机或其他原因连接不上Redis集群的方式配置缓存,可以经过如下配置:

1)在项目中添加如下配置类:

SpringContextConfig:配置Spring容器:

package io.mykit.cache.redis.spring.utils.config;

import org.springframework.cache.annotation.EnableCaching;

import org.springframework.context.annotation.ComponentScan;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.EnableAspectJAutoProxy;

import org.springframework.context.annotation.ImportResource;

import org.springframework.context.annotation.PropertySource;

import io.mykit.cache.redis.spring.annotation.config.CacheRedisConfig;

/**

  • @ClassName SpringContextConfig

  • @Description Spring Java配置

  • @author binghe

*/

@Configuration

@EnableCaching

@EnableAspectJAutoProxy(proxyTargetClass = true)

@ComponentScan(value = {“io.mykit.cache”})

@PropertySource(value = {“classpath:properties/redis-default.properties”, “classpath:properties/redis.properties”})

@ImportResource(“classpath:spring/applicationContext.xml”)

public class SpringContextConfig extends CacheRedisConfig{

}

SpringMVCConfig:配置SpringMVC:

package io.mykit.cache.redis.spring.utils.config;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.ImportResource;

/**

  • @ClassName SpringMVCConfig

  • @Description SpringMVC Java配置

  • @author binghe

*/

@Configuration

@ImportResource(“classpath:spring/SpringMVC-servlet.xml”)

public class SpringMVCConfig {

}

2)web项目的web.xml修改如下:

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”

xmlns=“http://java.sun.com/xml/ns/javaee” xmlns:web=“http://java.sun.com/xml/ns/javaee”

xsi:schemaLocation=“http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd”

version=“3.0”>

org.springframework.web.context.ContextLoaderListener

contextClass

org.springframework.web.context.support.AnnotationConfigWebApplicationContext

contextConfigLocation

io.mykit.cache.redis.spring.utils.config.SpringContextConfig

org.springframework.web.util.IntrospectorCleanupListener

SpringMVC

org.springframework.web.servlet.DispatcherServlet

contextClass

org.springframework.web.context.support.AnnotationConfigWebApplicationContext

contextConfigLocation

io.mykit.cache.redis.spring.utils.config.SpringMVCConfig

1

SpringMVC

/

3.需要使用Spring+Memcached集群配置缓存


1、需要在工程的pom.xml中引用

io.mykit.cache

mykit-cache-memcached-spring-simple-xml

1.0.0-SNAPSHOT

注意:框架的此模块不支持主动刷新缓存,底层核心使用的是simple-spring-memcached内核。

2、使用方法

1)在自身项目的classpath:properties目录下新建Memcached的配置文件,比如:memcached.properties文件,配置连接Memcached的属性;

属性配置如下:

#simple memcached config

simple.memcache.server=127.0.0.1:12000

simple.memcache.consistenthashing=true

simple.memcache.connectionpoolsize=1

simple.memcache.optimizeget=false

simple.memcache.optimizemergebuffer=false

simple.memcache.mergefactor=50

simple.memcache.usebinaryprotocol=true

simple.memcache.connectiontimeout=3000

simple.memcache.operationtimeout=2000

simple.memcache.enableheartbeat=true

simple.memcache.failureMode=false

注意:自定义的memcached文件的属性,必须和memcached-default.properties默认配置的属性key相同,也就是和上述配置的key相同,但可以不用覆盖上述完整的配置,

可以只配置:

simple.memcache.server=192.168.209.121:12000

来覆盖simple.memcache.server属性

2)在自身项目的classpath目录下新建spring配置文件,比如:spring-context.xml,配置内容如下:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns=“http://www.springframework.org/schema/beans”

xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”

xmlns:p=“http://www.springframework.org/schema/p”

xmlns:aop=“http://www.springframework.org/schema/aop”

xmlns:context=“http://www.springframework.org/schema/context”

xmlns:cache=“http://www.springframework.org/schema/cache”

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-4.2.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-4.2.xsd

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop-4.2.xsd

http://www.springframework.org/schema/cache

http://www.springframework.org/schema/cache/spring-cache-4.2.xsd">

<context:annotation-config />

aop:aspectj-autoproxy/

<context:component-scan base-package=“io.mykit.cache”/>

<context:property-placeholder location=“classpath*:properties/memcached-default.properties, classpath*:properties/memcached.properties” system-properties-mode=“FALLBACK”/>

<context:annotation-config />

<context:component-scan base-package=“io.mykit.cache” />

根据上述配置加载properties文件顺序,框架会用自定义的memcached.properties文件属性覆盖memcached-default.properties文件的属性。

如果memcached-default.properties文件中存在memcached.properties中不存在的属性,框架会用memcached-default.properties中默认的属性。

至此,就可以使用simple-spring-memcached提供的注解来配置使用缓存了。

3、simple-spring-memcached介绍

3-1、基本介绍

simple-spring-memcached本质上是采用了AOP的方式来实现缓存的调用和管理,其核心组件声明了一些Advice,当遇到相应的切入点时,会执行这些Advice来对memcached加以管理。

切入点是通过标签的方式来进行声明的,在项目开发时,通常在DAO的方法上加以相应的标签描述,来表示组件对该方法的拦截 组件所提供的切入点主要包括以下几种:

ReadThroughSingleCache、ReadThroughMultiCache、ReadThroughAssignCache

1)当遇到查询方法声明这些切入点时,组件首先会从缓存中读取数据,取到数据则跳过查询方法,直接返回。 取不到数据在执行查询方法,并将查询结果放入缓存,以便下一次获取。 InvalidateSingleCache、InvalidateMultiCache、InvalidateAssignCache

2)当遇到删除方法声明这些切入点时,组件会删除缓存中的对应实体,以便下次从缓存中读取出的数据状态是最新的 UpdateSingleCache、UpdateMultiCache、UpdateAssignCache

3-2、注解说明

各Annotation的详细说明

  • ReadThroughSingleCache

作用:读取Cache中数据,如果不存在,则将读取的数据存入Cachekey生成规则:ParameterValueKeyProvider指定的参数,如果该参数对象中包含CacheKeyMethod注解的方法,则调用其方法,否则调用toString方法

@ReadThroughSingleCache(namespace = “Alpha”, expiration = 30)

public String getDateString(@ParameterValueKeyProvider final String key) {

final Date now = new Date();

try {

Thread.sleep(1500);

} catch (InterruptedException ex) {

}

return now.toString() + “:” + now.getTime();

}

  • InvalidateSingleCache

作用:失效Cache中的数据

key生成规则:

1)使用 ParameterValueKeyProvider注解时,与ReadThroughSingleCache一致

2)使用 ReturnValueKeyProvider 注解时,key为返回的对象的CacheKeyMethod或toString方法生成

@InvalidateSingleCache(namespace = “Charlie”)

public void updateRandomString(@ParameterValueKeyProvider final Long key) {

// Nothing really to do here.

}

@InvalidateSingleCache(namespace = “Charlie”)

@ReturnValueKeyProvider

public Long updateRandomStringAgain(final Long key) {

return key;

}

  • UpdateSingleCache

作用:更新Cache中的数据

key生成规则:ParameterValueKeyProvider指定

1)ParameterDataUpdateContent:方法参数中的数据,作为更新缓存的数据

2)ReturnDataUpdateContent:方法调用后生成的数据,作为更新缓存的数据

注:上述两个注解,必须与Update*系列的注解一起使用

@UpdateSingleCache(namespace = “Alpha”, expiration = 30)

public void overrideDateString(final int trash, @ParameterValueKeyProvider final String key,

@ParameterDataUpdateContent final String overrideData) {

}

@UpdateSingleCache(namespace = “Bravo”, expiration = 300)

@ReturnDataUpdateContent

public String updateTimestampValue(@ParameterValueKeyProvider final Long key) {

try {

Thread.sleep(100);

} catch (InterruptedException ex) {

}

final Long now = new Date().getTime();

final String result = now.toString() + “-U-” + key.toString();

return result;

}

  • ReadThroughAssignCache

作用:读取Cache中数据,如果不存在,则将读取的数据存入Cache

key生成规则: ReadThroughAssignCache 注解中的 assignedKey 字段指定

@ReadThroughAssignCache(assignedKey = “SomePhatKey”, namespace = “Echo”, expiration = 3000)

public List getAssignStrings() {

try {

Thread.sleep(500);

} catch (InterruptedException ex) {

}

final List results = new ArrayList();

final long extra = System.currentTimeMillis() % 20;

final String base = System.currentTimeMillis() + “”;

for (int ix = 0; ix < 20 + extra; ix++) {

results.add(ix + “-” + base);

}

return results;

}

  • InvalidateAssignCache

作用:失效缓存中指定key的数据

key生成规则:assignedKey 字段指定

@InvalidateAssignCache(assignedKey = “SomePhatKey”, namespace = “Echo”)

public void invalidateAssignStrings() {

}

  • UpdateAssignCache

作用:更新指定缓存

key生成规则:assignedKey 字段指定

@UpdateAssignCache(assignedKey = “SomePhatKey”, namespace = “Echo”, expiration = 3000)

public void updateAssignStrings(int bubpkus, @ParameterDataUpdateContent final List newData) {

}

4.需要使用Spring + Ehcache集群配置缓存


框架此模块暂时不做实现,由于Spring与Ehcache的整合过于简单,可自行实现Spring与Ehcache的整合,这个不提供封装了。

spring4配置基于注解的ehcache缓存

1. ehcache配置文件ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>

<defaultCache

maxElementsInMemory=“10000”

eternal=“false”

timeToIdleSeconds=“30”

timeToLiveSeconds=“30”

overflowToDisk=“true”>

<cache name=“statisticServiceCache”

maxElementsInMemory=“1000”

eternal=“false”

overflowToDisk=“true”

timeToIdleSeconds=“900”

timeToLiveSeconds=“1800”

diskPersistent=“false”

memoryStoreEvictionPolicy=“LFU” />

2.spring-cache注解及ehcache bean配置

<cache:annotation-driven cache-manager=“cacheManager”/>

3.确认开启了spring的aop支持

aop:aspectj-autoproxy/

4.Spring的cache注解的使用

(1)@Cacheable

@Cacheable 主要的参数

  • value

缓存的名称,在 spring 配置文件中定义,必须指定至少一个

例如:

@Cacheable(value=”mycache”) 或者

@Cacheable(value={”cache1”,”cache2”}

  • key

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合

例如:

@Cacheable(value=”testcache”,key=”#userName”)

  • condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存

例如:

@Cacheable(value=”testcache”,condition=”#userName.length()

如下示例:

@Cacheable(value = “statisticServiceCache”, key = “‘activityChartData_’ + #urlID”)

public ResultInfo getActivityChartData(String urlID, Date startMonth,Date endMonth) {

}

这个注解用于,在调用被注解的方法时,首先检查当前缓存系统中是否存在键值为key的缓存。如果存在,则直接返回缓存对象,不执行该方法。如果不存在,则调用该方法,并将得到的返回值写入缓存中。

(2)@CachePut

@CachePut 主要的参数

  • value

缓存的名称,在 spring 配置文件中定义,必须指定至少一个

例如:

@Cacheable(value=”mycache”) 或者

@Cacheable(value={”cache1”,”cache2”}

  • key

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合

例如:

@Cacheable(value=”testcache”,key=”#userName”)

  • condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存

例如:

@Cacheable(value=”testcache”,condition=”#userName.leng

@CachePut用于写入缓存,但是与@ Cacheable不同,@CachePut注解的方法始终执行,然后将方法的返回值写入缓存,此注解主要用于新增或更新缓存。

(3) @CacheEvict

@CacheEvict 主要的参数

  • value

缓存的名称,在 spring 配置文件中定义,必须指定至少一个

例如:

@CachEvict(value=”mycache”) 或者

@CachEvict(value={”cache1”,”cache2”}

  • key

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合

例如:

@CachEvict(value=”testcache”,key=”#userName”)

  • condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才清空缓存

例如:

@CachEvict(value=”testcache”, condition=”#userName.length()>2”)

  • allEntries

是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存

例如:

@CachEvict(value=”testcache”,allEntries=true)

  • beforeInvocation

是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存

例如:

@CachEvict(value=”testcache”,beforeInvocation=true)

@CacheEvict用于删除缓存

注意事项


无论使用哪种模块,需要在相关的项目中配置ApplicationContext到SpringContextWrapper中。

示例代码如下:

package io.mykit.cache.test.redis.spring.utils;

import io.mykit.cache.redis.spring.context.SpringContextWrapper;

import lombok.extern.slf4j.Slf4j;

import org.springframework.context.ApplicationContext;

import org.springframework.context.ApplicationContextAware;

import org.springframework.stereotype.Component;

import redis.clients.util.Hashing;

/**

  • @author binghe

  • @version 1.0.0

  • @description 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候中取出ApplicaitonContext.

*/

@Slf4j

@Component

public class SpringContext implements ApplicationContextAware {

private static ApplicationContext applicationContext;

/**

  • 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量.

*/

@Override

public void setApplicationContext(ApplicationContext applicationContext) {

SpringContext.applicationContext = applicationContext; // NOSONAR

log.debug(SpringContext.class.getName() + " 类加载的路径:" + this.getClass().getResource(“/”).getPath() + “, hashcode:” + Hashing.MURMUR_HASH.hash(this.getClass().getResource(“/”).getPath()));

log.debug(SpringContext.class.getName() + " applicationContext===>>>" + applicationContext);

SpringContextWrapper.setApplicationContext(SpringContextWrapper.getContextKey(this.getClass()), applicationContext);

}

/**

  • 取得存储在静态变量中的ApplicationContext.

  • @return ApplicationContext对象

*/

public static ApplicationContext getApplicationContext() {

checkApplicationContext();

return applicationContext;

}

/**

  • 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.

  • @param name Spring中Bean的名称

  • @return 泛型对象

*/

@SuppressWarnings(“unchecked”)

public static T getBean(String name) {

checkApplicationContext();

return (T) applicationContext.getBean(name);

}

/**

  • 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.

  • @param clazz 指定的clazz对象

  • @return 泛型对象

*/

public static T getBean(Class clazz) {

checkApplicationContext();

return (T) applicationContext.getBean(clazz);

}

/**

  • 清除applicationContext静态变量.

*/

public static void cleanApplicationContext() {

applicationContext = null;

}

private static void checkApplicationContext() {

if (applicationContext == null) {

throw new IllegalStateException(“applicaitonContext未注入,请在applicationContext.xml中定义SpringContextHolder”);

}

}

}

本项目还在开发中,目前未添加到Maven中央仓库,后续开发完成会添加到Maven中央仓库。

如果这个框架对大家有点帮助,还请小伙伴们打开Github和Gitee链接,给这个项目一个大大的Star,让更多的小伙伴收益。也可以为这篇文章点赞、在看和转发哦~~

写在最后


如果你想进大厂,想升职加薪,或者对自己现有的工作比较迷茫,都可以私信我交流,希望我的一些经历能够帮助到大家~~

推荐阅读:

总结

面试难免让人焦虑不安。经历过的人都懂的。但是如果你提前预测面试官要问你的问题并想出得体的回答方式,就会容易很多。

此外,都说“面试造火箭,工作拧螺丝”,那对于准备面试的朋友,你只需懂一个字:刷!

给我刷刷刷刷,使劲儿刷刷刷刷刷!今天既是来谈面试的,那就必须得来整点面试真题,这不花了我整28天,做了份“Java一线大厂高岗面试题解析合集:JAVA基础-中级-高级面试+SSM框架+分布式+性能调优+微服务+并发编程+网络+设计模式+数据结构与算法等”

image

且除了单纯的刷题,也得需准备一本【JAVA进阶核心知识手册】:JVM、JAVA集合、JAVA多线程并发、JAVA基础、Spring 原理、微服务、Netty与RPC、网络、日志、Zookeeper、Kafka、RabbitMQ、Hbase、MongoDB、Cassandra、设计模式、负载均衡、数据库、一致性算法、JAVA算法、数据结构、加密算法、分布式缓存、Hadoop、Spark、Storm、YARN、机器学习、云计算,用来查漏补缺最好不过。

image

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

如果这个框架对大家有点帮助,还请小伙伴们打开Github和Gitee链接,给这个项目一个大大的Star,让更多的小伙伴收益。也可以为这篇文章点赞、在看和转发哦~~**

写在最后


如果你想进大厂,想升职加薪,或者对自己现有的工作比较迷茫,都可以私信我交流,希望我的一些经历能够帮助到大家~~

推荐阅读:

总结

面试难免让人焦虑不安。经历过的人都懂的。但是如果你提前预测面试官要问你的问题并想出得体的回答方式,就会容易很多。

此外,都说“面试造火箭,工作拧螺丝”,那对于准备面试的朋友,你只需懂一个字:刷!

给我刷刷刷刷,使劲儿刷刷刷刷刷!今天既是来谈面试的,那就必须得来整点面试真题,这不花了我整28天,做了份“Java一线大厂高岗面试题解析合集:JAVA基础-中级-高级面试+SSM框架+分布式+性能调优+微服务+并发编程+网络+设计模式+数据结构与算法等”

[外链图片转存中…(img-tNx3Nt5u-1715546202395)]

且除了单纯的刷题,也得需准备一本【JAVA进阶核心知识手册】:JVM、JAVA集合、JAVA多线程并发、JAVA基础、Spring 原理、微服务、Netty与RPC、网络、日志、Zookeeper、Kafka、RabbitMQ、Hbase、MongoDB、Cassandra、设计模式、负载均衡、数据库、一致性算法、JAVA算法、数据结构、加密算法、分布式缓存、Hadoop、Spark、Storm、YARN、机器学习、云计算,用来查漏补缺最好不过。

[外链图片转存中…(img-kni7o0B7-1715546202395)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值