代理模式

一、概述

  代理是一种模式,提供了对目标对象的间接访问方式,即通过代理访问目标对象。如此便于在目标实现的基础上增加额外的功能操作,前拦截,后拦截等,以满足自身的业务需求,同时代理模式便于扩展目标对象功能的特点也为多人所用。

二、图形描述

三、代码实现

静态代理,由于比较简单,所有把代码都合到一起了: 

// 需要被代理的接口
public interface BussinessInterface {
void execute();
} // 基础实现类
public class Bussiness implements BussinessInterface { @Override
public void execute() {
System.out.println("柯贤铭在做生意~~~");
}
} // 在基础实现类的基础之上,封装一层方法
public class BussinessProxy implements BussinessInterface { private BussinessInterface bussinessImpl; public BussinessProxy(BussinessInterface bussinessImpl) {
this.bussinessImpl = bussinessImpl;
} @Override
public void execute() {
System.out.println("前拦截...");
bussinessImpl.execute();
System.out.println("后拦截...");
}
} // 测试类,真正使用的时候,我们采用增强之后的实现类
public class TestAgent { public static void main(String[] args) {
BussinessInterface bussinessInterface = new Bussiness();
BussinessInterface newBuss = new BussinessProxy(bussinessInterface);
newBuss.execute();
}
}

效果截图:

静态总结:

优点:可以做到不对目标对象进行修改的前提下,对目标对象进行功能的扩展和拦截。

缺点:因为代理对象,需要实现与目标对象一样的接口,会导致代理类十分繁多,不易维护,同时一旦接口增加方法,则目标对象和代理类都需要维护。

动态代理模式,由于代码量较少,我也融合到一起:

// 定义接口
public interface UserService {
void saveUser();
} // 定义接口实现类及方法
public class UserServiceImpl implements UserService {
@Override
public void saveUser() {
System.out.println("调用 saveUser() 方法");
}
} // 定义代理工具类
public class MyProxyUtil {
public static UserService getProxyByJDK(UserService service) {
// 参数:目标对象的类加载器,目标对象的接口,代理对象的执行处理器
UserService userService = (UserService) Proxy.newProxyInstance(service.getClass().getClassLoader(),
service.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("记录日志-开始");
Object obj = method.invoke(service, args);
System.out.println("记录日志-结束");
return obj;
}
});
return userService;
}
} // 测试类
public class Test { public static void main(String[] args) {
// 创建目标对象
UserService userService = new UserServiceImpl();
// 生成代理对象
UserService proxy = MyProxyUtil.getProxyByJDK(userService);
// 调用目标对象方法
userService.saveUser();
System.out.println("===================================");
// 调用代理对象方法
proxy.saveUser();
}
}

测试截图:

动态代理的总结

优点:代理对象无需实现接口,免去了编写很多代理类的烦恼,同时接口增加方法也无需再维护目标对象和代理对象,只需在事件处理器中添加对方法的判断即可。

缺点:代理对象不需要实现接口,但是目标对象一定要实现接口,否则无法使用JDK动态代理。

CGLib 动态代理

CGLib 动态代理相对于 JDK 动态代理局限性就小了很多,目标对象不需要实现接口,底层是通过继承目标对象产生代理子对象

代码,只是工具类方法多了一个:

public static UserService getProxyByCglib(UserService service) {
// 创建增强器
Enhancer enhancer = new Enhancer();
// 设置需要增强的类的对象
enhancer.setSuperclass(UserServiceImpl.class);
// 设置回调方法
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
long begin = System.currentTimeMillis();
System.out.println("记录程序开始");
Object object = methodProxy.invokeSuper(o, args);
long end = System.currentTimeMillis();
System.out.println("记录程序结束");
return object;
}
});
UserService userService = (UserService) enhancer.create();
return userService;
}

测试代码:

public class TestCglib {
public static void main(String[] args) {
// 创建目标对象
UserService userService = new UserServiceImpl();
// 生成代理对象
UserService proxy = MyProxyUtil.getProxyByCglib(userService);
// 调用目标对象方法
userService.saveUser();
System.out.println("===================================");
// 调用代理对象方法
proxy.saveUser();
}
}

测试结果:

总结:

Cglib代理: 针对类来实现代理,对指定目标 产生一个子类 通过方法拦截技术拦截所有父类方法的调用。 我们要使用cglib代理必须引入 cglib的jar包

三种代理模式进行总的分析概括:

代理模式:代理类和被代理类实现共同的接口(或继承),代理类中存有指向被代理类的索引,实际执行时通过调用代理类的方法、实际执行的是被代理类的方法。

而AOP,是通过动态代理实现的。

一、简单来说:

  JDK动态代理只能对实现了接口的类生成代理,而不能针对类

  CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承)

二、Spring在选择用JDK还是CGLiB的依据:

(1)当Bean实现接口时,Spring就会用JDK的动态代理

(2)当Bean没有实现接口时,Spring使用CGlib是实现

(3)可以强制使用CGlib(在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)

三、CGlib比JDK快?

  (1)使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。

  (2)在对JDK动态代理与CGlib动态代理的代码实验中看,1W次执行下,JDK7及8的动态代理性能比CGlib要好20%左右。

静态代理,动态代理和CGLIB代理模式的更多相关文章

  1. 静态代理、动态代理和cglib代理

    转:https://www.cnblogs.com/cenyu/p/6289209.html 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处 ...

  2. 设计模式---JDK动态代理和CGLIB代理

    Cglig代理设计模式 /*测试类*/ package cglibProxy; import org.junit.Test; public class TestCglib { @Test public ...

  3. SpringAOP-JDK 动态代理和 CGLIB 代理

    在 Spring 中 AOP 代理使用 JDK 动态代理和 CGLIB 代理来实现,默认如果目标对象是接口,则使用 JDK 动态代理,否则使用 CGLIB 来生成代理类. 1.JDK 动态代理 那么接 ...

  4. Spring中AOP的两种代理方式(Java动态代理和CGLIB代理)

    第一种代理即Java的动态代理方式上一篇已经分析,在这里不再介绍,现在我们先来了解下GCLIB代理是什么?它又是怎样实现的?和Java动态代理有什么区别? cglib(Code Generation ...

  5. JDK动态代理和 CGLIB 代理

    JDK动态代理和 CGLIB 代理 JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期期间创建一个接口的实现类来完成对目标对象的代理. 代码示例 接口 public interface ...

  6. Java动态代理和CGLib代理

    本文参考 在上一篇"Netty + Spring + ZooKeeper搭建轻量级RPC框架"文章中涉及到了Java动态代理和CGLib代理,在这篇文章中对这两种代理方式做详解 下 ...

  7. Java三种代理模式:静态代理、动态代理和cglib代理

    一.代理模式介绍 代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能. 简言之,代理模式就是 ...

  8. 总结两种动态代理jdk代理和cglib代理

    动态代理 上篇文章讲了什么是代理模式,为什么用代理模式,从静态代理过渡到动态代理. 这里再简单总结一下 什么是代理模式,给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问,即客户不直接操控原 ...

  9. spring的AOP动态代理--JDK代理和CGLIB代理区分以及注意事项

    大家都知道AOP使用了代理模式,本文主要介绍两个代理模式怎么设置以及区别,对原文一些内容进行了引用后加入了自己的理解和更深入的阐述:   一.JDK代理和CGLIB代理的底层实现区别* JDK代理只能 ...

  10. JDK动态代理和CGLIB代理的区别

    一.原理区别: java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理. 而cglib动态代理是利用asm开源包,对代理对象类的class文件 ...

随机推荐

  1. Android开发学习笔记Intent 一

    Inten的概念 1.Intent是Android四大组件直接沟通的桥梁 2.Intent是一种运行时绑定(runtime binding)机制 Intent对象的属性 Itent的种类 Inten过 ...

  2. 恕我直言你可能真的不会java第2篇:Java Stream API?

    一.什么是Java Stream API? Java Stream函数式编程接口最初是在Java 8中引入的,并且与lambda一起成为Java开发的里程碑式的功能特性,它极大的方便了开放人员处理集合 ...

  3. 深入理解Java虚拟机学习笔记(一)-----Java内存区域

    一 概述 对于 Java 程序员来说,在虚拟机自动内存管理机制下,不再需要像C/C++程序开发程序员这样为内一个 new 操作去写对应的 delete/free 操作,不容易出现内存泄漏和内存溢出问题 ...

  4. Spring整合JDBC temple

    一.Spring对Jdbc的支持 Spring为了提供对Jdbc的支持,在Jdbc API的基础上封装了一套实现,以此建立一个 JDBC 存取框架. 作为 Spring JDBC 框架的核心, JDB ...

  5. Linux 进程间通信(IPC)总结

    概述 一个大型的应用系统,往往需要众多进程协作,进程(Linux进程概念见附1)间通信的重要性显而易见.本系列文章阐述了 Linux 环境下的几种主要进程间通信手段. 进程隔离 进程隔离是为保护操作系 ...

  6. django 中间键 csrf 跨站请求伪造

    django中间件和auth模块   Django中间件 由django的生命周期图我们可以看出,django的中间件就类似于django的保安,请求一个相应时要先通过中间件才能到达django后端( ...

  7. Spring Boot2+Resilience4j实现容错之Bulkhead

    Resilience4j是一个轻量级.易于使用的容错库,其灵感来自Netflix Hystrix,但专为Java 8和函数式编程设计.轻量级,因为库只使用Vavr,它没有任何其他外部库依赖项.相比之下 ...

  8. CCNA-Part3 - 数据链路层的趣事 - 走进交换机

    在这篇文章中,会先介绍局域网及其的组件,通过交换机延伸到 TCP/IP 中数据链路层,了解数据的传输介质,以及交换机的发展历程及原理. 最后介绍数据帧的格式. 在阅读后应该了解如下的内容: 什么是局域 ...

  9. 前端笔记(关于webpack打包时内存溢出问题的解决)

    首先安装increase-memory-limit cnpm install -g increase-memory-limit 重启cmd,并在项目跟目录中运行一下 increase-memory-l ...

  10. JS中字符串和数组的相互转化

    题目:利用var s1=prompt("请输入任意的字符串:") ,可以获取用户输入的字符串,试编程将用户输入的字符串“反转”,并且将字符串输出. 思路:字符串对象的方法中并没有实 ...