-
Notifications
You must be signed in to change notification settings - Fork 39
Aaaa #86
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ShanqingHuang98
wants to merge
3
commits into
master
Choose a base branch
from
aaaa
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Aaaa #86
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
109 changes: 108 additions & 1 deletion
109
src/main/java/com/github/hcsp/annotation/CacheClassDecorator.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,23 +1,130 @@ | ||
| package com.github.hcsp.annotation; | ||
|
|
||
| import net.bytebuddy.ByteBuddy; | ||
| import net.bytebuddy.implementation.MethodDelegation; | ||
| import net.bytebuddy.implementation.bind.annotation.AllArguments; | ||
| import net.bytebuddy.implementation.bind.annotation.Origin; | ||
| import net.bytebuddy.implementation.bind.annotation.RuntimeType; | ||
| import net.bytebuddy.implementation.bind.annotation.SuperCall; | ||
| import net.bytebuddy.implementation.bind.annotation.This; | ||
| import net.bytebuddy.matcher.ElementMatchers; | ||
|
|
||
| import java.lang.reflect.Method; | ||
| import java.util.Arrays; | ||
| import java.util.Objects; | ||
| import java.util.concurrent.Callable; | ||
| import java.util.concurrent.ConcurrentHashMap; | ||
|
|
||
| public class CacheClassDecorator { | ||
| // 将传入的服务类Class进行增强 | ||
| // 使得返回一个具有如下功能的Class: | ||
| // 如果某个方法标注了@Cache注解,则返回值能够被自动缓存注解所指定的时长 | ||
| // 这意味着,在短时间内调用同一个服务的同一个@Cache方法两次 | ||
| // 它实际上只被调用一次,第二次的结果直接从缓存中获取 | ||
| // 注意,缓存的实现需要是线程安全的 | ||
| @SuppressWarnings("unchecked") | ||
| public static <T> Class<T> decorate(Class<T> klass) { | ||
| return klass; | ||
| return (Class<T>) new ByteBuddy() | ||
| // 对带有cache缓存的方法进行增强 | ||
| .subclass(klass) | ||
| .method(ElementMatchers.isAnnotatedWith(Cache.class)) | ||
| .intercept(MethodDelegation.to(CacheAdvisor.class)) | ||
| .make() | ||
| .load(klass.getClassLoader()) | ||
| .getLoaded(); | ||
|
|
||
| } | ||
|
|
||
| private static class CacheKey { | ||
| private Object thisObject; | ||
| private String methodName; | ||
| private Object[] arguments; | ||
|
|
||
| CacheKey(Object thisObject, String methodName, Object[] arguments) { | ||
| this.thisObject = thisObject; | ||
| this.methodName = methodName; | ||
| this.arguments = arguments; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (this == o) { | ||
| return true; | ||
| } | ||
| if (o == null || getClass() != o.getClass()) { | ||
| return false; | ||
| } | ||
| CacheKey cacheKey = (CacheKey) o; | ||
| return Objects.equals(thisObject, cacheKey.thisObject) && | ||
| Objects.equals(methodName, cacheKey.methodName) && | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| Arrays.equals(arguments, cacheKey.arguments); | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| int result = Objects.hash(thisObject, methodName); | ||
| result = 31 * result + Arrays.hashCode(arguments); | ||
| return result; | ||
| } | ||
| } | ||
|
|
||
| private static class CacheValue { | ||
| private Object value; | ||
| private long time; | ||
|
|
||
| CacheValue(Object value, long time) { | ||
| this.value = value; | ||
| this.time = time; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| public static class CacheAdvisor { | ||
| private static ConcurrentHashMap<CacheKey, CacheValue> cache = new ConcurrentHashMap<>(); | ||
|
|
||
| @RuntimeType | ||
| public static Object cache( | ||
| @SuperCall Callable<Object> superCall, | ||
| @Origin Method method, | ||
| @This Object thisObject, | ||
| @AllArguments Object[] arguments) throws Exception { | ||
| CacheKey cacheKey = new CacheKey(thisObject, method.getName(), arguments); | ||
| final CacheValue resultExistInCache = cache.get(cacheKey); | ||
| if (resultExistInCache != null) { | ||
| if (cacheExpires(resultExistInCache, method)) { | ||
| return invokeRealMethodAndPutIntoCache(superCall, cacheKey); | ||
| } else { | ||
| return resultExistInCache.value; | ||
| } | ||
|
|
||
| } else { | ||
| return invokeRealMethodAndPutIntoCache(superCall, cacheKey); | ||
| } | ||
| } | ||
|
|
||
| private static Object invokeRealMethodAndPutIntoCache(@SuperCall Callable<Object> superCall, CacheKey cacheKey) throws Exception { | ||
| Object realMethodInvocationResult = superCall.call(); | ||
| cache.put(cacheKey, new CacheValue(realMethodInvocationResult, System.currentTimeMillis())); | ||
| return realMethodInvocationResult; | ||
| } | ||
|
|
||
| private static boolean cacheExpires(CacheValue cacheValue, Method method) { | ||
| long time = cacheValue.time; | ||
| int cacheSeconds = method.getAnnotation(Cache.class).cacheSeconds(); | ||
| return System.currentTimeMillis() - time > cacheSeconds * 1000; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| public static void main(String[] args) throws Exception { | ||
| DataService dataService = decorate(DataService.class).getConstructor().newInstance(); | ||
|
|
||
| // 有缓存的查询:只有第一次执行了真正的查询操作,第二次从缓存中获取 | ||
| System.out.println(dataService.queryData(1)); | ||
| Thread.sleep(1 * 1000); | ||
| System.out.println(dataService.queryData(1)); | ||
| Thread.sleep(3 * 1000); | ||
| System.out.println(dataService.queryData(1)); | ||
|
|
||
| // 无缓存的查询:两次都执行了真正的查询操作 | ||
| System.out.println(dataService.queryDataWithoutCache(1)); | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'&&' 应另起一行。