代理模式,为其他对象提供一种代理以控制对这个对象的访问。
静态代理:
委托者和代理者实现同一个接口,委托者持有代理者的实例,在代理任务的过程中可以做些其他事情,比如
远程代理:为一个对象在不同的地址空间提供局部代表,隐藏一个对象存在不同地址空间的事实。
虚拟代理,根据需要创建开销很大的对象, 通过它来存放实例化需要很长时间的真实对象。如打开网页时未加载的图片,此时代理存储了真实图片的路径和尺寸。
安全代理,用来控制真实对象访问的权限。
智能指引,代理处理另外一些事。如计算真实对象的引用次数,无引用时释放对象。访问对象前,检查是否已经锁定它,这样其他对象无法改变它。第一次引用一个持久对象时,把它装入内存等等。
静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类.
//接口
public interface I {
void operation();
}
//委托类
public class Subject implements I{
@Override
public void operation() {
System.out.println("我是委托者");
}
}
//代理类
public class ProxyMan implements I {
I i;
public ProxyMan(I i) {
this.i = i;
}
@Override
public void operation() {
System.out.println("我是代理者,执行了代理");
i.operation();
}
public static void main(String[] args) {
gdut.iot.softdev.review.pattern.proxy.simple.Subject subject = new Subject();
ProxyMan proxyMan = new ProxyMan(subject);
proxyMan.operation();
}
}
动态代理:
1.JDK特性的代理
代理类并非在Java代码中定义,而是运行期根据一些指示生成的
- 可以很方便的对代理类的函数进行统一管理,不需要逐个方法修改
- 代理关系没有硬编码,可以在运行时动态改变
- 解决方法:对发送给服务对象的请求进行拦截,加入处理逻辑后决定是否放行
- 动态代理类涉及的角色
- 委托类(服务对象)和代理类的公共接口
- 具体实现该接口的服务对象
- InvocationHandler接口,会被Proxy类回调,需要一个实现了InvocationHandler的类,在invoke方法中添加代理的逻辑
- 动态代理的核心类Proxy
//接口
public interface Subject {
void goshopping();
}
//委托类
public class RealSubject implements Subject{
public RealSubject() {
}
@Override
public void goshopping() {
System.out.print("Realgoshopping");
}
}
//代理类
*基于JDK的动态代理有两个类要记住,Proxy和InvocationHandler( 接口)蔡渣男想找个代理对象代替他白嫖,首先要把自己这个对象托付给一个类,这个类要实现InvocationHandler接口。
这个类实现了这个接口,重写invoke方法对蔡渣男的白嫖方法进行扩展
public class ProxyMan implements InvocationHandler {
Subject target;
public ProxyMan(Subject target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.print("开始代理");
Object result = method.invoke(target, args);//invoke方法是利用反射调用实际的方法
return result;
}
public static void main(String[] args) {
Subject realSubject = new RealSubject();
InvocationHandler proxyMan = new ProxyMan(realSubject);
Subject realSubjectProxy = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(),
new Class<?>[]{Subject.class}, proxyMan);
realSubjectProxy.goshopping();//参数分别是 代理类的加载器 被代理的接口 代理类实例 原理是通过反射调用这个方法
}
}
- CgLib 动态代理:继承
被代理类没有实现接口的情况下应该用CGLIB, CGLIB是一种通过继承的方法对对象进行代理,构建被代理对象的子类,子类中继承了父类的所有方法,可以通过在子类中重载父类方法来进行功能增强。
需要导入Cgilb的包
import gdut.iot.softdev.rtti.proxy.cglibproxy.CglibMethodInterceptor;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodProxy;
//父类,委托类 想要对这个类增强,可以构建一个子类来实现
public class Dog {
public void call() {
System.out.print("www");
}
}
//拦截类要实现MethodInterceptor接口,在intercept方法中扩展代理对象,注意jdk是对象操作,而cglib是类操作
public class CgLibInterceptor extends CglibMethodInterceptor {
@Override
public Object CglibProxyGeneratory(Class target) {
//这里有用到一个类叫Enhancer,通过这个类可以设置委托类为父类,此类为子类
Enhancer enhancer = new Enhancer();
//把被代理类设置为父类
enhancer.setSuperclass(target);
enhancer.setCallback(this);
//生成一个继承target类的代理对象
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.print("k开始代理");
//对这个类来说,执行原本的方法就是执行他父类的方法,所以用invokeSuper 是方法的调用 不是进行反射
Object result = proxy.invokeSuper(obj,args);
return result;
}
public static void main(String[] args) {
CgLibInterceptor cgLibInterceptor = new CgLibInterceptor();
//传入被代理类。
Dog dogProxy = (Dog) cgLibInterceptor.CglibProxyGeneratory(Dog.class);
dogProxy.call();
}
1、JDK动态代理具体实现原理:
通过实现InvocationHandler接口创建自己的调用处理器;
通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理;
通过反射机制获取动态代理类的构造函数,其唯一参数类型就是调用处理器接口类型;
通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数参入;
2、CGLib动态代理:
利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
3、两者对比:
JDK动态代理是面向接口的。
CGLib动态代理是通过字节码底层继承要代理类来实现,因此如果被代理类被final关键字所修饰,会失败