如何创建一个代理对象:作用:在不修改源码的基础下,对已有方法进行增强
特征:字节码随用随创建,随用随加载
分类:1.基于接口的动态代理(JDK动态代理) 2.基于子类的动态代理(CGLib动态代理)
本篇内容主要阐述基于接口的动态代理
基于接口的动态代理 使用要求:被代理类最少要实现一个接口
基于接口的动态代理是JDK官方提供的
涉及的类:java.lang.reflect.Proxy
Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。
涉及的方法:
static Object newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h)
参数:
ClassLoader loader:
类加载器。用于加载代理对象的字节码。写的是:和被代理对象使用相同的类加载器。
因此:
代理哪个对象,就用哪个对象的getClass().getClassLoader()
固定写法
Class>[] interfaces:传递被代理人所实现的所有接口的class文件对象
字节码数组。用于让代理对象和被代理对象具有相同的行为(有相同的方法)
写的是:
如果被代理对象是一个普通类:
则写的是:被代理对象.getClass().getInterfaces();
如果被代理对象是一个接口:
则写的是:new Class[]{被代理接口.class}
固定写法
InvocationHandler h:
一个接口。用于提供增强的代码的。
增强的代码:谁用谁写。
返回值:
Object:代理对象
举例说明
培养明星的接口
//培养明星的接口
public interface Star {
//唱歌
public abstract void changGe();
//跳舞
public abstract void tiaoWu();
//rap
public abstract void rap();
//打篮球();
public abstract void daLanQiu();
//直播带货():
public abstract String zhiBoDaiHuo(int money);
}
蔡徐坤类
//定义明星蔡徐坤类
public class CaiXuKun implements Star{
@Override
public void changGe() {
System.out.println("蔡徐坤在唱歌!");
}
@Override
public void tiaoWu() {
System.out.println("蔡徐坤在跳舞!");
}
@Override
public void rap() {
System.out.println("蔡徐坤在rap!");
}
@Override
public void daLanQiu() {
System.out.println("蔡徐坤在打篮球!");
}
@Override
public String zhiBoDaiHuo(int money) {
System.out.println("蔡徐坤在直播带货,挣了"+money+"钱!");
return "挣大钱了!";
}
}
鹿晗类
//定义明星鹿晗类
public class LuHan implements Star{
@Override
public void changGe() {
System.out.println("鹿晗在唱歌!");
}
@Override
public void tiaoWu() {
System.out.println("鹿晗在跳舞!");
}
@Override
public void rap() {
System.out.println("鹿晗在rap!");
}
@Override
public void daLanQiu() {
System.out.println("鹿晗在打篮球!");
}
@Override
public String zhiBoDaiHuo(int money) {
System.out.println("鹿晗在直播带货,挣了"+money+"钱!");
return "挣大钱了!";
}
}
测试类(代理类)
public class Demo01Proxy {
public static void main(String[] args) {
//创建蔡徐坤对象
CaiXuKun cxk = new CaiXuKun();
//没有使用动态代理,随意的调用蔡徐坤的方法
//cxk.changGe();
//cxk.tiaoWu();
//创建蔡徐坤的代理人对象
Star cxkProxy = (Star)Proxy.newProxyInstance(cxk.getClass().getClassLoader(), cxk.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//获取到拦截到的方法名称
String name = method.getName();
if("tiaoWu".equals(name)){
//对跳舞的方法进行增强
System.out.println("蔡徐坤在央视的舞台跳舞!");
return null;
}
if("zhiBoDaiHuo".equals(name)){
//不让蔡旭进行直播带货
throw new RuntimeException("不允许蔡徐坤直播带货!");
}
//其他的方法(唱歌,rap,打篮球)直接放行
Object v = method.invoke(cxk, args);
return v;
}
});
//cxkProxy.changGe();//蔡徐坤在唱歌!
//cxkProxy.tiaoWu();//蔡徐坤在央视的舞台跳舞!
//cxkProxy.zhiBoDaiHuo(1);//RuntimeException: 不允许蔡徐坤直播带货!
//创建鹿晗对象
LuHan lh = new LuHan();
//获取鹿晗对象的class文件对象
Class lhClazz = lh.getClass();
//创建鹿晗的代理人对象
Star lhProxy = (Star)Proxy.newProxyInstance(lhClazz.getClassLoader(), lhClazz.getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//获取拦截鹿晗对象的方法名称
String name = method.getName();
if("changGe".equals(name)){
//对唱歌的方法进行增强
System.out.println("安排鹿晗在鸟巢的舞台唱歌!");
return null;
}
if("tiaoWu".equals(name)){
throw new RuntimeException("不允许鹿晗给粉丝跳舞!");
}
//其他的方法,直接放行(rap,打篮球,直播带货)
Object v = method.invoke(lh, args);
return v;
}
});
//lhProxy.changGe();//安排鹿晗在鸟巢的舞台唱歌!
//lhProxy.tiaoWu();//RuntimeException: 不允许鹿晗给粉丝跳舞!
String s = lhProxy.zhiBoDaiHuo(100);//鹿晗在直播带货,挣了100钱!
System.out.println(s);//挣大钱了!
}
}



