JAVA的动态代理模式,在Spring的AOP中有着重要的应用,也不容易理解,动态代理模式的定义是:生成一个代理对象,来代理真实对象,通过这个代理对象来控制对真实对象的访问。要实现动态代理必须实现来两个步骤:
代理对象和真实对象建立代理关系;
实现代理对象的代理逻辑方法。
常用的动态代理方式有两种,一种是JDK动态代理,一种是CGLIB动态代理。在Spring中这两种代理方式都用到了。
JDK动态代理
JDK动态代理是通过java.lang.reflect.*包来实现的,实现JDK动态代理必须借助一个接口才能生成代理对象:
public interface HelloWorld{
public void sayHelloWorld();
}
接口实现
public class HelloWorldImpl implements HelloWorld{
@Override
public void sayHelloWorld(){
System.out.println("Hello World");
}
这是一个简单的接口和接口实现,我们可以通过动态代理来操作这个接口对象,在JDK动态代理中,要实现代理逻辑类,必须实现java.lang.reflect.InvocationHandler接口,接口里有个invoke方法,并提供接口数组用于挂载代理对象。
package com.springstudy.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkProxyExample implements InvocationHandler {
//真实对象
private Object target = null;
/*
* 第一步:建立代理对象与真实对象的代理关系,并返回代理对象
* @param target真实对象
* @return 代理对象
*
*/
public Object bind(Object target){
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
/*
* 第二步:代理方法逻辑
* @param proxy
* --代理对象
* @param method
* --当前调度方法
* @param args
* --当前方法参数
* @return 代理结果返回
* @throws Throwable
* --异常
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("进入代理逻辑方法");
System.out.println("在调度真实对象方法前的服务");
Object obj = method.invoke(target, args);//相当于调用sayHelloWorld方法
System.out.println("在调度真实对象之后的服务");
return obj;
}
}
通过 Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), this);建立了代理对象与真实对象的关系,第一个参数是类加载器,这里我们传入的就是HelloWorldImpl的类加载器,第二个参数是冬天代理对象下挂那些接口,这里就是HelloWorld接口,这个参数的类型是Class<?>[],第三个参数是实现代理方法逻辑的实现类,也就是invoke方法哦实现类,所以这里就是this。
通过invoke(Object proxy, Method method, Object[] args)实现了代理逻辑,第一个参数是代理对象,也就是bind方法返回的对象,第二个参数是当前调度的方法,args是调度方法的参数。这里其实是用到了JAVA反射方法的机制,实现代理对象到真实对象方法的调用。
测试代码:
public class TestJdkProxy {
public static void main(String[] args) {
// TODO Auto-generated method stub
JdkProxyTest();
}
public static void JdkProxyTest(){
JdkProxyExample jdk = new JdkProxyExample();
HelloWorld proxy = (HelloWorld)jdk.bind(new HelloWorldImpl());
proxy.sayHelloWorld();
}
}
输出结果如下:
进入代理逻辑方法
在调度真实对象方法前的服务
Hello World
在调度真实对象之后的服务
这里的proxy调用sayHelloWorld方法时,是通过重载的invoke方法实现的,在invoke方法里我们夹带了一些代理逻辑,这样当proxy调用真实对象的方法时,同时也会将代理逻辑执行。动态代理的动态两个字可以理解为使用反射机制实现真实对象方法的动态调用。
参考资料《JAVAEE 互联网轻量级框架整合开发》