目录
为其他对象提供一种代理来控制对这个对象的访问
在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介作用
不改变原类的代码,而增强原类对象的功能
可以选择前置、后置、环绕、异常处理增加
为其他对象提供一种代理以控制对这个对象的访问
在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层
优点:
缺点:
代理模式的用意是在代理中控制使用者对目标对象的访问,以及进行功能增强
装饰者模式的用意主要是在原有功能的基础上进行功能的增强
涉及的角色:
源码如下:
public abstract class Subject {
/** 声明一个抽象的请求方法 */
abstract public void request();
}
public class RealSubject extends Subject {
/** 构造函数 */
public RealSubject() {
}
/** 实现请求的方法 */
@Override
public void request() {
System.out.println("RealSubject实现请求");
}
}
public class ProxySubject extends Subject {
private RealSubject realSubject;
/** 构造函数 */
public ProxySubject() {
}
/** 实现请求的方法 */
@Override
public void request() {
preRequest();
if (realSubject == null) {
realSubject = new RealSubject();
}
realSubject.request();
postRequest();
}
/** 请求前的操作 */
private void preRequest() {
System.out.println("请求前的操作。。。");
}
/** 请求后的操作 */
private void postRequest() {
System.out.println("请求后的操作。。。");
}
}
public class Client {
public static void main(String[] args) {
Subject subject = new ProxySubject();
subject.request();
}
}
由程序员创建或者由特定工具自动生成代理类源代码,再对其进行编译;在程序运行前,代理类的.class文件就已经存在了
public class TuHao {
private double length;
public TuHao(double length) {
this.length = length;
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public void dating(Girl girl) {
girl.dating(length);
}
}
public interface Girl {
/** 约会 */
boolean dating(double length);
}
public class TeacherCang implements Girl {
@Override
public boolean dating(double length) {
if (length >= 1.7d) {
System.out.println("身高可以,约一下!");
return true;
}
System.out.println("身高不行,哥哥我们不约!");
return false;
}
}
public class Tony implements Girl {
private Girl girl;
public Girl getGirl() {
return girl;
}
public void setGirl(Girl girl) {
this.girl = girl;
}
@Override
public boolean dating(double length) {
doSomethingBefore();
boolean result = this.girl.dating(length);
doSomethingAfter();
return result;
}
/** 前置增强 */
private void doSomethingBefore() {
System.out.println("老板,这个我试过了,很不错,推荐给你!");
}
/** 后置增强 */
private void doSomethingAfter() {
System.out.println("老板,你觉得怎样,欢迎下次再约!");
}
}
public class Client {
public static void main(String[] args) {
TuHao tuHao = new TuHao(1.8d);
Girl girl = new TeacherCang();
Tony tony = new Tony();
tony.setGirl(girl);
tuHao.dating(tony);
}
}
静态代理的缺点:
扩展能力差
可维护性差
代理类在程序运行时,运用反射机制动态创建而成
静态代理事先知道要代理的是什么,而动态代理不知道要代理什么东西,只有在运行时才知道
优点:
在运行时,动态为不同类的对象创建代理,增强功能,灵活扩展,易维护
两种实现方式:
public class TonyCompany {
public static Object proxy(Object target) {
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new MyInvationHandler(target));
}
/** 功能增加的实现 */
private static class MyInvationHandler implements InvocationHandler {
private Object target;
public MyInvationHandler(Object target) {
super();
this.target = target;
}
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
doSomethingBefore();
/** 调用被代理对象的方法 */
Object result = method.invoke(target, args);
doSomethingAfter();
return result;
}
/** 前置增强 */
private void doSomethingBefore() {
System.out.println("老板,这个我试过了,很不错,推荐给你!");
}
/** 后置增强 */
private void doSomethingAfter() {
System.out.println("老板,你觉得怎样,欢迎下次再约!");
}
}
}
public class Client {
public static void main(String[] args) {
TuHao th = new TuHao(1.8F);
Girl tc = new TeacherCang();
Girl girl = (Girl) TonyCompany.proxy(tc);
th.dating(girl);
}
}
下面可以通过一个工具类来看动态代理后所生成的.class文件:
public class ProxyUtils {
/*
* 将根据类信息 动态生成的二进制字节码保存到硬盘中, 默认的是clazz目录下 params :clazz 需要生成动态代理类的类
* proxyName : 为动态生成的代理类的名称
*/
public static void generateClassFile(Class<?> clazz, String proxyName) {
// 根据类信息和提供的代理类名称,生成字节码
byte[] classFile = ProxyGenerator.generateProxyClass(proxyName,
new Class[] { clazz });
ProxyUtils.writeToFile(clazz, classFile, proxyName);
}
public static void writeToFile(Class<?> clazz, byte[] classFile,
String proxyName) {
String paths = clazz.getResource(".").getPath();
System.out.println(paths);
FileOutputStream out = null;
try {
// 保留到硬盘中
out = new FileOutputStream(paths + proxyName + ".class");
out.write(classFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public interface Boy {
/** 约会 */
boolean dating(char cup);
/** 拍照 */
void show();
}
public class TeacherChen implements Boy {
@Override
public boolean dating(char cup) {
if (cup == 'E') {
System.out.println("这个妹子不错可以约!");
return true;
}
System.out.println("这个妹子不行,妹子我们不约!");
return false;
}
@Override
public void show() {
System.out.println("开始进入拍照模式。。。");
}
}
public class Client {
public static void main(String[] args) {
Boy boy = new TeacherChen();
Boy boy1 = (Boy) TonyCompany.proxy(boy);
boy1.dating('E');
boy1.show();
ProxyUtils.generateClassFile(Boy.class, boy1.getClass().getName());
}
}
可以看到在项目中生成的文件:
点开上面所标识的文件即是动态生成的.class文件:
public final class $Proxy0 extends Proxy implements Boy {
private static Method m1;
private static Method m4;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void show() throws {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final boolean dating(char var1) throws {
try {
return (Boolean)super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m4 = Class.forName("com.example.demo.syms.proxy.p2.Boy").getMethod("show");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.example.demo.syms.proxy.p2.Boy").getMethod("dating", Character.TYPE);
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
cglib是一个高层次的java字节码生成和转换的api库
主要用途:
在运行期为类、接口生成动态代理对象
以达到不改动原代码而实现功能增强的目的
常在哪里使用它:
AOP、test、orm框架中用来生成动态代理对象、拦截属性访问
代码示例:
public class CglibDemo {
static class MyMethodInterceptor implements MethodInterceptor {
private Object target;
public MyMethodInterceptor(Object target) {
this.target = target;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("*********" + method.getName());
//前置增强
doSomethingBefore();
//返回值
Object result = null;
//调用父类的该方法,当是生成接口的代理时不可调用。
//result = methodProxy.invokeSuper(o, objects);
if (target != null) {
//通过method来调用被代理对象的方法
result = method.invoke(target, objects);
}
//后置增强
doSomethingAfter();
return result;
}
private void doSomethingBefore() {
System.out.println("老板你好,这个我试过了,很不错,推荐给你!");
}
private void doSomethingAfter() {
System.out.println("老板你觉得怎样? 欢迎下次.....");
}
}
public static void main(String[] args) {
//cglib的增强器,即代理人
Enhancer e = new Enhancer();
//被代理的对象
TeacherCang c = new TeacherCang();
//设置代理增加动作-回调
e.setCallback(new MyMethodInterceptor(c));
/** 接口代理 */
//获得接口代理对象
e.setInterfaces(new Class[]{Girl.class});
Girl g = (Girl) e.create();
g.dating(1.8D);
System.out.println("------------------------------------------");
/** 类代理 */
//对类生成代理对象
e.setSuperclass(TeacherCang.class);
e.setInterfaces(null);
TeacherCang tc = (TeacherCang) e.create();
tc.dating(1.8D);
//当有多个callback时,需要通过callbackFilter来指定被代理方法使用第几个callback
//e.setCallbacks(new Callback[] {new MyMethodInterceptor(tc), new YouMethodInterceptor(tc)});
/*e.setCallbackFilter(new CallbackFilter() {
@Override
public int accept(Method method) {
// 返回多个callback中的第几个,索引值
if("dating".equals(method.getName())) {
return 1;
}
return 0;
}
});
*/
}
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章