1、核心作用
通过代理,控制对对象的访问。可以详细控制访问某个对象的方法,在调用这个方法之前做前置处理,调用这个方法之后做后置处理。Spring的AOP就是利用代理模式进行实现的。
2、代理模式的角色
抽象角色:定义代理角色和真实角色的公共对外方法;
真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色使用;
代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。实现了将统一的流程控制放到了代理角色中处理。代理角色持久真实角色的引用
3、应用场景
安全代理:屏蔽对真实对象的直接访问;
远程代理:通过代理类处理远程方法调用(RMI);
延迟加载:先加载轻量级的代理对象,真正需要的时候才加载真实的对象。比如开发一个大文档查看软件,里面有大量的图片,有可能图片的大小有100M,在打开文件时不可能将所有的图片都显示出来,于是可以使用代理模式,当需要查看图片时,用proxy进行大图片的打开。
4、分类
代理可以分为静态代理和动态代理;
静态代理:静态生产代理类。
动态代理:动态生成代理类。
实现动态代理的技术:JDK自带的动态代理,javaassist字节码操作库实现,CGLIB,ASM(底层使用指令,可维护性较差)。
5、代码实现
5.1 静态代理
5.1.1 创建抽象角色
package com.zdw.proxy.staticProxy;
/**
* 抽象角色,这里比作歌星
*/
public interface Star {
/**
* 面谈
*/
public void confer();
/**
* 签合同
*/
public void signContract();
/**
* 唱歌
*/
public void sing();
/**
* 收钱
*/
public void collectMoney();
}
5.1.2 创建真实角色
package com.zdw.proxy.staticProxy;
/**
* 真实角色,真正要做的事情就是唱歌
*/
public class ZhouJieLun implements Star {
@Override
public void confer() {
}
@Override
public void signContract() {
}
@Override
public void sing() {
System.out.println("我是周杰伦,我会唱歌,而且很好听。。。");
}
@Override
public void collectMoney() {
}
}
5.1.3 创建代理角色
package com.zdw.proxy.staticProxy;
/**
* 经纪人,相当于是代理角色,除了不会唱歌,其他的事情都是我干的
*/
public class JingjiRen implements Star {
//经纪人知道周杰伦的联系方式,相当于代理对象持有真实角色的引用
private Star star;
//构造方法给真实角色赋值
public JingjiRen(Star star) {
this.star = star;
}
@Override
public void confer() {
System.out.println("经纪人和第三方公司面谈");
}
@Override
public void signContract() {
System.out.println("经纪人和第三方公司签合同");
}
@Override
public void sing() {
//调用真实角色唱歌
star.sing();
}
@Override
public void collectMoney() {
System.out.println("经纪人负责收钱。。。");
}
}
5.1.4 测试
package com.zdw.proxy.staticProxy;
public class TestStaticProxy {
public static void main(String[] args) {
Star zhouJieLun = new ZhouJieLun();//真实角色
Star proxy = new JingjiRen(zhouJieLun);//代理角色
proxy.confer();
proxy.signContract();
proxy.sing();
proxy.collectMoney();
}
}
打印结果:
经纪人和第三方公司面谈
经纪人和第三方公司签合同
我是周杰伦,我会唱歌,而且很好听。。。
经纪人负责收钱。。。
5.2 动态代理
这里使用的是JDK自带的动态代理来实现,主要用到的是两个类:java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler
Proxy:动态生成代理类和对象;
InvocationHandler:它里面的invoke方法实现对真实对象的代理访问,每次通过Proxy的newProxyInstance生成代理类对象时,都要指定对应的处理器对象。
5.2.1 创建抽象接口
package com.zdw.proxy.dynamicProxy;
public interface Singer {
public void sing();
}
5.2.2 创建真实角色
package com.zdw.proxy.dynamicProxy;
public class ZhouJieLun implements Singer {
@Override
public void sing() {
System.out.println("我唱的七里香很好听哦。。。");
}
}
5.2.3 创建处理器
package com.zdw.proxy.dynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 处理器,动态代理的对象会先执行invoke方法
*/
public class SingerHandler implements InvocationHandler {
private Singer singer;//持有真实对象的引用
public SingerHandler(Singer singer) {
this.singer = singer;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我会先帮歌手去签合同");
//调用真实对象来唱歌
Object o = method.invoke(singer, args);
System.out.println("唱歌之后,我负责来帮歌手收钱");
return o;
}
}
5.2.4 测试
package com.zdw.proxy.dynamicProxy;
import java.lang.reflect.Proxy;
public class TestDynamicProxy {
public static void main(String[] args) {
Singer singer = new ZhouJieLun();
SingerHandler singerHandler = new SingerHandler(singer);
Singer proxy = (Singer) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Singer.class}, singerHandler);
proxy.sing();
}
}
运行结果:
我会先帮歌手去签合同
我唱的七里香很好听哦。。。
唱歌之后,我负责来帮歌手收钱
6、应用场景
Struts2中拦截器的实现;
数据库连接池关闭处理;
Hibernate中延迟加载的实现;
MyBatis中实现拦截器插件;
AspectJ的实现;
Spring中AOP的实现:日志拦截和声明式事务管理;
RMI远程方法调用。
来源:CSDN
作者:zengdongwen
链接:https://blog.csdn.net/zengdongwen/article/details/104158593