代理对象和真实对象必须实现同一个接口
API介绍
Proxy
类
-
使用JDK的动态代理的要求:目标对象必须实现了接口。
-
相关类:JDK的类
java.lang.reflect.Proxy
,提供了生成代理对象的方法 -
生成代理对象的方法:
Proxy.newProxyInstance(ClassLoader loader,Class[] interfaces, InvocationHandler h)
-
loader
:类加载器 -
interfaces
:目标对象所实现的接口 字节码数组 -
h
:用于写代理对象要做的事情,通常写成InvocationHandler
接口的匿名内部类,实现其invoke
方法
-
InvocationHandler
接口
-
接口只有一个方法:每次当代理对象被调用时,这个方法都会执行。在方法里通常写代理对象的行为
invoke(Object proxy, Method method, Object[] args)
-
方法的参数:
-
Object proxy
:最终生成的代理对象 -
Method method
:用户在调用代理对象时,所执行的方法对象 -
Object[] args
:用户在调用代理对象,执行方法时,所传递的实参
-
-
方法的返回值:
-
当用户调用的代理对象的方法后,得到的返回值
-
使用示例
1.同一个接口
package com.dian.proxy.jdk;
//真是对象,代理对象的共同接口
public interface Star {
void sing(String name);
void dance(String name);
}
2.实现类
package com.dian.proxy.jdk;
//真实对象的方法
public class SuperStar implements Star {
public void sing(String name) {
System.out.println("明星在唱歌:" + name);
}
public void dance(String name) {
System.out.println("明星在跳舞:" + name);
}
}
3.有通知类(用于进行功能增强的)
package com.dian.proxy.jdk;
//这里是可以增强真实对象的方法
public class StarAdvice {
public void before() {
System.out.println("彩排一下~!");
}
public void after() {
System.out.println("收钱~!");
}
}
4.使用动态代理生成代理对象
package com.dian.proxy.jdk;
import org.junit.Test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class TestJDKProxy {
@Test
public void testJDK() {
//1.创建真实对象
final Star realObj = new SuperStar();
//2.创建代理对象 只是在外人面前是代理对象在干活,实际上还是真实对象在干活
Star proxyObj = (Star) Proxy.newProxyInstance(
realObj.getClass().getClassLoader(), //真实类使用什么类加载器,代理类也使用什么类加载器
realObj.getClass().getInterfaces(), //真实对象用什么接口,代理对象也用什么接口
new InvocationHandler() { //调用处理器是代理对象和真实对象沟通的桥梁
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// System.out.println("调用了invoke方法~");
/*
在这里让真实对象干活
*/
/*
invoke方法: 当我们在外面使用代理对象调用任何方法,这个invoke方法都会被调用一次。
proxy : 代理对象
method : 外面调用的那个方法的对象,
proxyObj.sing("忘情水"); ==== method 就是sing方法
args :表示方法参数,表示外面调用的方法用到的参数
proxyObj.sing("忘情水"); ==== args : 忘情水
*/
//调用方法之前增强
StarAdvice sa = new StarAdvice();
sa.before();
//为了匹配任意情况,所以这里必须要用反射调用。
Object object = method.invoke(realObj, args);
//调用方法之后,增强
sa.after();
return object;
}
}
);
//3. 让代理唱歌,跳舞
proxyObj.dance("极乐净土");
}
}