diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/Aop.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/Aop.java index 506c537a..500a5f10 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/Aop.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/Aop.java @@ -23,10 +23,10 @@ package fun.asgc.neutrino.core.aop; import fun.asgc.neutrino.core.aop.proxy.Proxy; import fun.asgc.neutrino.core.aop.proxy.ProxyFactory; -import fun.asgc.neutrino.core.aop.proxy.ProxyStrategy; import fun.asgc.neutrino.core.cache.Cache; import fun.asgc.neutrino.core.cache.MemoryCache; import fun.asgc.neutrino.core.util.Assert; +import fun.asgc.neutrino.core.util.ClassUtil; import fun.asgc.neutrino.core.util.LockUtil; /** @@ -35,16 +35,36 @@ import fun.asgc.neutrino.core.util.LockUtil; * @date: 2022/6/24 */ public class Aop { - private static final ProxyStrategy proxyStrategy = ProxyStrategy.SUB_CLASS_PROXY; - private static final ProxyFactory proxyFactory = Proxy.getProxyFactory(proxyStrategy); + private static ProxyStrategy proxyStrategy = ProxyStrategy.AUTO; private static final Cache, Object> proxyBeanCache = new MemoryCache<>(); public static T get(Class clazz) { - Assert.notNull(proxyFactory, "代理工厂初始化异常!"); return (T)LockUtil.doubleCheckProcess(() -> !proxyBeanCache.containsKey(clazz), clazz, - () -> proxyBeanCache.set(clazz, proxyFactory.get(clazz)), + () -> proxyBeanCache.set(clazz, getProxyFactory(clazz).get(clazz)), () -> proxyBeanCache.get(clazz) ); } + + /** + * 获取代理工厂 + * 1、如果被代理类是一个接口,则采用jdk动态代理,减少避免不必要的字节码编译开销 + * 2、其他情况则采用子类代理(AsgcProxy) + * @return + */ + private static ProxyFactory getProxyFactory(Class clazz) { + if (ClassUtil.isInterface(clazz)) { + return Proxy.getProxyFactory(ProxyStrategy.JDK_DYNAMIC_PROXY); + } + return Proxy.getProxyFactory(ProxyStrategy.ASGC_PROXY); + } + + /** + * 设置代理策略 + * @param proxyStrategy + */ + public static synchronized void setProxyStrategy(ProxyStrategy proxyStrategy) { + Assert.notNull(proxyStrategy, "代理策略不能为空!"); + Aop.proxyStrategy = proxyStrategy; + } } diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/proxy/ProxyStrategy.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/ProxyStrategy.java similarity index 89% rename from neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/proxy/ProxyStrategy.java rename to neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/ProxyStrategy.java index ba99341c..294835ac 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/proxy/ProxyStrategy.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/ProxyStrategy.java @@ -19,7 +19,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package fun.asgc.neutrino.core.aop.proxy; +package fun.asgc.neutrino.core.aop; /** * 代理策略 @@ -33,8 +33,10 @@ import lombok.Getter; @Getter @AllArgsConstructor public enum ProxyStrategy { + // 在该模式下,代理策略由框架根据一定策略自动选择 + AUTO(0, "自动选择"), JDK_DYNAMIC_PROXY(1, "JDK动态代理"), - SUB_CLASS_PROXY(2, "子类代理"); + ASGC_PROXY(2, "asgc子类代理"); private Integer strategy; private String desc; diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/proxy/AsgcProxyFactory.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/proxy/AsgcProxyFactory.java index d9d767cd..e9fe1a35 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/proxy/AsgcProxyFactory.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/proxy/AsgcProxyFactory.java @@ -42,7 +42,8 @@ import java.util.stream.Stream; */ @Slf4j public class AsgcProxyFactory implements ProxyFactory { - private static String classNameTemplate = "%sAsgcProxy$$%s"; + private static final String SYMBOLIC = "AsgcProxy$$"; + private static final String classNameTemplate = "%s" + SYMBOLIC + "%s"; private static AtomicLong proxyClassCounter = new AtomicLong(); private ProxyCompiler compiler = new ProxyCompiler(); private ProxyClassLoader classLoader = new ProxyClassLoader(); @@ -69,6 +70,11 @@ public class AsgcProxyFactory implements ProxyFactory { && Stream.of(clazz.getConstructors()).filter(e -> e.getParameterCount() == 0).count() > 0); } + @Override + public boolean isProxyClass(Class clazz) { + return null != clazz && clazz.getSimpleName().contains(SYMBOLIC); + } + private T doGet(Class clazz) throws ReflectiveOperationException { ProxyClass proxyClass = new ProxyClass(clazz); proxyClass.setName(generateClassName(clazz)); diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/proxy/JdkDynamicProxyFactory.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/proxy/JdkDynamicProxyFactory.java new file mode 100644 index 00000000..07e0bc5a --- /dev/null +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/proxy/JdkDynamicProxyFactory.java @@ -0,0 +1,94 @@ +/** + * 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.proxy; + +import fun.asgc.neutrino.core.aop.Invocation; +import fun.asgc.neutrino.core.util.ArrayUtil; +import fun.asgc.neutrino.core.util.Assert; +import fun.asgc.neutrino.core.util.ClassUtil; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +/** + * JDK动态代理 + * @author: aoshiguchen + * @date: 2022/6/29 + */ +public class JdkDynamicProxyFactory implements ProxyFactory { + + @Override + public T get(Class clazz) { + Assert.notNull(clazz, "被代理类不能为空!"); + Assert.isTrue(canProxy(clazz), String.format("类[%s]无法被代理!", clazz.getName())); + try { + return doGet(clazz); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + private T doGet(Class clazz) throws ReflectiveOperationException { + if (ClassUtil.isInterface(clazz)) { + return (T) Proxy.newProxyInstance(clazz.getClassLoader(), + new Class[]{clazz}, + new JdkDynamicProxy(null) + ); + } + return null; + } + + @Override + public boolean canProxy(Class clazz) { + return ClassUtil.isInterface(clazz) || ArrayUtil.notEmpty(clazz.getInterfaces()); + } + + @Override + public boolean isProxyClass(Class clazz) { + return Proxy.isProxyClass(clazz); + } + + private static class JdkDynamicProxy implements InvocationHandler { + private Object target; + public JdkDynamicProxy(Object target) { + this.target = target; + } + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + Long methodId = ProxyCache.setMethod(method); + Invocation inv = new Invocation(methodId,this, () -> { + if (null != target) { + try { + return method.invoke(target, args); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + return null; + }, args); + inv.invoke(); + return inv.getReturnValue(); + } + } +} diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/proxy/Proxy.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/proxy/Proxy.java index c2d65c6f..37745dfb 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/proxy/Proxy.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/proxy/Proxy.java @@ -21,6 +21,8 @@ */ package fun.asgc.neutrino.core.aop.proxy; +import fun.asgc.neutrino.core.aop.ProxyStrategy; + /** * * @author: aoshiguchen @@ -28,10 +30,12 @@ package fun.asgc.neutrino.core.aop.proxy; */ public class Proxy { private static final ProxyFactory subClassProxyFactory = new AsgcProxyFactory(); + private static final ProxyFactory jdkDynamicProxyFactory = new JdkDynamicProxyFactory(); public static ProxyFactory getProxyFactory(ProxyStrategy strategy) { switch (strategy) { - case SUB_CLASS_PROXY: return subClassProxyFactory; + case ASGC_PROXY: return subClassProxyFactory; + case JDK_DYNAMIC_PROXY: return jdkDynamicProxyFactory; default: return null; } } diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/proxy/ProxyFactory.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/proxy/ProxyFactory.java index 8b207d09..a13b8d53 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/proxy/ProxyFactory.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/proxy/ProxyFactory.java @@ -41,4 +41,11 @@ public interface ProxyFactory { * @return */ boolean canProxy(Class clazz); + + /** + * 判断指定类是否由当前代理策略产生 + * @param clazz + * @return + */ + boolean isProxyClass(Class clazz); }