切面代理工具中的cglib支持多参数构造生成

This commit is contained in:
Looly 2023-05-25 00:16:08 +08:00
parent 99c5e13930
commit 2e88e74cae
4 changed files with 174 additions and 6 deletions

View File

@ -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构造方法设置成publicissue#I77LUE@Gitee
* 【core 】 切面代理工具中的cglib支持多参数构造生成issue#I74EX7@Gitee
### 🐞Bug修复
* 【core 】 修复URLUtil.decode无法解码UTF-16问题issue#3063@Github

View File

@ -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> 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);
}
/**
* 创建代理对象<br>
* https://gitee.com/dromara/hutool/issues/I74EX7<br>
* 某些对象存在非空参数构造则需遍历查找需要的构造完成代理对象构建
*
* @param <T> 代理对象类型
* @param enhancer {@link org.springframework.cglib.proxy.Enhancer}
* @param targetClass 目标类型
* @return 代理对象
*/
@SuppressWarnings("unchecked")
private static <T> 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");
}
}

View File

@ -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> 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);
}
/**
* 创建代理对象<br>
* https://gitee.com/dromara/hutool/issues/I74EX7<br>
* 某些对象存在非空参数构造则需遍历查找需要的构造完成代理对象构建
*
* @param <T> 代理对象类型
* @param enhancer {@link Enhancer}
* @param targetClass 目标类型
* @return 代理对象
*/
@SuppressWarnings("unchecked")
private static <T> 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");
}
}

View File

@ -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<br>
* 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<br>
* 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);
}
}
}