代理模式(Proxy pattern)
代理模式为其它对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用。可以在目标对象实现的功能上,增加额外的功能补充,即扩展目标对象的功能。
举个例子来说:房东和租房中介之间就是代理与被代理的关系,房东出租房屋,可以看做是一个目标对象,其他琐碎事交给中介来处理。
代理模式设计到的角色:
抽象角色:声明真实对象和代理角色的共同接口
代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。代理对象在执行真实对象操作时,可以附加自己的操作,相当于对真实对象进行封装。将统一的流程控制放到代理角色中处理。
真实角色:代理角色所代表的真实对象,定义真实角色所要实现的业务逻辑,供代理角色调用。是我们最终要引用的对象。
代理模式的分类:
1. 静态代理
2. 动态代理
静态代理的实现:
1.接口
package com.dsx.proxy;
//出租房屋
public interface Rent {
public void rent();
}
2. 真实角色
package com.dsx.proxy;
//房东
public class Host implements Rent{
@Override
public void rent() {
System.out.println("房东要出租房子");
}
}
3. 代理角色
package com.dsx.proxy;
public class Proxy implements Rent {
private Host host;
public Proxy(){}
public Proxy(Host host) {
this.host = host;
}
@Override
public void rent() {
seeHouse();
System.out.println("代理帮助房东出租房子");
fare();
}
public void seeHouse(){
System.out.println("中介带你看房子");
}
public void fare(){
System.out.println("收中介费");
}
}
4. 客户端访问代理角色
package com.dsx.proxy;
public class Client {
public static void main(String[] args) {
//房东要出租房子,
Host host = new Host();
//代理 中介帮助房东出租房子,但是,代理一般会有一些附属操作
Proxy proxy = new Proxy(host);
//不用面对房东,直接找中介就可以
proxy.rent();
}
}
代理模式的优点:
1.代理模式能将代理对象与真实对象被调用的目标对象分离,使真实角色的操作更加纯粹,不用关注一些公共的业务。
2.一定程度上降低了系统的耦合度,扩展性好。
3.保护目标对象。
4.增强目标对象。
代理模式的缺点:
1.代理模式会造成系统设计中类的数目的增加(一个真实角色就会产生一个代理角色)。
2.在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢
3.增加了系统的复杂度。
动态代理
动态代理和静态代理角色一样
动态代理的代理类是动态生成的,不是我们直接写好的
动态代理分为两大类:基于接口的动态代理,基于类的动态代理
基于接口------> JDK动态代理
基于类: CGLIB代理 java字节码操作库实现:javassist
代码实现(以JDK代理为例):
需要了解的类:
• JDK自带的动态代理
– java.lang.reflect.Proxy
• 作用:动态生成代理类和对象
– java.lang.reflect.InvocationHandler(处理器接口)
• 可以通过invoke方法实现对真实角色的代理访问。 • 每次通过Proxy生成代理类对象对象时都要指定对应的处理器对象
1. 接口
package com.dsx.proxy;
//出租房屋
public interface Rent {
public void rent();
}
2. 真实角色
package com.dsx.proxy;
//房东
public class Host implements Rent{
@Override
public void rent() {
System.out.println("房东要出租房子");
}
}
3.动态代理的实现
package com.dsx.proxy.dongtaidaili;
import com.dsx.proxy.Host;
import com.dsx.proxy.Rent;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Object target;
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
//得到生成的代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
//处理代理实例,并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理的本质就是使用反射机制实现
log(method.getName());
Object result = method.invoke(target,args);
return result;
}
public void seeHouse(){
System.out.println("中介看房子");
}
public void fare(){
System.out.println("中介收中介费");
}
public void log(String msg){
System.out.println("执行了"+msg+"方法");
}
}
4.测试代码
public static void main(String[] args) {
//真实角色
Host host = new Host();
//代理角色
ProxyInvocationHandler p = new ProxyInvocationHandler();
//通过调用程序处理角色来处理我们要调用的接口对象
p.setTarget(host);//设置要代理的对象
//动态生成代理类
Rent proxy =(Rent) p.getProxy();
proxy.rent();
}
运行结果:
动态代理相比静态代理的优点:
一个动态代理类代理的是一个接口,一般就是对应的一类业务。
一个动态代理类可以代理多个类,只要实现了同一个接口即可。
抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中处理,我们可以更加灵活和统一的处理众多方法。
代理模式在开发框架中的应用场景:
1. struts2中拦截器的实现
2. 数据库连接池关闭处理
3. Hibernate中延迟加载的实现
4. mybatis中实现拦截器插件
5.AspectJ的实现
6. spring中AOP的实现(日志拦截,声明式事务处理)
在Spring的AOP编程中:
如果加入容器的目标对象有实现接口,用JDK代理
如果目标对象没有实现接口,用Cglib代理。
以上便是对代理模式的简单回顾,spring的AOP可以参考本人之前的博客 https://blog.csdn.net/duan196_118/article/details/104133176,
如有不足,欢迎留言指正,望不吝赐教!!!