gpt4 book ai didi

java - 无法从JDK动态代理获取方法注释

转载 作者:行者123 更新时间:2023-11-30 06:49:05 25 4
gpt4 key购买 nike

我在网上找了好久。但没有用。请帮忙或尝试给出一些如何实现这一目标的想法

在我的客户端中,我可以使用真实对象而不是代理对象来获取方法上的注释。

我曾经以为是因为我自己的Annotation上缺少Retention Annotation。但这不起作用。这是代码:

注释:

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {}

界面:

public interface UserDao {
void save();
void update();
}

实现:

public class UserDaoImpl implements UserDao{
@Override
@MyAnnotation
public void save() {
System.out.println("save");
}

@Override
public void update() {
System.out.println("update");
}
}

客户端+驱动程序应用程序:

public class Client {
public static void main(String[] args) {
final UserDaoImpl dao = new UserDaoImpl();
Method[] methods = dao.getClass().getMethods();
for (Method m : methods){
if(m.getAnnotation(MyAnnotation.class) != null)
System.out.println("save method is enhanced");
}

UserDao proxy = (UserDao) Proxy.newProxyInstance(
dao.getClass().getClassLoader(),
dao.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
obj = dao;
if(method.getAnnotation(MyAnnotation.class) != null)
System.out.println("save method is enhanced2");
Object result = method.invoke(obj, args);
return result;
}
}
);

proxy.save();
System.out.println("-----------");
proxy.update();
}
}

最佳答案

动态代理直接实现给定的接口(interface),它不会像您假设的那样扩展实现类。我已经修复了您的非编译代码,添加了更多日志输出,并将所有类移至我的一个包中,因为 Java 编译器不喜欢默认包。

驱动程序应用程序(已更新):

package de.scrum_master.so;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Client {
public static void main(String[] args) {
final UserDaoImpl dao = new UserDaoImpl();
Method[] methods = dao.getClass().getMethods();
for (Method method : methods) {
if (method.getAnnotation(MyAnnotation.class) != null) {
System.out.println(method + " -> " + method.getDeclaringClass());
System.out.println("impl method is enhanced");
}
}
System.out.println("-----------");

UserDao proxy = (UserDao) Proxy.newProxyInstance(
dao.getClass().getClassLoader(),
dao.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
obj = dao;
System.out.println(method + " -> " + method.getDeclaringClass());
if (method.getAnnotation(MyAnnotation.class) != null)
System.out.println("proxy method is enhanced");
Object result = method.invoke(obj, args);
return result;
}
});

proxy.save();
System.out.println("-----------");
proxy.update();
}
}

控制台日志:

public void de.scrum_master.so.UserDaoImpl.save() -> class de.scrum_master.so.UserDaoImpl
impl method is enhanced
-----------
public abstract void de.scrum_master.so.UserDao.save() -> interface de.scrum_master.so.UserDao
save
-----------
public abstract void de.scrum_master.so.UserDao.update() -> interface de.scrum_master.so.UserDao
update

在这里您可以看到UserDaoImpl和动态UserDao代理之间的区别。

我不确定你为什么用 springaop 标记这个问题,因为在你的示例代码中没有 AOP 也没有 Spring,但我想你想使用 Spring AOP也是基于动态代理的。您可以选择强制将实现接口(interface)的组件创建为 CGLIB 代理,即代理直接扩展其基类。也许它可以工作,但我不确定 CGLIB 代理的详细工作原理。如果它们要重写每个方法,则会应用 JVM 限制:重写方法永远不会继承方法注释。

您的技术问题就这么多。但你真正想要实现的目标是什么?这是许多人在这里犯的一个错误:他们没有描述他们想要实现的目标,但心中已经有了一个可能不合适的技术解决方案。这样他们就错过了解决问题的其他选择。通常,应用程序设计是基于他们的错误假设而存在缺陷的,如果他们不那么执着于他们的解决方案偏差,那么很容易修复。也许如果这对您没有帮助,您可以创建一个新问题,将其链接到这个问题,其中显示您的 Spring AOP 问题并描述您想要实现的目标。

<小时/>

更新:如果您想从代理的调用处理程序访问原始(“真实”)对象,您可以这样做:

改进的驱动程序应用程序:

package de.scrum_master.so;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Client {
public static void main(String[] args) {
final UserDaoImpl dao = new UserDaoImpl();
Method[] methods = dao.getClass().getMethods();
for (Method method : methods) {
if (method.getAnnotation(MyAnnotation.class) != null) {
System.out.println(method + " -> " + method.getDeclaringClass());
System.out.println("impl method is enhanced");
}
}
System.out.println("-----------");

UserDao proxy = (UserDao) Proxy.newProxyInstance(
dao.getClass().getClassLoader(),
dao.getClass().getInterfaces(),
new MyInvocationHandler(dao)
);

proxy.save();
System.out.println("-----------");
proxy.update();
}

private static class MyInvocationHandler implements InvocationHandler {
private Object realObject;

public MyInvocationHandler(Object realObject) {
this.realObject = realObject;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method + " -> " + method.getDeclaringClass());
if (method.getAnnotation(MyAnnotation.class) != null)
System.out.println("proxy method is enhanced");
if (realObject.getClass().getMethod(method.getName(), method.getParameterTypes()).getAnnotation(MyAnnotation.class) != null)
System.out.println("real object method is enhanced");
return method.invoke(realObject, args);
}

}
}

控制台日志:

public void de.scrum_master.so.UserDaoImpl.save() -> class de.scrum_master.so.UserDaoImpl
impl method is enhanced
-----------
public abstract void de.scrum_master.so.UserDao.save() -> interface de.scrum_master.so.UserDao
real object method is enhanced
save
-----------
public abstract void de.scrum_master.so.UserDao.update() -> interface de.scrum_master.so.UserDao
update

请注意行增强了真实对象方法

关于java - 无法从JDK动态代理获取方法注释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43152221/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com