通过JDK动态代理和自定义注解来控制方法级别的权限访问

  自定义一个场景,玩电脑和睡觉,电脑只能是人玩,但是人,猫,狗都可以睡觉
  
  这里将玩游戏和睡觉抽象出两个方法:
    1.playComputer
    2.sleep
  
  将人和动物抽象出来成一个类:
    1.Animal

  但是怎么通过动态代理加自定义注解去让playComputer只能让人调用,sleep方法人,猫,狗都可以调用呢?

  有个思路就是,在方法上面加注解,且注解的内容就是允许访问该方法的Animal的type,在调用这个playComputer或者sleep方法的时候进行拦截,并且取出被调用那个方法上面的注解值与调用对象Animal的type进行比对,如果包含就访问这个方法,如果不包含就不调用.

  注意:这里使用的是jdk的动态代理,所以需要将注解放到接口上面,如果放到目标类的方法上面会导致读取不到,如果使用cglib的动态代理,当然那就不需要接口了,直接将注解放到目标类方法上面也能读取到注解的内容.

  如下工程:

通过JDK动态代理和自定义注解来控制方法级别的权限访问_第1张图片

  首先自定义注解,并且在里面定义人,猫,狗的常量:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Secure {
    String[] values();
    static String HUMAN = "HUMAN";
    static String DOG = "DOG";
    static String CAT = "CAT";
}

  将人,猫,狗抽象成Animal类:

public class Animal {
    private String name;
    private String type;

    getter and setter...
    public String toString()...

  接口类:

public interface Deal {

    @Secure(values = {Secure.HUMAN})
    public String playComputer(Animal a);

    @Secure(values = {Secure.HUMAN, Secure.CAT, Secure.DOG})
    public String sleep(Animal a);
}

  目标类:

public class DealImpl implements Deal {
    public String playComputer(Animal a) {
        String re = a + " playComputer, DealImpl方法";
        System.out.println(re);
        return re;
    }

    public String sleep(Animal a) {
        String re = a + " sleep,  DealImpl方法";
        System.out.println(re);
        return re;
    }
}

  关键的代理类,里面将被调用的方法上面的注解内容取出,和调用者的类型进行匹配:

public class ProxyDeal implements InvocationHandler {

    private Object target;

    public Object bind(Object target) {
        this.target = target;
        Object targetProxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        return targetProxy;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Animal animal = null;
        Object result = null;
        if (null != args && args.length != 0) {
            animal = (Animal) args[0];
        }
        if (method.isAnnotationPresent(Secure.class)) {
            Secure annotation = method.getAnnotation(Secure.class);
            String[] values = annotation.values();
            if (null != values && values.length != 0) {
                for (String value : values) {
                    if (value.trim().equals(animal.getType().trim())) {
                        result = method.invoke(target, args);
                        return result;
                    }
                }
                System.out.println("禁止访问:" + animal);
                return null;
            }
            annotation.values();
        }
        return result;
    }
}

  测试主函数:

public class SecureMain {
    public static void main(String[] args) {
        Deal deal = new DealImpl();
        ProxyDeal proxy = new ProxyDeal();
        Deal dealProxy = (Deal) proxy.bind(deal);
        Animal animal = new Animal("zhangsan", Secure.CAT);
        String re1 = dealProxy.playComputer(animal);
        String re2 = dealProxy.sleep(animal);
        System.out.println(re1 + "   main");
        System.out.println(re2 + "   main");
    }
}

  测试结果:

通过JDK动态代理和自定义注解来控制方法级别的权限访问_第2张图片

你可能感兴趣的:(Java)