JDK动态代理是
java.lang.reflect.*
包提供的方式,它必须借助一个接口才能产生一个对象,也就是说JDK动态代理
是对接口的代理。一般要使用JDK动态代理
,首先得定义接口,然后再对这个接口的实现类对象进行代理,产生代理对象。Spring
的AOP
就是JDK动态代理
的应用之一。
第一步:定义接口
JDK动态代理
必须有接口,这里仅仅定义一个及其简单的接口用于示例。
package com.lemon.designmode.interfaces;
/**
* @author lemon
* @date 2018/2/11 上午10:25
*/
public interface HelloWorld {
void sayHello();
}
第二步:实现接口
这里是接口的实现类,具体的业务逻辑写在这里。
代码语言:javascript复制package com.lemon.designmode.bean;
import com.lemon.designmode.interfaces.HelloWorld;
/**
* @author lemon
* @date 2018/2/11 上午10:23
*/
public class HelloWorldImpl implements HelloWorld {
@Override
public void sayHello() {
System.out.println("向Java世界问好...");
}
}
这里是最简单的Java
接口和实现类的关系,此时可以开始动态代理了,一般会分为两个步骤:第一是建立代理对象和真实服务对象的代理和被代理关系,第二步是实现代理对象具体方法的逻辑。
第三步:动态代理绑定和代理逻辑实现
在JDK动态代理
中,要实现代理逻辑类必须娶实现java.lang.reflect.InvocationHandler
接口,它内部定义了一个invoke
方法,并提供接口数组用于将代理对象下挂到被代理对象所属的接口下,也就是说代理对象和被代理对象都是实现了同一个接口,只不过被代理对象是显式实现(使用了关键字implements
),代理对象是运行时实现。
package com.lemon.designmode.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author lemon
* @date 2018/2/11 上午10:27
*/
public class JdkProxyExample implements InvocationHandler {
private Object target;
/**
* 该方法用于将真实对象绑定到代理类,并返回代理对象
*
* @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);
System.out.println("代理方法调用真实对象之后的逻辑处理");
return obj;
}
}
上面的代码实现了两步:第一是将真实服务对象和代理对象进行了绑定;第二步是实现了代理逻辑。
这里通过bind
方法将真实服务对象保存到了代理类的成员变量中,并返回了代理对象。
newProxyInstance
方法分析: 1)第一个参数是类加载器,这里使用的是target
的类加载器 2)第二个参数是传入真实服务对象所在的接口,用于将代理对象下挂到和真实服务对象所在的接口 3)第三个参数是定义实现方法逻辑的代理类,this
表示当前类对象,也就是代理类,那么这个代理类就必须实现InvocationHandler
接口的invoke
方法,它就是代理逻辑的实现方法。
invoke
方法分析: 1)第一个参数是代理对象,就是bind
方法生成的对象 2)第二个参数是当前调度的方法 3)第三个参数是调度方法的参数。
第四步:测试JDK动态代理
代码语言:javascript复制package com.lemon.designmode.test;
import com.lemon.designmode.bean.HelloWorldImpl;
import com.lemon.designmode.interfaces.HelloWorld;
import com.lemon.designmode.proxy.JdkProxyExample;
/**
* @author lemon
* @date 2018/2/11 上午10:44
*/
public class JdkProxyTest {
public static void main(String[] args) {
JdkProxyExample jdkProxyExample = new JdkProxyExample();
HelloWorld proxy = (HelloWorld) jdkProxyExample.bind(new HelloWorldImpl());
proxy.sayHello();
}
}
这里使用代理对象直接调用真实服务对象同名方法,实现了零入侵式代码增强。Spring AOP就是这个原理,在真实服务对象方法加入前置通知、后置通知、环绕通知等。 测试方法运行结果如下:
代码语言:javascript复制进入代理方法
代理方法调用真实对象之前的逻辑处理
向Java世界问好...
代理方法调用真实对象之后的逻辑处理