aop代理功能增强,支持代理实例是被代理类超类类型,解决jdk只能代理纯接口的问题

This commit is contained in:
aoshiguchen
2022-07-07 12:06:52 +08:00
parent 6ab126dee7
commit 0671cb5e59
11 changed files with 426 additions and 22 deletions
@@ -34,10 +34,19 @@ import fun.asgc.neutrino.core.util.LockUtil;
* @author: aoshiguchen
* @date: 2022/6/24
*/
@SuppressWarnings("all")
public class Aop {
private static ProxyStrategy proxyStrategy = ProxyStrategy.AUTO;
private static final Cache<Class<?>, Object> proxyBeanCache = new MemoryCache<>();
private static final Cache<Class<?>/*targetType*/, Cache<Class<?>/*proxyType*/, Object>> otherProxyBeanCache = new MemoryCache<>();
/**
* 被代理类型与代理类同源,即生成的代理类可以用被代理类的类型接收
* @param clazz
* @param <T>
* @return
* @throws Exception
*/
public static <T> T get(Class<T> clazz) throws Exception {
return (T)LockUtil.doubleCheckProcess(() -> !proxyBeanCache.containsKey(clazz),
clazz,
@@ -46,6 +55,38 @@ public class Aop {
);
}
/**
* 1、当且仅当被代理类型与代理类类型相等时,该方法与上面的方法等价
* 2、否则,生成的代理类类型是被代理类的超类,也就是只代理超类的可代理方法
* @param targetType
* @param proxyType
* @param <T>
* @param <P>
* @return
* @throws Exception
*/
public static <T,P> P get(Class<T> targetType, Class<P> proxyType) throws Exception {
Assert.notNull(targetType, "被代理类类型不能为空!");
Assert.notNull(proxyType, "代理类类型不能为空!");
if (targetType == proxyType) {
return get(proxyType);
}
if (!proxyType.isAssignableFrom(targetType)) {
throw new RuntimeException(String.format("期望的代理类类型[%s]不是目标类型[%s]的超类!", proxyType.getName(), targetType.getName()));
}
return (P)LockUtil.doubleCheckProcess(
() -> !otherProxyBeanCache.containsKey(targetType) || !otherProxyBeanCache.get(targetType).containsKey(proxyType),
targetType,
() -> {
if (!otherProxyBeanCache.containsKey(targetType)) {
otherProxyBeanCache.set(targetType, new MemoryCache<>());
}
otherProxyBeanCache.get(targetType).set(proxyType, getProxyFactory(targetType, proxyType).get(targetType, proxyType));
},
() -> otherProxyBeanCache.get(targetType).get(proxyType)
);
}
/**
* 获取代理工厂
* 1、如果被代理类是一个接口,则采用jdk动态代理,减少避免不必要的字节码编译开销
@@ -62,6 +103,25 @@ public class Aop {
return Proxy.getProxyFactory(proxyStrategy);
}
/**
* 获取代理工厂
* 1、如果被代理类是一个接口,则采用jdk动态代理,减少避免不必要的字节码编译开销
* 2、其他情况则采用子类代理(AsgcProxy)
* @return
*/
private static ProxyFactory getProxyFactory(Class<?> targetType, Class<?> proxyType) {
if (targetType == proxyType) {
return getProxyFactory(targetType);
}
if (proxyStrategy == ProxyStrategy.AUTO) {
if (ClassUtil.isInterface(proxyType)) {
return Proxy.getProxyFactory(ProxyStrategy.JDK_DYNAMIC_PROXY);
}
return Proxy.getProxyFactory(ProxyStrategy.ASGC_PROXY);
}
return Proxy.getProxyFactory(proxyStrategy);
}
/**
* 设置代理策略
* @param proxyStrategy
@@ -42,10 +42,10 @@ public class AsgcProxyFactory implements ProxyFactory {
private ProxyClassLoader classLoader = new ProxyClassLoader();
@Override
public <T> T get(Class<T> clazz) throws Exception {
Assert.notNull(clazz, "被代理类不能为空!");
Assert.isTrue(canProxy(clazz), String.format("类[%s]无法被代理!", clazz.getName()));
return doGet(clazz);
public <T> T get(Class<T> targetType) throws Exception {
Assert.notNull(targetType, "被代理类不能为空!");
Assert.isTrue(canProxy(targetType), String.format("类[%s]无法被代理!", targetType.getName()));
return doGet(targetType, targetType);
}
@Override
@@ -59,23 +59,36 @@ public class AsgcProxyFactory implements ProxyFactory {
&& Stream.of(clazz.getConstructors()).filter(e -> e.getParameterCount() == 0).count() > 0);
}
@Override
public <T, P> P get(Class<T> targetType, Class<P> proxyType) throws Exception {
Assert.notNull(targetType, "被代理类不能为空!");
Assert.notNull(proxyType, "代理类类型不能为空!");
Assert.isTrue(canProxy(targetType, proxyType), String.format("类[targetType:%s, proxyType:%s]无法被代理!", targetType.getName(), proxyType.getName()));
return doGet(targetType, proxyType);
}
@Override
public boolean canProxy(Class<?> targetType, Class<?> proxyType) {
return canProxy(targetType) && proxyType.isAssignableFrom(targetType);
}
@Override
public boolean isProxyClass(Class<?> clazz) {
return null != clazz && clazz.getSimpleName().contains(SYMBOLIC);
}
private <T> T doGet(Class<T> clazz) throws ReflectiveOperationException {
ProxyClass proxyClass = new ProxyClass(clazz);
proxyClass.setName(generateClassName(clazz));
String sourceCode = AsgcProxyGenerator.getInstance().generator(proxyClass.getName(), clazz); // generateProxyClassSourceCode(clazz, proxyClass.getName());
private <T,P> P doGet(Class<T> targetType, Class<P> proxyType) throws ReflectiveOperationException {
ProxyClass proxyClass = new ProxyClass(targetType);
proxyClass.setName(generateClassName(targetType));
String sourceCode = AsgcProxyGenerator.getInstance().generator(proxyClass.getName(), targetType, proxyType); // generateProxyClassSourceCode(clazz, proxyClass.getName());
proxyClass.setSourceCode(sourceCode);
if (GlobalConfig.isIsPrintGeneratorCode()) {
log.debug("类:{} 的代理类源码:\n{}", clazz.getName(), sourceCode);
log.debug("类:{} 的代理类源码:\n{}", targetType.getName(), sourceCode);
}
compiler.compile(proxyClass);
Class<T> retClass = (Class<T>)classLoader.loadProxyClass(proxyClass);
T obj = retClass.newInstance();
Class<P> retClass = (Class<P>)classLoader.loadProxyClass(proxyClass);
P obj = retClass.newInstance();
return obj;
}
@@ -28,6 +28,7 @@ import lombok.experimental.Accessors;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import sun.management.MethodInfo;
import java.io.StringWriter;
import java.lang.reflect.Method;
@@ -63,6 +64,10 @@ public class AsgcProxyGenerator {
}
public String generator(String proxyClassName, Class<?> targetType) {
return generator(proxyClassName, targetType, targetType);
}
public String generator(String proxyClassName, Class<?> targetType, Class<?> proxyType) {
Map<String, Object> map = new HashMap<>();
map.put("package", targetType.getPackage().getName());
List<Class<?>> importList = new ArrayList<>();
@@ -76,7 +81,7 @@ public class AsgcProxyGenerator {
List<MethodInfo> methodInfoList = new ArrayList<>();
map.put("methodInfoList", methodInfoList);
Method[] methods = targetType.getMethods();
Method[] methods = proxyType.getMethods();
if (ArrayUtil.notEmpty(methods)) {
for (Method method : methods) {
if (Modifier.isFinal(method.getModifiers()) ||
@@ -44,18 +44,31 @@ public class JdkDynamicProxyFactory implements ProxyFactory {
}
private <T> T doGet(Class<T> clazz) throws ReflectiveOperationException {
if (ClassUtil.isInterface(clazz)) {
return (T) Proxy.newProxyInstance(clazz.getClassLoader(),
new Class[]{clazz},
new JdkDynamicProxy(null)
);
}
return null;
return (T) Proxy.newProxyInstance(clazz.getClassLoader(),
new Class[]{clazz},
new JdkDynamicProxy(null)
);
}
@Override
public boolean canProxy(Class<?> clazz) {
return ClassUtil.isInterface(clazz) || ArrayUtil.notEmpty(clazz.getInterfaces());
return ClassUtil.isInterface(clazz);
}
@Override
public <T, P> P get(Class<T> targetType, Class<P> proxyType) throws Exception {
Assert.notNull(targetType, "被代理类不能为空!");
Assert.notNull(proxyType, "代理类类型不能为空!");
Assert.isTrue(canProxy(targetType, proxyType), String.format("类[targetType:%s, proxyType:%s]无法被代理!", targetType.getName(), proxyType.getName()));
return (P) Proxy.newProxyInstance(targetType.getClassLoader(),
new Class[]{proxyType},
new JdkDynamicProxy(targetType.newInstance())
);
}
@Override
public boolean canProxy(Class<?> targetType, Class<?> proxyType) {
return ClassUtil.isInterface(proxyType) && proxyType.isAssignableFrom(targetType);
}
@Override
@@ -42,6 +42,25 @@ public interface ProxyFactory {
*/
boolean canProxy(Class<?> clazz);
/**
* 获取一个类的代理类实例
* @param targetType
* @param proxyType
* @param <T>
* @param <P>
* @return
* @throws Exception
*/
<T,P> P get(Class<T> targetType, Class<P> proxyType) throws Exception;
/**
* 是否能被代理
* @param targetType
* @param proxyType
* @return
*/
boolean canProxy(Class<?> targetType, Class<?> proxyType);
/**
* 判断指定类是否由当前代理策略产生
* @param clazz
@@ -0,0 +1,64 @@
/**
* 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;
/**
*
* @author: aoshiguchen
* @date: 2022/7/7
*/
@Intercept(value = TestInterceptor.class, ignoreGlobal = true)
public class DefaultPlayer implements Player {
private String name;
public DefaultPlayer(String name) {
this.name = name;
}
public DefaultPlayer() {
this.name = "未知设备";
}
@Override
public void on() {
System.out.println(String.format("%s 开机", name));
}
@Override
public void off() {
System.out.println(String.format("%s 关机", name));
}
@Override
public void play() {
System.out.println(String.format("%s 开始播放", name));
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@@ -0,0 +1,45 @@
/**
* 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;
/**
* 播放器接口
* @author: aoshiguchen
* @date: 2022/7/7
*/
@Intercept(value = TestInterceptor.class, ignoreGlobal = true)
public interface Player {
/**
* 开机
*/
void on();
/**
* 关机
*/
void off();
/**
* 播放
*/
void play();
}
@@ -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;
/**
*
* @author: aoshiguchen
* @date: 2022/7/7
*/
public class RadioPlayer extends DefaultPlayer implements SoundPlayer {
public RadioPlayer() {
super("收音机");
}
@Override
public void volumeIncrease() {
System.out.println(String.format("%s 音量增加", getName()));
}
@Override
public void volumeReduce() {
System.out.println(String.format("%s 音量减少", getName()));
}
}
@@ -0,0 +1,38 @@
/**
* 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;
/**
* @author: aoshiguchen
* @date: 2022/7/7
*/
public interface SoundPlayer extends Player {
/**
* 音量增加
*/
void volumeIncrease();
/**
* 音量减少
*/
void volumeReduce();
}
@@ -37,8 +37,8 @@ public class Test3 {
@Test
public void test1() throws Exception {
// Animal animal = Aop.get(Animal.class);
Animal animal = Proxy.getProxyFactory(ProxyStrategy.ASGC_PROXY).get(Animal.class);
Animal animal = Aop.get(Animal.class);
// Animal animal = Proxy.getProxyFactory(ProxyStrategy.ASGC_PROXY).get(Animal.class);
System.out.println(animal);
System.out.println(animal.say("aa"));
}
@@ -0,0 +1,103 @@
/**
* 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.proxy.Proxy;
import fun.asgc.neutrino.core.base.GlobalConfig;
import org.junit.Test;
/**
*
* @author: aoshiguchen
* @date: 2022/7/7
*/
public class Test4 {
static {
// 配置输出生成代理类源码
GlobalConfig.setIsPrintGeneratorCode(true);
}
@Test
public void jdk代理1() throws Exception {
Player player = Proxy.getProxyFactory(ProxyStrategy.JDK_DYNAMIC_PROXY).get(RadioPlayer.class, Player.class);
player.on();
player.play();
player.off();
}
@Test
public void jdk代理2() throws Exception {
SoundPlayer player = Proxy.getProxyFactory(ProxyStrategy.JDK_DYNAMIC_PROXY).get(RadioPlayer.class, SoundPlayer.class);
player.on();
player.play();
player.volumeReduce();
player.off();
}
/**
* 无法被代理,应抛出异常
* @throws Exception
*/
@Test
public void jdk代理3() throws Exception {
DefaultPlayer player = Proxy.getProxyFactory(ProxyStrategy.JDK_DYNAMIC_PROXY).get(RadioPlayer.class, DefaultPlayer.class);
player.on();
player.play();
player.off();
}
@Test
public void 子类代理1() throws Exception {
Player player = Proxy.getProxyFactory(ProxyStrategy.ASGC_PROXY).get(RadioPlayer.class, Player.class);
player.on();
player.play();
player.off();
}
@Test
public void 子类代理2() throws Exception {
DefaultPlayer player = Proxy.getProxyFactory(ProxyStrategy.ASGC_PROXY).get(RadioPlayer.class, DefaultPlayer.class);
player.on();
player.play();
player.off();
System.out.println(player.getName());
}
@Test
public void 子类代理3() throws Exception {
SoundPlayer player = Proxy.getProxyFactory(ProxyStrategy.ASGC_PROXY).get(RadioPlayer.class, SoundPlayer.class);
player.on();
player.play();
player.volumeIncrease();
player.off();
}
@Test
public void 子类代理4() throws Exception {
RadioPlayer player = Proxy.getProxyFactory(ProxyStrategy.ASGC_PROXY).get(RadioPlayer.class, RadioPlayer.class);
player.on();
player.play();
player.volumeIncrease();
player.off();
}
}