前言
现实中的代理,买房、租房需要找中介,中介可以帮你去做一些额外的事情,你只需要付钱。明星有经纪人,经纪人可以帮明星处理一些琐碎的事情,明星只负责表演之类的。
动态代理就是为对象创建一个代理类,去为类对象的行为做一些额外的辅助操作。
提示:以下是本篇文章正文内容,下面案例可供参考
一、什么是代理
1.动态代理允许我们使用代理对象来包装其他对象。你还可以使用代理对象来拦截对被包装对象的请求,然后用代理再转发给这些被包装的对象。还可以在拦截调用前后增加自己的代码。对于动态代理施加限制可以防止包装任意对象。在正常条件下,动态代理使你能完整地控制被包装对象的操作。
2.通俗来说就是某些场景下对象会找一个代理对象,来辅助自己完成一些工作,如:歌星(经济人),买房的人(房产中介)。
3.代理主要是对对象的行为额外做一些辅助操作。
二、如何创建代理对象
java中代理的代表类是:java.lang.reflect.Proxy
Proxy提供了一个静态方法,用于为对象产生一个代理对象返回
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
第一个参数:ClassLoader loader 主要是告诉代理对象为谁代理,obj.getClass().getClassLoader() 所以创建当前对象之后,用当前对象获取到它的类再通过它的类获取到它的类加载器。
第二个参数:obj.getClass().getInterfaces() 主要是告诉代理对象需要代理这些对象的哪些行为。所以就需要通过当前类对象获取到它的类再获取到它实现的接口列表,就能知道它实现了哪些方法。
第三个参数:new InvocationHandler() 通过匿名内部类创建代理类对象,它会去实现刚才传入到接口列表。
三、动态代理的步骤
1.必须存在接口。
2.被代理的对象需要实现接口。
3.使用Proxy类提供的方法创建的对象为代理对象。
这里举例一个明星代理说明。
每个明星都拥有自己的技能。这里定义一个技能接口。
/**
* 技能接口
*/
public interface Skill {
void jump();
void sing();
}
然后定义一个明星类实现这个技能接口,重写属于自己的方法。
/**
* 明星类
*/
public class Start implements Skill {
private String name;
public Start(String name) {
this.name = name;
}
@Override
public void jump() {
System.out.println(this.name+"在跳舞");
}
@Override
public void sing() {
System.out.println(this.name+"在唱歌");
}
}
创建一个代理类,提供一个获取当前类的代理类的方法,参数就是传入的对象。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 明星代理类
*/
public class StartAgenProxy {
/**
* 返回一个代理对象
*/
//代理对象通过匿名内部类创建,所以会实现Skill接口,所以返回值可以用接口接收(多态)
public static Skill getProxy(Start obj){
//为对象生成一个代理对象
//代理对象和对象都实现同一个接口,所以代理对象可以直接向上转型为Skill接口
return (Skill)Proxy.newProxyInstance(obj.getClass().getClassLoader(), //对象获取类,类再获取到类加载器
obj.getClass().getInterfaces(), //先拿到类对象,再获取它实现的接口,代理对象才知道需要代理哪些方法
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("收首付款");
//method 正在调用的方法 args正在调用方法的参数
Object rs = method.invoke(obj, args);
System.out.println("收尾款");
return rs;
}
}
);
}
}
提示:Object rs = method.invoke(obj, args); 这里会调用本身类的方法。比如说测试类中代理类调用jump()方法,proxy.jump(); invoke就相当于s.jump()方法。这个method就是当前类的方法,args就是当前方法的参数。这个method.invoke(obj,args) 会返回当前类调用方法的返回值,有就返回,没有就是null。
这里代理对象的返回值可以是Skill接口,是因为匿名内部类创建代理对象的时候实现了这个Skill接口,本身方法返回的是一个Object类,向下转型为Skiil类(多态)。
测试类
public class Test {
public static void main(String[] args) {
Start s= new Start("杨超越");
//new 创建 Proxy代理 Instance对象
/**
* newProxyInstance(ClassLoader loader,
* Class<?>[] interfaces,
* InvocationHandler h)
* 1.这个方法内部会创建一个代理类,再通过代理类创建一个代理对象
* 所以需要类加载器,好让底层去加载这个代理类去生成代理对象
* 2.代理类要实现的接口列表,因为接口里面有他需要代理的行为
* 3.方法调用分配到的调用处理程序(代理的核心处理程序)
*
*/
//为对象生成一个代理对象
Skill proxy = StartAgenProxy.getProxy(s);
//调用jump或者sing的时候就会走代理
proxy.jump();
System.out.println("------");
proxy.sing();
}
}
创建当前明星对象之后,如果直接用明星对象去调用run或者jump方法,就只能实现当前方法功能。
但是创建这个明星的代理对象之后,就可以在这个明星功能的前后做代理方法,比如收首尾款之类的。
四、总结
1.动态代理就是利用反射机制在运行时创建代理类的对象。
2.需要被代理的对象和代理对象要实现共同接口。
3.通过代理对象调用方法会先走向代理,代理可以为方法做一些额外的辅助工作,然后真正触发对象的方法执行,回到代理中,由代理负责返回结果给方法的调用者。