四要素:
1、目标对象
2、代理对象
3、InvocationHandler处理器,即具体要怎么增强或拦截目标方法
4、要代理的目标对象方法通过接口表示
对于客户端,代理类与目标类是一样的。当代理类调用方法时,将会回调InvocationHandler实现增强或拦截
目标对象与接口:
public interface Stars00 {
String getName();
void sing();
void dance();
void rap();
void exercise();
}
import java.util.Random;
import java.util.concurrent.TimeUnit;
public class KunKun implements Stars00 {
Random random = new Random();
@Override
public String getName() {
int i = random.nextInt(5);
try {
TimeUnit.SECONDS.sleep(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "大家好!我是坤坤!";
}
@Override
public void sing() {
int i = random.nextInt(5);
try {
TimeUnit.SECONDS.sleep(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("鸡哥在唱歌!");
}
@Override
public void dance() {
int i = random.nextInt(5);
try {
TimeUnit.SECONDS.sleep(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("鸡哥在跳舞!");
}
@Override
public void rap() {
int i = random.nextInt(5);
try {
TimeUnit.SECONDS.sleep(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("鸡哥在rap!");
}
@Override
public void exercise() {
int i = random.nextInt(5);
try {
TimeUnit.SECONDS.sleep(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("鸡哥在打篮球!");
}
}
代理类:
import my.proxy.Handler.TimerInvocationHandler;
import java.lang.reflect.Proxy;
// 返回代理类
public class ProxyUtil {
public static Object getTargetProxy(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new TimerInvocationHandler(target));
}
}
处理器类:
增强:计算坤坤唱跳表演花费的时间
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
//单独写一个handler类,增强复用,而不是在代理类中通过匿名内部类或者lambda表达式实现
public class TimerInvocationHandler implements InvocationHandler {
Object target;
public TimerInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("getName")) {
return method.invoke(target, args);
}
long start = System.currentTimeMillis();
Object returnResult = method.invoke(target, args);
long end = System.currentTimeMillis();
System.out.println("花费:" + (end - start) / 1000 + "s");
return null;
}
}
测试类:
对于客户端,代理类和目标类是一样的,因为实现了相同的接口。
代理类与目标类是关联关系(has a),代理类中有一个属性:目标类 target
在target调用方法时,实现增强或拦截
应用到的技术:
反射,回调
import my.proxy.proxyutils.ProxyUtil;
import my.proxy.target.KunKun;
import my.proxy.target.Stars00;
import org.junit.Test;
public class TestProxy {
@Test
public void TestKunkun() {
Stars00 kunKun = new KunKun();
Stars00 kunkunProxy = (Stars00) ProxyUtil.getTargetProxy(kunKun);
System.out.println(kunkunProxy.getName());
kunkunProxy.sing();
kunkunProxy.dance();
kunkunProxy.rap();
kunkunProxy.exercise();
}
}
遇到新的明星,直接复用Handler
public interface Stars01 {
String getName();
void rap();
}
import java.util.concurrent.TimeUnit;
public class XiaoGui implements Stars01 {
@Override
public String getName() {
return "我是小鬼!";
}
@Override
public void rap() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("小鬼在rap:如果你也可以像我一样,那真是太酷啦!");
}
}
import my.proxy.proxyutils.ProxyUtil;
import my.proxy.target.KunKun;
import my.proxy.target.Stars00;
import my.proxy.target.Stars01;
import my.proxy.target.XiaoGui;
import org.junit.Test;
public class TestProxy {
@Test
public void TestKunkun() {
Stars00 kunKun = new KunKun();
Stars00 kunkunProxy = (Stars00) ProxyUtil.getTargetProxy(kunKun);
System.out.println(kunkunProxy.getName());
kunkunProxy.sing();
kunkunProxy.dance();
kunkunProxy.rap();
kunkunProxy.exercise();
}
@Test
public void TestXiaogui() {
Stars01 xiaogui = new XiaoGui();
Stars01 xiaoguiProxy = (Stars01) ProxyUtil.getTargetProxy(xiaogui);
System.out.println(xiaoguiProxy.getName());
xiaoguiProxy.rap();
}
}
静态代理:
通过继承实现(is a)
子类重写父类方法实现增强或拦截。
问题:
1、耦合度过高
2、代码没复用
3、类爆炸。对于所有目标类都需要子类。动态代理时,Java自动生成代理类对象字节码在内存中