aop逻辑调整、增加全局拦截器、过滤器、异常处理器、结果处理器封装及测试代码

This commit is contained in:
aoshiguchen
2022-06-27 15:02:20 +08:00
parent 039d8337ff
commit 70ee451c60
14 changed files with 557 additions and 38 deletions
@@ -21,6 +21,8 @@
*/
package fun.asgc.neutrino.core.aop;
import fun.asgc.neutrino.core.aop.interceptor.Interceptor;
import java.lang.annotation.*;
/**
@@ -33,5 +35,6 @@ import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Intercept {
Class<? extends Interceptor>[] value();
Class<? extends Interceptor>[] value() default {};
Class<? extends Interceptor>[] exclude() default {};
}
@@ -21,11 +21,14 @@
*/
package fun.asgc.neutrino.core.aop;
import fun.asgc.neutrino.core.aop.interceptor.Interceptor;
import fun.asgc.neutrino.core.aop.interceptor.InterceptorFactory;
import fun.asgc.neutrino.core.aop.proxy.ProxyCache;
import fun.asgc.neutrino.core.util.ArrayUtil;
import fun.asgc.neutrino.core.util.CollectionUtil;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Method;
import java.util.List;
import java.util.function.Supplier;
/**
@@ -40,7 +43,7 @@ public class Invocation {
private Object proxy;
private Supplier callback;
private Object[] args;
private Interceptor[] interceptors;
private List<Interceptor> interceptors;
private volatile int index = 0;
private Object returnValue;
@@ -50,43 +53,12 @@ public class Invocation {
this.proxy = proxy;
this.callback = callback;
this.args = args;
this.interceptors = getInterceptors(this.targetMethod);
}
/**
* TODO 先简单实现为 newInstance
* @param targetMethod
* @return
*/
public static Interceptor[] getInterceptors(Method targetMethod) {
if (null == targetMethod) {
return null;
}
Intercept intercept = targetMethod.getAnnotation(Intercept.class);
if (null == intercept) {
intercept = targetMethod.getDeclaringClass().getAnnotation(Intercept.class);
}
if (null == intercept) {
return null;
}
Class<? extends Interceptor>[] classes = intercept.value();
if (ArrayUtil.isEmpty(classes)) {
return null;
}
Interceptor[] interceptors = new Interceptor[classes.length];
for (int i = 0; i < classes.length; i++) {
try {
interceptors[i] = classes[i].newInstance();
} catch (Exception e) {
// ignore
}
}
return interceptors;
this.interceptors = InterceptorFactory.getListByTargetMethod(this.targetMethod);
}
public void invoke() {
if (ArrayUtil.notEmpty(this.interceptors) && index < this.interceptors.length) {
this.interceptors[index++].intercept(this);
if (CollectionUtil.notEmpty(this.interceptors) && index < this.interceptors.size()) {
this.interceptors.get(index++).intercept(this);
} else {
returnValue = callback.get();
}
@@ -96,6 +68,9 @@ public class Invocation {
return (T)returnValue;
}
public void setReturnValue(Object returnValue) {
this.returnValue = returnValue;
}
public Class<?> getTargetClass() {
return targetClass;
@@ -0,0 +1,44 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.core.aop.interceptor;
/**
* 异常处理器
* @author: aoshiguchen
* @date: 2022/6/27
*/
public interface ExceptionHandler {
/**
* 是否支持处理该异常
* @param e
* @return
*/
boolean support(Exception e);
/**
* 异常处理
* @param e
* @return
*/
Object handle(Exception e);
}
@@ -0,0 +1,44 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.core.aop.interceptor;
import java.lang.reflect.Method;
/**
* 过滤器
* @author: aoshiguchen
* @date: 2022/6/27
*/
public interface Filter {
/**
* 是否过滤
* @param targetClass
* @param targetMethod
* @param args
* @return
*/
default boolean filtration(Class<?> targetClass, Method targetMethod, Object[] args) {
return false;
}
}
@@ -0,0 +1,90 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.core.aop.interceptor;
import fun.asgc.neutrino.core.aop.Invocation;
import fun.asgc.neutrino.core.util.CollectionUtil;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
/**
* 内部的全局拦截器
* @author: aoshiguchen
* @date: aoshiguchen
*/
@Slf4j
public class InnerGlobalInterceptor implements Interceptor {
private static final List<Filter> filterList = new ArrayList<>();
private static final List<ResultAdvice> resultAdviceList = new ArrayList<>();
private static final List<ExceptionHandler> exceptionHandlerList = new ArrayList<>();
@Override
public void intercept(Invocation inv) {
try {
log.debug("内置顶层拦截器 class:{} method:{} args:{} before", inv.getTargetClass().getName(), inv.getTargetMethod().getName(), inv.getArgs());
if (CollectionUtil.notEmpty(filterList)) {
for (Filter filter : filterList) {
if (filter.filtration(inv.getTargetClass(), inv.getTargetMethod(), inv.getArgs())) {
return;
}
}
}
inv.invoke();
Object result = inv.getReturnValue();
log.info("内置顶层拦截器 class:{} method:{} args:{} result:{} after", inv.getTargetClass().getName(), inv.getTargetMethod().getName(), inv.getArgs(), result);
if (CollectionUtil.notEmpty(resultAdviceList)) {
for (ResultAdvice advice : resultAdviceList) {
result = advice.advice(inv.getTargetClass(), inv.getTargetMethod(), result);
}
}
inv.setReturnValue(result);
log.info("内置顶层拦截器 class:{} method:{} args:{} result:{} finished.", inv.getTargetClass().getName(), inv.getTargetMethod().getName(), inv.getArgs(), result);
} catch (Exception e) {
log.info("内置顶层拦截器 class:{} method:{} args:{} exception.", inv.getTargetClass().getName(), inv.getTargetMethod().getName(), inv.getArgs());
if (CollectionUtil.notEmpty(exceptionHandlerList)) {
for (ExceptionHandler handler : exceptionHandlerList) {
if (handler.support(e)) {
Object result = handler.handle(e);
inv.setReturnValue(result);
return;
}
}
}
}
}
public static synchronized void registerFilter(Filter filter) {
filterList.add(filter);
}
public static synchronized void registerResultAdvice(ResultAdvice resultAdvice) {
resultAdviceList.add(resultAdvice);
}
public static synchronized void registerExceptionHandler(ExceptionHandler exceptionHandler) {
exceptionHandlerList.add(exceptionHandler);
}
}
@@ -19,7 +19,9 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.core.aop;
package fun.asgc.neutrino.core.aop.interceptor;
import fun.asgc.neutrino.core.aop.Invocation;
/**
* @author: aoshiguchen
@@ -0,0 +1,106 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.core.aop.interceptor;
import fun.asgc.neutrino.core.aop.Intercept;
import fun.asgc.neutrino.core.cache.Cache;
import fun.asgc.neutrino.core.cache.MemoryCache;
import fun.asgc.neutrino.core.util.ArrayUtil;
import fun.asgc.neutrino.core.util.Assert;
import fun.asgc.neutrino.core.util.LockUtil;
import java.lang.reflect.Method;
import java.util.*;
/**
* 拦截器工厂
* @author: aoshiguchen
* @date: 2022/6/24
*/
public class InterceptorFactory {
private static final Cache<Class<? extends Interceptor>, Interceptor> interceptorCache = new MemoryCache<>();
private static final List<Interceptor> globalInterceptorList = Collections.synchronizedList(new ArrayList<>());
static {
registerGlobalInterceptor(InnerGlobalInterceptor.class);
}
public static <T extends Interceptor> T get(Class<T> clazz) {
return (T)LockUtil.doubleCheckProcess(() -> !interceptorCache.containsKey(clazz),
clazz,
() -> {
try {
interceptorCache.set(clazz, clazz.newInstance());
} catch (InstantiationException|IllegalAccessException e) {
throw new RuntimeException(e);
}
},
() -> interceptorCache.get(clazz)
);
}
public static List<Interceptor> getListByTargetMethod(Method targetMethod) {
if (null == targetMethod) {
return null;
}
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(globalInterceptorList);
addInterceptorByAnnotation(interceptors, targetMethod.getDeclaringClass().getAnnotation(Intercept.class));
addInterceptorByAnnotation(interceptors, targetMethod.getAnnotation(Intercept.class));
return interceptors;
}
private static void addInterceptorByAnnotation(List<Interceptor> interceptors, Intercept intercept) {
if (null == interceptors || null == intercept) {
return;
}
if (ArrayUtil.notEmpty(intercept.value())) {
for (Class<? extends Interceptor> clazz : intercept.value()) {
Interceptor interceptor = get(clazz);
if (null != interceptor && !interceptors.contains(interceptor)) {
interceptors.add(interceptor);
}
}
}
if (ArrayUtil.notEmpty(intercept.exclude())) {
for (Class<? extends Interceptor> clazz : intercept.exclude()) {
Interceptor interceptor = get(clazz);
if (null != interceptor && interceptors.contains(interceptor)) {
interceptors.remove(interceptor);
}
}
}
}
/**
* 注册拦截器 - 全局
* @param clazz
*/
public static synchronized void registerGlobalInterceptor(Class<? extends Interceptor> clazz) {
Assert.notNull(clazz, "class不能为空!");
Interceptor interceptor = get(clazz);
if (!globalInterceptorList.contains(interceptor)) {
globalInterceptorList.add(interceptor);
}
}
}
@@ -0,0 +1,44 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.core.aop.interceptor;
import java.lang.reflect.Method;
/**
* 结果处理
* @author: aoshiguchen
* @date: 2022/6/27
*/
public interface ResultAdvice {
/**
* 结果处理
* @param targetClass
* @param targetMethod
* @param result
* @return
*/
default Object advice(Class<?> targetClass, Method targetMethod, Object result) {
return result;
}
}
@@ -35,6 +35,7 @@ public class Dog {
System.out.println("汪汪汪");
}
@Intercept(exclude = TestInterceptor2.class)
public String say(String msg) {
return "狗说:" + msg;
}
@@ -0,0 +1,33 @@
/**
* Copyright (C) 2018-2022 Zeyi information technology (Shanghai) Co., Ltd.
* <p>
* All right reserved.
* <p>
* This software is the confidential and proprietary
* information of Zeyi Company of China.
* ("Confidential Information"). You shall not disclose
* such Confidential Information and shall use it only
* in accordance with the terms of the contract agreement
* you entered into with Zeyi inc.
*/
package fun.asgc.neutrino.core.aop;
import fun.asgc.neutrino.core.aop.interceptor.Interceptor;
import lombok.extern.slf4j.Slf4j;
/**
*
* @author: wen.y
* @date: 2022/6/27
*/
@Slf4j
public class GlobalInterceptor implements Interceptor {
@Override
public void intercept(Invocation inv) {
log.info("全局拦截器1 class:{} method:{} args:{} before", inv.getTargetClass().getName(), inv.getTargetMethod().getName(), inv.getArgs());
inv.invoke();
log.info("全局拦截器1 class:{} method:{} args:{} after", inv.getTargetClass().getName(), inv.getTargetMethod().getName(), inv.getArgs());
}
}
@@ -0,0 +1,57 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.core.aop;
import fun.asgc.neutrino.core.aop.interceptor.InnerGlobalInterceptor;
/**
*
* @author: aoshiguchen
* @date: 2022/6/27
*/
public class Panda {
public Panda() {
System.out.println("熊猫出生");
}
public void eat() {
System.out.println("熊猫吃竹子");
}
@Intercept(exclude = InnerGlobalInterceptor.class)
public void play(String project) {
System.out.println("熊猫在玩" + project);
}
public Integer division(int x, int y) {
return x / y;
}
public void say(String msg) {
System.out.println("熊猫说:" + msg);
}
public String request(String a, String b) {
return String.format("参数 a:%s b:%s 处理结果", a, b);
}
}
@@ -0,0 +1,110 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.core.aop;
import com.alibaba.fastjson.JSONObject;
import fun.asgc.neutrino.core.aop.interceptor.*;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.lang.reflect.Method;
/**
*
* @author: aoshiguchen
* @date: 2022/6/27
*/
@Slf4j
public class Test2 {
{
// 注册全局拦截器
InterceptorFactory.registerGlobalInterceptor(GlobalInterceptor.class);
// 注册过滤器
InnerGlobalInterceptor.registerFilter(new Filter() {
@Override
public boolean filtration(Class<?> targetClass, Method targetMethod, Object[] args) {
if (targetClass == Panda.class && targetMethod.getName().equals("say")) {
return true;
}
return false;
}
});
// 注册结果处理器
InnerGlobalInterceptor.registerResultAdvice(new ResultAdvice() {
@Override
public Object advice(Class<?> targetClass, Method targetMethod, Object result) {
if (targetClass == Panda.class && targetMethod.getName().equals("request")) {
JSONObject data = new JSONObject();
data.put("code", 0);
data.put("data", result);
return data.toJSONString();
}
return result;
}
});
// 注册异常处理器
InnerGlobalInterceptor.registerExceptionHandler(new ExceptionHandler() {
@Override
public boolean support(Exception e) {
return e instanceof ArithmeticException;
}
@Override
public Object handle(Exception e) {
log.info("除数不能为0!");
return null;
}
});
}
@Test
public void eat() {
Panda panda = Aop.get(Panda.class);
panda.eat();
}
@Test
public void play() {
Panda panda = Aop.get(Panda.class);
panda.play("滑板");
}
@Test
public void division() {
Panda panda = Aop.get(Panda.class);
System.out.println(panda.division(10, 5));
panda.division(10, 0);
}
@Test
public void say() {
Panda panda = Aop.get(Panda.class);
panda.say("hello");
}
@Test
public void request() {
Panda panda = Aop.get(Panda.class);
panda.request("xxx", "yyy");
}
}
@@ -21,6 +21,7 @@
*/
package fun.asgc.neutrino.core.aop;
import fun.asgc.neutrino.core.aop.interceptor.Interceptor;
import lombok.extern.slf4j.Slf4j;
/**
@@ -31,6 +32,10 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
public class TestInterceptor implements Interceptor {
public TestInterceptor() {
System.out.println("拦截器1实例化");
}
@Override
public void intercept(Invocation inv) {
try {
@@ -21,6 +21,7 @@
*/
package fun.asgc.neutrino.core.aop;
import fun.asgc.neutrino.core.aop.interceptor.Interceptor;
import lombok.extern.slf4j.Slf4j;
/**
@@ -31,6 +32,10 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
public class TestInterceptor2 implements Interceptor {
public TestInterceptor2() {
System.out.println("拦截器2实例化");
}
@Override
public void intercept(Invocation inv) {
try {