代理模式
SpringAop的底层,动态代理
例子:租房中介
代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
静态代理
角色分析:
- 抽象角色:一般会属于接口或者抽象类来解决
- 真实角色:被代理的角色
- 代理角色:代理真实的角色,一般又一些附属操作
- 客户:访问代理对象的人
例子:
租房接口:
public interface Rent{
public void rent();
}
房东:
public class Host implements Rent{
public void rent(){};
}
中介:
public class Proxy{
private Host host;
public Proxy(Host host){
this.host = host;
}
public void rent(){
seeHouse();
host.rent();
Pay();
}
// 看房
public void seeHouse(){};
// 付款
public void Pay(){};
}
客户:
public class Client{
public static void main(String[] args){
Host host = new Host();
Proxy proxy = new Proxy(host); // 中介会比房东有更多附属操作。
proxy.rent();
}
}
好处:使得真实角色的操作更加纯粹,不去关心业务。公共业务交给代理角色,公共业务发生扩展时方便集中管理。不改变原来代码的情况下增加功能,控制行为。
AOP:
动态代理
动态代理的代理类是动态生成的。
分为两类:
- 基于接口:JDK动态代理
- 基于类的动态代理:cglib
代理程序
public class ProxyInvocationHandler 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{
// 先执行处理方法
seeHouse();
// 动态代理的本质是使用反射机制去实现
// 此方法生成一个代理类
Object result = method.invoke(rent, args); // 执行方法 , invoke(调用)就是调用Method类代表的方法。可以实现动态调用,例如可以动态的传参数,可以把方法参数化。
Pay();
//执行代理类之后的方法
return result;
}
public void seeHouse(){}
// 付款
public void Pay(){};
}
客户:
public class Client{
public static void main(String[] args){
Host host = new Host();
// 代理角色,要新生成
ProxyInvocationHandler pih = new ProxyInvocationHandler(host); // 中介会比房东有更多附属操作。
// 通过调用程序处理角色来处理要调用的接口对象!
pih.setRent(host);
// 生成代理类proxy,使用反射机制
Rent proxy = pih.getproxy();
}
}
代理程序模板,适用于任意代理对象
public class ProxyInvocationHandler implements InvocationHandler{
// 被代理接口
private Object target;
public void setTarget(Object target){
this.target = target;
}
// 生成代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader, target.getClass().getInterfaces(), this); // 一般只需要改变第二个参数接口。
}
// 处理代理实例,返回结果
public Object invoke(Object proxy, Method method. Object[] args) throws Throwable{
log(method.getName());
// 此方法生成一个代理类
// 对象是通过getproxy生成的,但是调用类的方法的时候调用的是左侧的invoke方法,invoke方法的前面后面又加了别的方法,所以还是代理
Object result = method.invoke(target, args);
return result;
}
// 日志输出方法名称
public void log(String msg){
System.out.println(msg);
}
}
好处:一个动态代理类代理的是一个接口,一类业务。一个动态代理类可以代理多个类,只是实现了同一个接口。
应用:
延迟加载,指为了提高系统的性能,延迟对目标的加载。例如,Hibernate 中就存在属性的延迟加载和关联表的延时加载。