有没有一种方法可以使用ByteBuddy为没有空构造函数的类创建代理? 这个想法是为给定的具体类型创建代理,然后将所有方法重定向到处理程序。 此测试展示了为没有空构造函数的类创建代理的场景,并且抛出java.lang.NoSuchMethodException 实体: ...
提示:本站收集StackOverFlow近2千万问答,支持中英文搜索,鼠标放在语句上弹窗显示对应的参考中文或英文, 本站还提供 中文繁体 英文版本 中英对照 版本,有任何建议请联系yoyou2525@163.com。
我想创建一个类Sample的动态代理,该类具有两个没有公共构造函数的类,它不起作用并给出错误。 但是,如果我将构造函数设置为Public,则可以正常工作。 字节伙伴中是否有可能实现这一目标?
还有可能使addToList(..)方法成为非公共方法吗?
样例代码:
public class Sample {
private String name;
private String college;
private String id;
private List<String> fieldList = new LinkedList<>();
Sample() {
//some code
System.out.println("No arg constructor invoked");
}
Sample(String id) {
this();
this.id = id;
}
public String getId() {
return this.id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
System.out.println("Setting name: "+ name);
this.name = name;
}
public String getCollege() {
return college;
}
public void setCollege(String college) {
System.out.println("Setting college: "+college);
this.college = college;
}
public void addToList(String fieldName){
fieldList.add(fieldName);
}
public List<String> getFieldList() {
return Collections.unmodifiableList(fieldList);
}
public static Sample getProxyObject(String id) {
Sample proxyObj = null;
try {
Class<? extends Sample> dynamicType = new ByteBuddy()
.subclass(Sample.class, ConstructorStrategy.Default.IMITATE_SUPER_CLASS )
.method(ElementMatchers.nameStartsWith("set"))
.intercept(MethodDelegation.to(new GreetingInterceptor()))
.make()
.load(Sample.class.getClassLoader())
.getLoaded();
proxyObj = dynamicType.getConstructor(String.class).newInstance(id);
} catch (Exception ex){
ex.printStackTrace();
}
return proxyObj;
}
public static Sample getProxyObject() {
Sample proxyObj = null;
try {
proxyObj = new ByteBuddy()
.subclass(Sample.class)
.method(ElementMatchers.nameStartsWith("setName"))
.intercept(MethodDelegation.to(new GreetingInterceptor()))
.make()
.load(Sample.class.getClassLoader())
.getLoaded().newInstance();
} catch (Exception ex){
ex.printStackTrace();
}
return proxyObj;
}
public static class GreetingInterceptor {
public void abc(@SuperCall Callable<Void> zuper, @Origin Method method, @Super Sample parentObj, @This Object myself, @AllArguments Object[] args) {
try {
parentObj.addToList(method.getName());
zuper.call();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
要测试的主要课程:
public class SampleMain {
public static void main(String[] args) {
System.out.println("===Scenario 1=====");
Sample proxyObject = Sample.getProxyObject();
proxyObject.setName("John Doe");
System.out.println("===Scenario 2=====");
proxyObject.getFieldList().stream().forEach(System.out::println);
Sample proxyObject1 = Sample.getProxyObject("id123");
proxyObject1.setName("John Doe");
proxyObject1.setCollege("MIT");
System.out.println("Id is: "+proxyObject1.getId());
proxyObject1.getFieldList().stream().forEach(System.out::println);
}
}
错误跟踪:
===方案1 =====
Exception in thread "main" java.lang.IllegalAccessError: tried to access method com.algorithm.Sample.<init>()V from class com.algorithm.Sample$ByteBuddy$J74XiIU8
at com.algorithm.Sample$ByteBuddy$J74XiIU8.<init>(Unknown Source)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.lang.Class.newInstance(Class.java:442)
at com.algorithm.Sample.getProxyObject(Sample.java:88)
at com.algorithm.SampleMain.main(SampleMain.java:6)
如果protected
构造函数没问题,则:
Sample()
更改为protected Sample()
以使方案1起作用:这使ByteBuddy产生的子类可以访问no-args构造函数。 将Sample(String id)
更改为protected Sample(String id)
,然后在getProxyObject(String id)
更改
proxyObj = dynamicType.getConstructor(String.class).newInstance(id);
至
Constructor<? extends Sample> ctor = dynamicType.getDeclaredConstructor(String.class); ctor.setAccessible(true); proxyObj = ctor.newInstance(id);
这使方案2起作用。 ConstructorStrategy.Default.IMITATE_SUPER_CLASS
在子类中生成相同的受保护构造函数,因此您需要使用getDeclaredConstructor()
来获取它,然后使其可访问。
您还可以将addToList(..)
受保护的,因为GreetingInterceptor
可以访问它,因此可以正常工作。
请注意,只有在同一运行时包中定义了程序包私有构造函数,该类才对类可见。 默认情况下,Byte Buddy在加载类而不指定ClassLoadingStrategy
时会创建一个新的类加载ClassLoadingStrategy
。 如果一个软件包的名称相同,但未由同一类加载器加载,则运行时软件包将有所不同。
我假设通过指定:
.load(Sample.class.getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
尽管其他答案中提到的反射性访问已损坏,但您的代理仍可以按预期工作。 但是请注意,此策略使用了不安全的API,该API在以后的JVM版本中可能不再起作用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.