动态代理技术是整个java技术中最重要的一个技术,它是学习java框架的基础,不会动态代理技术,那么在学习Spring这些框架时是学不明白的。动态代理技术就是用来产生一个对象的代理对象的。在开发中为什么需要为一个对象产生代理对象呢?
举个例子:现实中明星都是有经纪人的,经纪人的作用就是帮明星来处理业务,节目组要找明星来表演,那么肯定不是和明星直接联系的,而是明星的经纪人出面和节目组洽谈,而且只有当业务条件满足时,明星才会出面表演,那么这个经纪人就是明星的代理人,他可以帮助明星来筛选演出业务,条件达不到要求的表演就过滤了,只有达到要求了,才会被经纪人接收然后明星就会出场表演,也就是拦截了外界对明星的直接访问。这也是JAVA中代理对象的作用,产生一个代理对象用来拦截外界对真实业务的访问。
所以在这里明确代理对象的两个概念:
1、代理对象存在的价值主要用于拦截对真实业务对象的访问。
2、代理对象应该具有和目标对象(真实业务对象)相同的方法。
明星的经纪人是完全知道自己代理的这个明星所具有的哪些表演技能的,比如唱歌、跳舞(这些表演技能就是对象的方法,那么这个代理对象就需要具备和对象一样的方法,但最终执行方法的是明星)。节目组找到了经纪人需要他的明星表演唱歌跳舞的基本节目之类的,而经纪人是不会唱歌跳舞的,但是经纪人知道自己代理的明星都会这些基本的表演方法(if("method'.equals(method.getName())),那么这个时候经纪人就提出了要求,需要1W块钱以上才能出面演出(if(money>=100000){method.invoke(明星,唱歌,10000)}),如果节目组给不到10000,那么接下来的方法就不会执行了。要是节目组愿意出这个钱,这个时候后面的方法就会执行,就是通过经纪人调用明星的表演方法了。
public interface ActorCompany {
//演艺公司默认的技能,演员必须具备。
void song(String name,float money);
void dance(String name,float money);
}
2.演员 Actor.java 演艺公司的演员应该具备演艺公司的所需技能(真实业务类具备的方法)
public class Actor implements ActorCompany {
//演员都具有演艺公司默认的表演方法
public void song(String name,float money){
System.out.println("拿到钱:"+money+",唱首歌:"+name);
}
public void dance(String name,float money){
System.out.println("拿到钱:"+money+",跳个舞:"+name);
}
}
3.经纪人 ActorProxy.java 具有演员的方法,还具有谈判功能(if条件),要达成条件才能返回方法。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//创建一个代理类
public class ActorProxy {
//找到演员
Actor actor= new Actor();
/*
经纪人获得具有跟节目组接触洽谈的代理方法
代理经纪人具有演员一样的身份getClass().getClassLoader(),
一样的表演方法getClass().getInterface,
但是多一个判断,也就是需要一个条件new InvocationHandler才能达成表演方法。
条件达成后 返回演员的表演方法
*/
public ActorCompany getProxy() {
return (ActorCompany) Proxy.newProxyInstance(actor.getClass().getClassLoader(),
actor.getClass().getInterfaces(), new InvocationHandler() {
/*
达成条件如下 :需要一个参数来判断执行一个方法。
例如:演员表演唱歌 需要10000以上;
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Float money = (Float) args[1];
String name = (String) args[0];
//达成特定条件,才会表演哪个项目
if ("song".equals(method.getName())) {
if (money >= 10000) {
return method.invoke(actor, name, money);
}
}
if ("dance".equals(method.getName())) {
if (money >= 30000) {
return method.invoke(actor, name, money);
}
}
return null;
}
});
}
}
4、节目组 MovieGroup.java 找到经纪人告诉经纪人节目内容,满足经纪人的条件,得到演员的表演并执行。
public class MovieGroup {
public static void main(String[] args){
//节目组准备的钱和节目名字
String song="青花瓷";
String dance="街舞";
Float money1=10000f;
Float money2=30000f;
//节目组从演艺公司找到一个经纪人
ActorCompany actorProxy=new ActorProxy().getProxy();
//节目组把信息给经纪人,达成条件就会返回演员的演出方法,没有达成就不返回。
actorProxy.song(song,money1);
actorProxy.dance(dance,money2);
}
}
以上程序逻辑已经结束 下面是运行结果:
拿到钱:10000.0,唱首歌:青花瓷
拿到钱:30000.0,跳个舞:街舞
Process finished with exit code 0
使用了代理类的代理对象指定了Handler处理器,不管是运行哪个方法都是要经过InvocationHandler类来判断筛选,然后执行的都是method.invoke()方法。由于invoke方法被调用需要三个参数:代理对象、方法、方法的参数,因此不管代理对象哪个方法调用处理器的invoke方法,都必须把自己所在的对象、自己(调用invoke方法的方法)、方法的参数传递进来。