概念
一个类代表另一个类的功能,就好比我们生活中的中介,我们要把楼卖出去,可是我们不可能天天在大街上问,有没有人愿意买我的楼嘛,中介就是帮我们干这件事,相当于我们的代理,中介跟我们都是有卖楼这同一操作的,但是真正卖楼的具体操作还是我们,中介只是负责找客户。
静态代理
案例:我们都玩过游戏吧,有些游戏只能在国外玩,如果想在国内玩,那肯定得有个代理商才行。今年国外最火的游戏《寸头大作战》想在国内开拓业务,于是找了小明做代理商。
实现代码如下:
首先,游戏最重要的就是赚钱了,所以定义一个游戏的接口:
public interface Game {
//赚钱
public void makeMoney();
}
接下来实例化《寸头大作战》的代码:
public class Ctb implements Game {
@Override
public void makeMoney() {
System.out.println("今年盈利:" + new Random().nextInt(100) + "亿");
}
}
小明做代理,那肯定也得有小明这个类:
public class XiaoMing implements Game {
private Ctb ctb;
public XiaoMing() {
this.ctb = new Ctb();
}
@Override
public void makeMoney() {
System.out.println("通过小明代理");
this.ctb.makeMoney();
}
}
最后就是测试类了:
public class Main {
public static void main(String[] args) {
//国内想玩游戏,得找小明代理才行
XiaoMing xiaoMing = new XiaoMing();
xiaoMing.makeMoney();
}
}
实验结果:
如果此时,小红听到了这个游戏这么赚,她也想当个代理,那么我们来帮她实现吧:
public class XiaoHong implements Game {
private Ctb ctb;
public XiaoHong() {
this.ctb = new Ctb();
}
@Override
public void makeMoney() {
System.out.println("通过小红代理");
this.ctb.makeMoney();
}
}
测试类:
public class Main2 {
public static void main(String[] args) {
//国内想玩游戏,得找小明,小红代理才行
XiaoMing xiaoMing = new XiaoMing();
XiaoHong xiaoHong = new XiaoHong();
xiaoMing.makeMoney();
xiaoHong.makeMoney();
}
}
实验结果:
我们可以看出,静态代理实现的时候,我们需要给代理人都实现Game的接口,他们得有共同的方法才行。
JDK方式动态代理
上面的例子中,如果我们要实现的不只是小明,小红,而是其他人,如果按照静态代理的方式,没新建一个代理人,都需要重新建一个类,如果不断变换,那就需要不断更新类,因此引入动态代理的概念。
同样的先定义一个游戏的接口:
public interface Game {
//赚钱
void makeMoney();
}
我们这次想定义一个人的类,里面包含名字这一参数
public class Person implements Game {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void makeMoney() {
System.out.println("今年盈利:" + new Random().nextInt(100) + "亿");
}
}
接下来就是我们的代理类了,这个代理类继承InvocationHandler类,其中这个动态代理的类中的参数可以进行任意修改,可以改为任意的Object类
public class DynamicProxyHandler implements InvocationHandler {
private Person person;
public DynamicProxyHandler(Person person) {
this.person = person;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我们现在找的代理人是:" + person.getName());
Object o = method.invoke(person,args);
return o;
}
}
测试类:
public class Main {
public static void main(String[] args) {
//实例一个代理对象
Person person = new Person("花花");
//通过放射技术,进行动态生成
Game game = (Game) Proxy.newProxyInstance(
Person.class.getClassLoader(),
new Class[]{Game.class},
new DynamicProxyHandler(person));
game.makeMoney();
}
}
实验结果:
Cglib代理
该方法不用定义接口,首先定义的是被代理对象,也就是上文案例中的游戏《寸头大作战》:
public class Ctb {
public void makeMoney(){
System.out.println("今年盈利:" + new Random().nextInt(100) + "亿");
}
}
接下来还需要写的是代理人:
public class Person implements MethodInterceptor {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//打印要代理的类
System.out.println(o.getClass().getSuperclass().getName());
//打印代理人
System.out.println("现在的代理人为:" + getName());
Object result = null;
result = methodProxy.invokeSuper(o, objects);
return result;
}
}
其中这个方法有点特殊,需要进行导包,这里就使用maven进行配置,在pom.xml中进行配置:
<dependencies>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.12</version>
</dependency>
</dependencies>
测试类:
public class Main {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Ctb.class);
enhancer.setCallback(new Person("花花"));
Ctb ctb = (Ctb) enhancer.create();
ctb.makeMoney();
}
}
测试结果:
总结:如果被代理对象有定义接口类,就使用JDK方式动态代理,如果没有定义接口类,就使用Cglib代理,静态代理局限性太大,无须考虑。
本文的代码:https://pan.baidu.com/s/1ubFxLFGBosES0Qzq3WhzAg
提取码:vngc