From 2e88e74caeb4585c580d0e0c714d9e064d6da368 Mon Sep 17 00:00:00 2001 From: Looly Date: Thu, 25 May 2023 00:16:08 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=87=E9=9D=A2=E4=BB=A3=E7=90=86=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E4=B8=AD=E7=9A=84cglib=E6=94=AF=E6=8C=81=E5=A4=9A?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E6=9E=84=E9=80=A0=E7=94=9F=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 +- .../hutool/aop/proxy/CglibProxyFactory.java | 42 ++++++++- .../aop/proxy/SpringCglibProxyFactory.java | 44 ++++++++- .../cn/hutool/aop/test/IssueI74EX7Test.java | 91 +++++++++++++++++++ 4 files changed, 174 insertions(+), 6 deletions(-) create mode 100644 hutool-aop/src/test/java/cn/hutool/aop/test/IssueI74EX7Test.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b878e6e0..0d0ed9c59 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ # 🚀Changelog ------------------------------------------------------------------------------------------------------------- -# 5.8.19.M1 (2023-05-23) +# 5.8.19.M1 (2023-05-25) ### 🐣新特性 * 【db 】 优化HttpRequest.toString()内容打印(issue#3072@Github) @@ -16,6 +16,7 @@ * 【core 】 增加CsvWriteConfig.setEndingLineBreak配置项(issue#I75K5G@Gitee) * 【core 】 增加Tailer追踪文件时文件被删除的处理情况(pr#3115@Github) * 【core 】 DelegatedExecutorService构造方法设置成public(issue#I77LUE@Gitee) +* 【core 】 切面代理工具中的cglib支持多参数构造生成(issue#I74EX7@Gitee) ### 🐞Bug修复 * 【core 】 修复URLUtil.decode无法解码UTF-16问题(issue#3063@Github) diff --git a/hutool-aop/src/main/java/cn/hutool/aop/proxy/CglibProxyFactory.java b/hutool-aop/src/main/java/cn/hutool/aop/proxy/CglibProxyFactory.java index d7510035c..b2b0f12b8 100755 --- a/hutool-aop/src/main/java/cn/hutool/aop/proxy/CglibProxyFactory.java +++ b/hutool-aop/src/main/java/cn/hutool/aop/proxy/CglibProxyFactory.java @@ -2,8 +2,12 @@ package cn.hutool.aop.proxy; import cn.hutool.aop.aspects.Aspect; import cn.hutool.aop.interceptor.CglibInterceptor; +import cn.hutool.core.util.ClassUtil; +import cn.hutool.core.util.ReflectUtil; import net.sf.cglib.proxy.Enhancer; +import java.lang.reflect.Constructor; + /** * 基于Cglib的切面代理工厂 * @@ -14,12 +18,46 @@ public class CglibProxyFactory extends ProxyFactory{ private static final long serialVersionUID = 1L; @Override - @SuppressWarnings("unchecked") public T proxy(T target, Aspect aspect) { + final Class targetClass = target.getClass(); + final Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(new CglibInterceptor(target, aspect)); - return (T) enhancer.create(); + return create(enhancer, targetClass); } + /** + * 创建代理对象
+ * https://gitee.com/dromara/hutool/issues/I74EX7
+ * 某些对象存在非空参数构造,则需遍历查找需要的构造完成代理对象构建。 + * + * @param 代理对象类型 + * @param enhancer {@link org.springframework.cglib.proxy.Enhancer} + * @param targetClass 目标类型 + * @return 代理对象 + */ + @SuppressWarnings("unchecked") + private static T create(final Enhancer enhancer, final Class targetClass) { + final Constructor[] constructors = ReflectUtil.getConstructors(targetClass); + Class[] parameterTypes; + Object[] values; + IllegalArgumentException finalException = null; + for (final Constructor constructor : constructors) { + parameterTypes = constructor.getParameterTypes(); + values = ClassUtil.getDefaultValues(parameterTypes); + + try { + return (T) enhancer.create(parameterTypes, values); + } catch (final IllegalArgumentException e) { + //ignore + finalException = e; + } + } + if (null != finalException) { + throw finalException; + } + + throw new IllegalArgumentException("No constructor provided"); + } } diff --git a/hutool-aop/src/main/java/cn/hutool/aop/proxy/SpringCglibProxyFactory.java b/hutool-aop/src/main/java/cn/hutool/aop/proxy/SpringCglibProxyFactory.java index caa43e596..2ed9745d1 100755 --- a/hutool-aop/src/main/java/cn/hutool/aop/proxy/SpringCglibProxyFactory.java +++ b/hutool-aop/src/main/java/cn/hutool/aop/proxy/SpringCglibProxyFactory.java @@ -2,8 +2,12 @@ package cn.hutool.aop.proxy; import cn.hutool.aop.aspects.Aspect; import cn.hutool.aop.interceptor.SpringCglibInterceptor; +import cn.hutool.core.util.ClassUtil; +import cn.hutool.core.util.ReflectUtil; import org.springframework.cglib.proxy.Enhancer; +import java.lang.reflect.Constructor; + /** * 基于Spring-cglib的切面代理工厂 * @@ -14,12 +18,46 @@ public class SpringCglibProxyFactory extends ProxyFactory{ private static final long serialVersionUID = 1L; @Override - @SuppressWarnings("unchecked") public T proxy(T target, Aspect aspect) { + final Class targetClass = target.getClass(); + final Enhancer enhancer = new Enhancer(); - enhancer.setSuperclass(target.getClass()); + enhancer.setSuperclass(targetClass); enhancer.setCallback(new SpringCglibInterceptor(target, aspect)); - return (T) enhancer.create(); + return create(enhancer, targetClass); } + /** + * 创建代理对象
+ * https://gitee.com/dromara/hutool/issues/I74EX7
+ * 某些对象存在非空参数构造,则需遍历查找需要的构造完成代理对象构建。 + * + * @param 代理对象类型 + * @param enhancer {@link Enhancer} + * @param targetClass 目标类型 + * @return 代理对象 + */ + @SuppressWarnings("unchecked") + private static T create(final Enhancer enhancer, final Class targetClass) { + final Constructor[] constructors = ReflectUtil.getConstructors(targetClass); + Class[] parameterTypes; + Object[] values; + IllegalArgumentException finalException = null; + for (final Constructor constructor : constructors) { + parameterTypes = constructor.getParameterTypes(); + values = ClassUtil.getDefaultValues(parameterTypes); + + try { + return (T) enhancer.create(parameterTypes, values); + } catch (final IllegalArgumentException e) { + //ignore + finalException = e; + } + } + if (null != finalException) { + throw finalException; + } + + throw new IllegalArgumentException("No constructor provided"); + } } diff --git a/hutool-aop/src/test/java/cn/hutool/aop/test/IssueI74EX7Test.java b/hutool-aop/src/test/java/cn/hutool/aop/test/IssueI74EX7Test.java new file mode 100644 index 000000000..82e90a326 --- /dev/null +++ b/hutool-aop/src/test/java/cn/hutool/aop/test/IssueI74EX7Test.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package cn.hutool.aop.test; + +import cn.hutool.aop.aspects.SimpleAspect; +import cn.hutool.aop.proxy.CglibProxyFactory; +import cn.hutool.aop.proxy.JdkProxyFactory; +import cn.hutool.aop.proxy.ProxyFactory; +import cn.hutool.aop.proxy.SpringCglibProxyFactory; +import cn.hutool.core.lang.Console; +import lombok.Setter; +import org.junit.Test; + +public class IssueI74EX7Test { + @Test + public void proxyTest() { + final SmsBlend smsBlend = new SmsBlendImpl(1); + final ProxyFactory engine = new JdkProxyFactory(); + engine.proxy(smsBlend, new SimpleAspect()); + } + + /** + * https://gitee.com/dromara/hutool/issues/I74EX7
+ * Enhancer.create()默认调用无参构造,有参构造或者多个构造没有很好的兼容。 + * + */ + @Test + public void cglibProxyTest() { + final SmsBlend smsBlend = new SmsBlendImpl(1); + final ProxyFactory engine = new CglibProxyFactory(); + engine.proxy(smsBlend, new SimpleAspect()); + } + + /** + * https://gitee.com/dromara/hutool/issues/I74EX7
+ * Enhancer.create()默认调用无参构造,有参构造或者多个构造没有很好的兼容。 + * + */ + @Test + public void springCglibProxyTest() { + final SmsBlend smsBlend = new SmsBlendImpl(1); + final ProxyFactory engine = new SpringCglibProxyFactory(); + engine.proxy(smsBlend, new SimpleAspect()); + } + + @Test + public void springCglibProxyWithoutConstructorTest() { + final SmsBlend smsBlend = new SmsBlendImplWithoutConstructor(); + final ProxyFactory engine = new SpringCglibProxyFactory(); + engine.proxy(smsBlend, new SimpleAspect()); + } + + public interface SmsBlend{ + void send(); + } + + public static class SmsBlendImpl implements SmsBlend{ + + private final int status; + + public SmsBlendImpl(final int status) { + this.status = status; + } + + @Override + public void send() { + Console.log("sms send." + status); + } + } + + @Setter + public static class SmsBlendImplWithoutConstructor implements SmsBlend{ + + private int status; + + @Override + public void send() { + Console.log("sms send." + status); + } + } +}