当我们需要通过注解的方式来判断一个类以及这个类的方法需要不要使用动态代理,就会发现动态代理的内部是无法获取到方法的注解信息的,通过一个例子来看,还是使用上一篇文章中所创建的对象信息。

创建注解

作用于类上的注解AnnotationInClass

package com.kezez.java;

import java.lang.annotation.*;

/**
 * @author : kaygb
 * @date : 2022/7/23 19:39
 * @desc :
 * @website : https://www.170601.xyz/
 * @blog : https://www.kezez.com/
 * @github : https://github.com/kaygb
 */
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationInClass {
}

作用于方法上的注解AnnotationInMethod

package com.kezez.java;

import java.lang.annotation.*;

/**
 * @author : kaygb
 * @date : 2022/7/23 19:40
 * @desc :
 * @website : https://www.170601.xyz/
 * @blog : https://www.kezez.com/
 * @github : https://github.com/kaygb
 */
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationInMethod {
}

创建实体类

创建实体类BirdTwo实现Bird接口(Bird接口为上篇文章创建)

package com.kezez.java;

/**
 * @author : kaygb
 * @date : 2022/7/23 19:44
 * @desc :
 * @website : https://www.170601.xyz/
 * @blog : https://www.kezez.com/
 * @github : https://github.com/kaygb
 */

@AnnotationInClass
public class BirdTwo implements Bird {

    public BirdTwo() {
    }

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

创建动态代理

package com.kezez.java;

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

/**
 * @author : kaygb
 * @date : 2022/7/23 19:41
 * @desc :
 * @website : https://www.170601.xyz/
 * @blog : https://www.kezez.com/
 * @github : https://github.com/kaygb
 */
public class DynamicProxy implements InvocationHandler {
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        if (target.getClass().isAnnotationPresent(AnnotationInClass.class)) {
            System.out.println("类上有注解");
        }
        if (method.isAnnotationPresent(AnnotationInMethod.class)) {
            System.out.println("方法上有注解");
        }
        System.out.println("动态代理:打开鸟笼的门");
        Object res = method.invoke(target, args);
        return res;
    }
}

通过isAnnotationPresent方法传入注解的类可以判断是方法或者类上是否使用了此注解,执行后我们可以发现,动态代理方法只输出了类上的注解,而并没有获取到方法上的注解。

类上有注解
动态代理:打开鸟笼的门
fly

问题导致的原因

为啥获取不到方法中的注解呢?其实是因为Proxy.newProxyInstance传入的是被代理对象的接口,而不是具体的实现类,所以只能获取到接口方法上的注解而获取不到实现类上的注解。

Proxy.newProxyInstance(birdTwo.getClass().getClassLoader(), birdTwo.getClass().getInterfaces(), dynamicProxy);

解决动态代理无法获取实现类方法上的注解

那么如何解决?其实也很简单,我们在创建DynamicProxy时,为此动态代理对象创建了一个属性传入了具体的目标对象target,我们可以通过动态代理中的method.getName()获取到方法的名称,然后使用target.getClass().getMethod(method.getName())获取到目标对象实现类的方法,获取到实现类的方法,具体如下:

target.getClass().getMethod(method.getName()).isAnnotationPresent(AnnotationInMethod.class)

完整的代码如下所示:

package com.kezez.java;

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

/**
 * @author : kaygb
 * @date : 2022/7/23 19:41
 * @desc :
 * @website : https://www.170601.xyz/
 * @blog : https://www.kezez.com/
 * @github : https://github.com/kaygb
 */
public class DynamicProxy implements InvocationHandler {
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        if (target.getClass().isAnnotationPresent(AnnotationInClass.class)) {
            System.out.println("类上有注解");
        }
        if (method.isAnnotationPresent(AnnotationInMethod.class)) {
            System.out.println("方法上有注解");
        }
        if (target.getClass().getMethod(method.getName()).isAnnotationPresent(AnnotationInMethod.class)) {
            System.out.println("实现类的方法上有注解");
        }
        System.out.println("动态代理:打开鸟笼的门");
        Object res = method.invoke(target, args);
        return res;
    }
}

执行main方法

package com.kezez.java;

import java.lang.reflect.Proxy;

public class Main {

    public static void main(String[] args) {

//        Bird birdOne = new BirdOne();
//        Birdcage birdcage = new Birdcage(birdOne);
//        birdcage.fly();

        Bird birdTwo = new BirdTwo();
        DynamicProxy dynamicProxy = new DynamicProxy();
        dynamicProxy.setTarget(birdTwo);
        Object obj = Proxy.newProxyInstance(birdTwo.getClass().getClassLoader(), birdTwo.getClass().getInterfaces(), dynamicProxy);
        ((Bird) obj).fly();
    }
}

输出的结果如下:

类上有注解
实现类的方法上有注解
动态代理:打开鸟笼的门
fly
最后修改:2022 年 07 月 23 日
如果觉得我的文章对你有用,请随意赞赏