做了一个简单的demo。Car是一个接口,Jeep是Car的实现类。
package bo; public interface Car { public abstract void carName(); }
package bo; public class Jeep implements Car{ @Override public void carName(){ System.out.println("Nice to Meet You, I'm Jeep"); } }
自定义了一个InvocationHandler类,并重载了invoke方法,对使用该Handler生成的代理类$Proxy0在调用非final方法前注入了一句话。效果可以理解为类似AOP。
package handler; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.logging.Logger; import bo.Car; public class DetailInvocationHandler implements InvocationHandler{ private Car car; public DetailInvocationHandler(Car car){ this.car = car; } Logger logger = Logger.getLogger(DetailInvocationHandler.class.getName()); @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { /** * 1、此时如果如下调用,则将栈溢出。 * 原因:可以看到proxy即为生成的代理类$Proxy0,当调用proxy的carName方法时, * 等于调用了handler中的invoke方法,此时,就会陷入死循环导致最后栈溢出, * 然而调用getClass方法并不会溢出,这是因为该方法时final的。 * 2、此处传入proxy的话可以对于annotation、name、method等参数进行监控 * */ System.out.println(proxy.getClass().getName()); // 不会溢出 // ((Car)proxy).carName(); // 会溢出 logger.info("Now Enter In InvocationHandler!"); method.invoke(car, args); return null; } }
最后,分别采用三种方法进行代理类的生成,并在最后测试了final方法是否会被拦截。
package service.impl; import handler.DetailInvocationHandler; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import bo.Car; import bo.Jeep; import service.CarService; class mockClass{ } public class CarServiceImpl implements CarService{ @SuppressWarnings("unchecked") public static void main(String[] args) throws Exception{ /** * ClassLoader: * 在调用用户定义的用JAVA实现的ClassLoader时,调用的是ExtClassLoader * 在调用其他默认情况下的class(classpath下的)时,调用的是AppClassLoader * */ System.out.println(Jeep.class.getClassLoader()); System.out.println(Car.class.getClassLoader()); System.out.println(mockClass.class.getClassLoader()); /** * Proxy.newProxyInstance方法中,需要三个参数 * 一、ClassLoader,用以将生成的class加载入JVM中去执行 * 二、Interface,用以根据需要实现的接口去生成代理类(相当于子类) * 三、InvocationHandler,用以对代理类的方法进行调度 * */ Car car = new Jeep(); InvocationHandler handler = new DetailInvocationHandler(car); /** * 1和2为两种获取interface的方法 * */ System.out.println("====================1=========================="); Car proxy = (Car)Proxy.newProxyInstance(mockClass.class.getClassLoader(),car.getClass().getInterfaces(), handler); proxy.carName(); System.out.println("====================2=========================="); Car proxy2 = (Car)Proxy.newProxyInstance(Car.class.getClassLoader(),new Class[]{Car.class}, handler); proxy2.carName(); /** * Class.getConstructor用来声明特指一个代理类的构造函数(源代码中:Proxy(InvocationHandler h){this.h = h}) * Constructor.newInstance用来填入构造函数,并生成相应的代理类 * */ System.out.println("====================3=========================="); Class class1 = Proxy.getProxyClass(Car.class.getClassLoader(), car.getClass().getInterfaces()); Car proxy3 = (Car)class1.getConstructor(new Class[]{InvocationHandler.class}).newInstance(new Object[]{handler}); proxy3.carName(); /** * final修饰符的方法不会被拦截! */ System.out.println("====================4=========================="); Car proxy4 = (Car)Proxy.newProxyInstance(Car.class.getClassLoader(),new Class[]{Car.class}, handler); System.out.println(proxy4.getClass().getName()); } }
详细的解释以及需要关注的一些地方都在注释中了,大部分在网上都能查得到。只是做了个demo将这些记忆点都记录了下来而已。