由于动态代理是针对接口的,所以首先需要声明一个接口,该测试接口如下所示
public interface TestI { void test(); }
有了接口,就要有实现类,实现类如下所示
public class TestImpl implements TestI { @Override public void test() { System.out.println("目标方法"); } }
要使用动态代理,就要创建一个代理类,该代理类实现InvocationHandler,并实现对应的方法
public class TestProxy implements InvocationHandler { private Object tarObj; public TestProxy() { } public TestProxy(Object tarObj) { this.tarObj = tarObj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("目标方法之前进行操作"); method.invoke(tarObj, args); System.out.println("目标方法之前进行操作"); return null; } }
invoke为实现的方法,该方法不需要自己调用,当产生好代理对象后,调用目标方法的时候,这个方法会被自动调用,各个参意义如下
proxy:代理对象(也就是下面主方法里的testProxy)
method:该method就是将要调用的真正的方法的Method对象,打印出来的结果是:
public abstract void asdasd.TestI.test()
(这个和反射机制的method是一回事,具体实现可以看反射机制的相关知识)
args:目标方法对应参数的数组
写好了代理类,接着就是使用了,为了方便,直接在TestProxy类中创建main方法进行测试,该类完整代码如下:
public class TestProxy implements InvocationHandler { //所要代理的真实的对象 private Object tarObj; public TestProxy() { } public TestProxy(Object tarObj) { this.tarObj = tarObj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("目标方法之前进行操作"); //利用反射机制调用真实对象的方法 method.invoke(tarObj, args); System.out.println("目标方法之后进行操作"); return null; } public static void main(String[] args) { TestImpl testImpl = new TestImpl(); TestProxy testProxy = new TestProxy(testImpl); TestI testI = (TestI) Proxy.newProxyInstance(TestI.class.getClassLoader(), new Class[]{TestI.class}, testProxy); testI.test(); } }
首先创建一个目标对象,即testImpl
接着当成参数传递给代理类,以此来创建一个代理对象,此
newProxyInstance方法返回一个代理对象,该方法有3个参数,意义如下:
ClassLoader:指定由动态代理产生的类由哪个类加载器来加载
Class[]:由动态代理产生的类的class数组(需要是接口)
InvocationHandler:实现InvocationHandler的接口的类的对象
运行程序输出的结果如下:
目标方法之前进行操作
目标方法
目标方法之后进行操作
就这样,一个动态代理的小实例就写好了
ps:
主方法中的testI不是真正的对象,而是一个代理对象,执行System.out.println(testI.getClass().getName());输出的结果如下
com.sun.proxy.$Proxy0
这就是一个代理对象,除非是代理不同类的对象,所产生的Proxy*才会出现序号不同的情况,如果仅仅是再次使用newProxyInstance来创建一个新的代理对象,那么序号还是一样的