静态代理与动态代理
一、静态代理
代理,即代替真实角色进行一系列操作。静态代理是有实实在在的代理类存在,并且和目标类实现相同的接口。他的优点是效率高,因为所有的类都是已经编写完成的,客户端只需要取得代理对象并且执行即可,同时他可以实现对目标对象中指定的方法进行增强但是他也有如下缺点:与目标类实现相同的接口代码冗余,如果接口发生改变,代理类中的方法也要修改,代理类服务于一种类型的对象,如果要服务多类型的对象,那么势必要为每种类型的对象都生成代理类,工作量变大,开发效率变低
代理模式的角色分析:
抽象角色:一般会使用抽象类或者接口实现
真实角色:被代理的角色
代理角色:代理真实角色,代理真实角色后,一般会做一些附属的操作;
客户:使用代理角色进行一些操作
一个简单的案例就是房屋出租:
接口(抽象角色)
package org.westos.staticproxy;
public interface Rent {
void rent();
}
真实角色
package org.westos.staticproxy;
public class Host implements Rent {
public void rent() {
System.out.println("我是房东,我要出租房屋");
}
}
代理角色
package org.westos.staticproxy;
public class StaticProxy implements Rent {
Host host;
public void setHost(Host host) {
this.host = host;
}
public void rent() {
lookHouse();
charge();
}
public void lookHouse(){
System.out.println("我是中介,我带客户看房子");
}
public void charge(){
System.out.println("我是中介,我收中介费");
}
}
测试(客户)
package org.westos.staticproxy;
public class Test {
public static void main(String[] args) {
//真实角色
Host host = new Host();
//代理角色
StaticProxy staticProxy = new StaticProxy();
host.rent();
staticProxy.setHost(host);
staticProxy.rent();
}
}
运行结果:
二、动态代理
基于接口实现:JDK
基于类实现:cglib
下面我们演示一下JDK动态代理,首先需先掌握两个类:
-
InvocationHandler
InvocationHandler是由代理实例的调用处理程序实现的接口 。
invoke(Object proxy, 方法 method, Object[] args)
处理代理实例上的方法调用并返回结果 -
Proxy
Proxy
提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。newProxyInstance(ClassLoader loader, 类<?>[] interfaces, InvocationHandler h)
返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。
要实现动态代理,重点是实现InvocationHandler接口,重写invoke方法处理代理实例上的方法调用并返回结果,由Proxy类的newProxyInstance方法(参数分别为本类的类加载器,抽象角色的Interfaces和本类对象)动态生成代理类,由动态生成的代理类即可实现业务。
现在用动态代理实现上面的租房案例
接口:
package org.westos.dynamicproxy;
public interface Rent {
void rent();
}
真实角色:
package org.westos.dynamicproxy;
public class Host implements Rent {
public void rent() {
System.out.println("我是房东,我要出租房屋");
}
}
动态代理类生成接口对象:
package org.westos.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxy implements InvocationHandler {
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//动态生成代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
}
//代理类
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
lookHouse();
Object invoke = method.invoke(rent, args);
charge();
return invoke;
}
private void lookHouse(){
System.out.println("中介带看房子");
}
private void charge(){
System.out.println("收中介费");
}
}
测试类
package org.westos.dynamicproxy;
public class Test {
public static void main(String[] args) {
Host host = new Host();
DynamicProxy proxy = new DynamicProxy();
proxy.setRent(host);
Rent proxy1 = (Rent) proxy.getProxy();
proxy1.rent();
}
}
运行结果:
动态代理的好处:
- 可以使真实角色更加纯粹,不用去关注一些公共的事情
- 公共的业务由代理来完成,实现业务的分工
- 公共业务的要扩展的话,可以更加集中和方便
- 一个动态代理,一般代理一类的业务,一个动态代理可以代理多个类,代理接口