最近学习到设计模式,现总结个人学习代理模式内容【更加关注过程,对被代理对象完全控制】。
上一篇:Java设计模式-委派模式
文章目录
- 定义
- 优缺点
-
- 优点
- 缺点
- 实现
-
- CGLIB代理
-
- 代码
- 测试
- JDK代理
-
- 代码
- 测试
- 对比
定义
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用
优缺点
优点
- (1).职责清晰,不用关心其他非本职责的事务。
- (2).代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介的作用和保护了目标对象的作用。
- (3).高扩展性 [1]
缺点
- 需要重新创建不可见对象。达到重写的目的。
- 使用到了反射,降低了性能。
实现
CGLIB代理
代码
代理对象需要实现MethodInterceptor,属于cglib.jar包。
cglib内部创建一个对象,继承我们的对象[LoginWorkflow ],在创建的对象上重写了父类的方法,但是还是会使用父类的逻辑,而代理代码,则在业务逻辑前后添加其他业务逻辑。
/**
* 登录流程
* @author cc百川
*/
public class LoginWorkflow {
public String doSubmit(){
System.out.println("正在登录");
return "登录成功";
}
}
public class ProxyLog implements MethodInterceptor{
public Object install(Class clazz) throws Exception{
Enhancer enhancer = new Enhancer();
//告诉cglib,生成的子类需要继承哪个父类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);//设置回调,告诉继续执行业务代码的类
//生成源代码,编译成class文件,加载到JVM中,并返回被代理对象
return enhancer.create();//创建被代理对象
}
@Override
public Object intercept(Object obj, Method arg1, Object[] arg2,
MethodProxy proxy) throws Throwable {
System.out.println("代理登录前处理业务逻辑,判断是否规定时间登录");
//该obj的引用是由CGLib给我们new出来的,这个是被代理对象的子类,子类引用强转父类,这时就可以操作父类的属性
String res = (String) proxy.invokeSuper(obj, arg2);
System.out.println("代理登录后处理日志相关等");
return res+",代理添加了日志";
}
}
测试
JDK代理
代码
jdk代理核心实现InvocationHandler。
jdk代理需要借助接口,也就是被代理者实现一个接口【这里是Workflow】。
jdk实现代理过程
- 1.拿到被代理对象的引用,然后获取它的接口
- 2.JDK代理重新生成一个类,同时实现我们给的代理对象所实现的接口
- 3.把被代理对象的引用也拿到了
- 4.重新动态生成一个class字节码
- 5.然后编译
/**
* 流程提交
* @author cc百川
*/
public interface Workflow {
String doSubmit();
}
/**
* 登录流程
* @author cc百川
*/
public class LoginWorkflow implements Workflow{
public String doSubmit(){
System.out.println("正在登录");
return "登录成功";
}
}
/**
* 代理登录 jdk代理核心实现InvocationHandler
* @author cc百川
*/
public class ProxyLog implements InvocationHandler{
//用于保留被代理对象的引用
private Workflow wf;
//获取被代理的对象【资料】
public Object install(Workflow wf) {
this.wf = wf;
Class cs = wf.getClass();
return Proxy.newProxyInstance(cs.getClassLoader(), cs.getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("代理登录前处理业务逻辑,判断是否规定时间登录");
String res = (String) method.invoke(this.wf, args);//执行原业务逻辑
System.out.println("代理登录后处理日志相关等");
return res+",代理添加了日志";
}
}
测试
通过代理的方式,可以在执行业务代码前后添加逻辑
对比
JDK的动态代理是通过接口来进行强制转换的,生成以后的代理对象,可以强制转换为接口。
CGLib的动态代理是通过生成一个被代理对象的子类,然后重写父类的方法。子类引用强转给父类【被代理类】,从而调用对象方法。
日常对代理模式,常见有AOP,以及产品二开等,达到无侵入修改【后期举例】。
以上仅为个人学习,如果错误望指出,谢谢。