代理模式
本文参考订阅公众号【Java中文社区】每日推送文章编写看完这篇文章,你会对静态代理,JDK动态代理和CGLIB动态代理模式有一个很清晰的认识文章目录简介静态代理动态代理模式JDK和CGLIB动态代理对比代理模式的优缺点简介什么是代理模式代理模式也称为委托模式,属于结构型模式之一。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介作用...
本文参考订阅公众号【Java中文社区】每日推送文章编写
看完这篇文章,你会对静态代理,JDK动态代理和CGLIB动态代理模式有一个很清晰的认识
简介
- 什么是代理模式
代理模式也称为委托模式,属于结构型模式之一。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介作用,比如我们生活中的邮局、快递公司、婚戒说等等。 - 代理模式分类
代理模式分为静态代理和动态代理。
静态代理是由程序员创建或者特定工具自动生成的源代码,再对其进行编译。在程序运行之前,代理类.class文件就已经被创建出来了。
动态代理实在程序员运行的时候通过java反射机制创建出来的。 - 代理模式的目的
主要有两个:一是保护目标对象,二是增强目标对象。
静态代理
静态代理模式的话我模拟一个古代结婚的场景。场景是这样的:在古代,某家的公子看上了别家的姑娘,一般都是家里的大人去姑娘的家里提亲,双方父母同意了,然后就拜堂成婚,后面要宴请亲朋好友。这里这个公子只需要拜堂成婚就行了,至于提亲和宴请亲友都是父母操办的。我们用代码来模拟一下这个场景。
首先我们来创建一个Person接口:
public interface Person {
void marry();
}
然后这家公子要成亲,我们建个 Son 类实现 Person 接口:
public class Son implements Person {
@Override
public void marry() {
System.out.println("我终于结婚了");
}
}
父亲帮儿子提亲,建个 Father 类:
public class FatherStaticProxy {
public static void main(String[] args) {
new FatherStaticProxy(new Son()).marry();
}
private Son son;
public FatherStaticProxy(Son son) {
this.son = son;
}
public void marry() {
before();
son.marry();
after();
}
private void after() {
System.out.println("父亲抱孙子");
}
private void before() {
System.out.println("父亲上门提亲");
}
}
代码写完了,大家有没有发现静态代理模式的一个缺点。那就是单一,一个类只能代理一个目标对象。比如上面的场景,父亲只能为自己的儿子提亲,不能为别人家的孩子提亲。
下面我们来看看动态代理是怎么解决这个问题的。
动态代理模式
动态代理模式分为 JDK 动态代理和 cglib 动态代理两种。这里先用 JDK 动态代理的方式来模拟一个通过婚介所找朋友的场景。
婚介所 JDKMatrimonialAgency 类:
public class JDKMatrimonialAgency implements InvocationHandler {
private Object target;
public Object getProxyInstance(Object target) {
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object invoke = method.invoke(target, args);
after();
return invoke;
}
private void after() {
System.out.println("婚姻介绍所介绍");
}
private void before() {
System.out.println("婚姻介绍所收取费用");
}
public static void main(String[] args) {
Person person = (Person) new JDKMatrimonialAgency().getProxyInstance(new Son());
person.marry();
}
}
然后我们用 CGLIB 来实现,如果不是spring(spring已经集成了 CGLIB )环境需要先引入 jar 包:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
然后加一个 CglibMatrimonialAgency 类:
public class CglibMatrimonialAgency implements MethodInterceptor {
public Object getProxyInstance(Class clazz) {
Enhancer enhancer = new Enhancer();
//要把哪个设置为即将生成的新类的父类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object o1 = methodProxy.invokeSuper(o, objects);
after();
return o1;
}
private void after() {
System.out.println("婚姻介绍所介绍");
}
private void before() {
System.out.println("婚姻介绍所收取费用");
}
public static void main(String[] args) {
Son son = (Son) new CglibMatrimonialAgency().getProxyInstance(new Son().getClass());
son.marry();
}
}
JDK和CGLIB动态代理对比
- JDK动态代理是实现了被代理对象的接口,CGLib是继承了被代理的对象。
- JDK和CGLib都是在运行期生成字节码,JDK是直接写Class字节码,CGLib使用ASM框架写Class字节码,CGLib代理实现更复杂,生成代理类比JDK效率低。
- JDK调用代理方法,是通过反射机制调用,CGLib是通过FastClass机制直接调用方法,CGLib执行效率更高。
代理模式的优缺点
优点:
降低耦合度,拓展性好。
代理对象将代理对象和目标对象分离,起到保护目标对象的作用。
可以对目标对象的功能增强。
缺点:
增加类的数量
因为会调用增强方法,所以会造成处理速度慢
增加了系统的复杂度(这是好的架构都会有的缺点,比如spring)
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)