Java及Spring框架中的AOP技术汇总--使用JDK反射对接口进行动态代理及限制条件

上一篇中我们使用接口方式,利用虚函数动态绑定机制实现了一个代理模式,来进行方法的拦截(AOP)处理。

本篇换成使用JDK内置的方式来进行方法(AOP)拦截

  1. 同前篇,定义IGreet接口:
package blf_aop_demo;
/*
1. 从java语言的角度来演示aop的两种实现(基于接口实现和基于类实现)
2. spring
*/
public interface IGreet {
    void sayHello(String name);

    void sayGoodBye(String name);
}
  1. 同前篇,实现IGreet接口:
package blf_aop_demo;

public class GreetImp implements IGreet {
    public void sayHello(String name) {
        System.out.println("Hello " + name);
    }

    public void sayGoodBye(String name) {
        System.out.println("GoodBye " + name);
    }
}
  1. 不同前篇,而是实现JDK中的java.lang.reflect.InvocationHandler接口:
package blf_aop_demo;

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

//JDKProxy
public class ReflectGreetProxy implements InvocationHandler {

    //注意: 这里使用了Object类型,提升到java类结构体系的最高层
    //java中一切都是Object,万物之源!
    
    private Object target;// 真实的,被代理的对象

    // 私有够着方法,用于限制new出本对象
    // 只能被下面的工厂方法使用
    private ReflectGreetProxy(Object target) {
        this.target = target;
    }

    public static Object newInstance(Object obj) {
        //使用Proxy静态方法
        //Proxy是java reflect包中的一个静态类(全部是静态方法)
        //Proxy作用是利用反射,自动生成target类的代理类一切必要的内容
        //很关键一点,obj.getClass().getInterfaces(),意味着使用JDK中的反射Proxy只能基于接口继承的对象
        return java.lang.reflect.Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),
                new ReflectGreetProxy(obj));
    }

    // Method method:調用的方法
    // Object[] args:方法要傳入的參數
    // invoke实现对GreetImpl中方法的调用,同时也可以在这里加入自己想要实现的操作
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // TODO Auto-generated method stub
        Object result;
        try
        {
            //自定義的處理
            System.out.println("--before method " + method.getName());
            //調用GreetImpl中方法
            result = method.invoke(target, args);
        }catch(InvocationTargetException e)
        {
            throw e.getTargetException();
        }catch(Exception e)
        {
            throw new RuntimeException("unexpected invocation exception: " + e.getMessage());
        }finally
        {
            System.out.println("--after method " + method.getName());
        }
        return result;
    }
}

4.测试代码:

 public static void testReflectGreet(){
        //生成一个真实对象
        IGreet real = new GreetImp();
        //从真实对象生成一个代理对象
        IGreet greet = (IGreet)ReflectGreetProxy.newInstance(real);
        
        //此时调用的是代理对象上的say系列方法
        //代理对象内部会调用public Object invoke(Object proxy, Method method, Object[] args)
        //对其所有方法进行拦截
        greet.sayHello("jackyBu");
        greet.sayGoodBye("jackyBu");
    }
public static void main(String[] args) {
        System.out.println("blf_aop_demo_test");
        testReflectGreet();
    }
  1. 测试结果:
blf_aop_demo_test
--before method sayHello
Hello jackyBu
--after method sayHello
--before method sayGoodBye
GoodBye jackyBu
--after method sayGoodBye
  • 我们会看到,代理对象会对真实对象的所有方法进行拦截,如果我有选择性的拦截,那就可以通过过滤被拦截方法的名称就可以了,例如你只想拦截sayHello,而不想拦截sayGoodBye,则进行方法名判定就可以了。

  • 相对于自己实现,使用JDK反射Proxy方式更加简单,特别是在真实对象有很多方法时,优势就显示出来了

  • 唯一的限制:

很关键一点,obj.getClass().getInterfaces(),意味着使用JDK中的反射Proxy只能代理基于接口继承的对象
JDK代理要求被代理的类必须实现接口,有很强的局限性

从上面这句注释可以了解到,jdk反射Proxy只能对接口进行方法拦截,不能对的方法进行拦截

下一篇我们来解决如何实现类的动态代理

你可能感兴趣的:(Java及Spring框架中的AOP技术汇总--使用JDK反射对接口进行动态代理及限制条件)