java的动态代理无法获取实现类上的注解(问题解决记录)

本文介绍了在Java中使用动态代理时遇到的问题:无法直接获取实现类上的注解,只能获取接口上的注解。原因是代理对象实际为实现了接口的匿名类。解决方案是通过反射获取被代理类的Class对象,从而读取其注解。示例代码展示了如何创建代理对象并在调用方法时处理相关注解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java的动态代理无法获取实现类上的注解(问题解决记录)

问题描述

使用
Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 方法,
创建代理对象时,无法获取实现类上的注解,只能获取接口上的注解

原因

使用 newProxyInstance 方法时,该对象是一个实现了 指定接口 的匿名类(我的理解)。

因此,无法去获取到指定要被代理的类的相关注解,即注解只有声明在接口的相关方法上才能被发现并起效果的原因。

这也是为什么返回类型无法强转为代理时声明的实现类的类型的原因,因为这两压根不是继承关系,但是可以使用接口类型来接收返回值。

解决方法(这个看了应该就明白了)

可以通过传入被代理的实现类的 Class,来解决。我们直接通过该 Class 对象,反射获取它的方法和类以及变量,这样就可以直接获取到相应的注解,然后,修改对应的方法即可。

这个问题我是这样想的,首先你肯定是能知道代理对象的类的,不然你如何写代理,所以这个解决方法应该不存在不行的问题。

示例代码

注解类

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Aspect {
    Class[] types();
}

接口类

public interface IOrder {

    void pay() throws InterruptedException;

    void show();
}

要被代理的实现类

@Aspect(types = TimeUsageIAspect.class)
public class Order implements IOrder {
    private int status = 0;

    @Override
    @Aspect(types = {TimeUsageIAspect.class})
    public void pay() throws InterruptedException {
        // 模拟支付耗时
        Thread.sleep(50);
        this.status = 1;
    }

    @Override
    public void show() {
        System.out.println("status: " +  this.status);
    }

    public static void main(String[] args) throws InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
    	// 实现代理的方法,传入实现类的 Class
        IOrder order = ObjectFactory.newInstance2(Order.class);
        order.pay();
        order.show();
    }
}

ObjectFactory类

public class ObjectFactory {
    public static <T> T newInstance(Class<T> cls) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        // 存放所有的切面类
        LinkedList<IAspect> aspects = new LinkedList<>();
        if (cls.isAnnotationPresent(Aspect.class)) {
            Class[] types = cls.getAnnotation(Aspect.class).types();
            for (Class type : types) {
                IAspect aspect = (IAspect) type.getConstructor().newInstance();
                aspects.push(aspect);
            }
        }


        T target = cls.getConstructor().newInstance();
        return (T) Proxy.newProxyInstance(
                cls.getClassLoader(),
                cls.getInterfaces(),
                (proxy, method, args) -> {
                    for (IAspect aspect : aspects) {
                        aspect.before();
                    }
                    Object result = method.invoke(target, args);
                    for (IAspect aspect : aspects) {
                        aspect.after();
                    }
                    return result;
                }
        );
    }

    public static <T> T newInstance2(Class<T> cls) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
    	// 记录方法与相关处理的映射之间的关系
        HashMap<String,LinkedList<IAspect> > methodAspectMap = new HashMap<>();
        Method[] methods = cls.getMethods();
        for (Method method : methods) {
            if (method.isAnnotationPresent(Aspect.class)) {
                Class[] types = method.getAnnotation(Aspect.class).types();
                LinkedList<IAspect> aspects = new LinkedList<>();
                for (Class type : types) {
                    IAspect aspect = (IAspect) type.getConstructor().newInstance();
                    aspects.push(aspect);
                }
                methodAspectMap.put(method.getName(), aspects);
            }
        }

        T target = cls.getConstructor().newInstance();
        return (T) Proxy.newProxyInstance(
                cls.getClassLoader(),
                cls.getInterfaces(),
                (proxy, method, args) -> {
                	// 根据方法名,执行对应注解的该干的事
                    if (methodAspectMap.containsKey(method.getName())) {
                        LinkedList<IAspect> aspects = methodAspectMap.get(method.getName());
                        for (IAspect aspect : aspects) {
                            aspect.before();
                        }
                        Object result = method.invoke(target, args);
                        for (IAspect aspect : aspects) {
                            aspect.after();
                        }
                        return result;
                    }
                    return method.invoke(target, args);
                }
        );
    }
}
题外话

这个示例代码,大部分是我学其他教程时写的,然后边学边瞎改的就遇到了这个问题,百度又没百度到方法(这个不用想,肯定是姿势不对),灵机一动就想到了这个办法,记录一下。代码肯定有许多莫名其妙的地方,别去管就完事。比如这方法的注解判断,感觉我整的好烂。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值