按照代理的创建时期,代理类可以分为两种。

静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。

动态代理:在程序运行时,运用反射机制动态创建而成。

动态代理三种方式

动态代理实现有三种方式,jdk动态代理(基于接口),cglib动态代理(基于继承),javassist(hibernate中使用这种方式)实现动态代理。

JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢?

这就需要CGLib了。

cglib如何实现代理

Cglib是一个优秀的动态代理框架,它的底层使用ASM在内存中动态的生成被代理类的子类,使用CGLIB即使代理类没有实现任何接口也可以实现动态代理功能。

CGLib原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。

CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。

cgLib动态代理实例

下面演示一个动态代理的实例。

导入maven 依赖

cglib 是基于asm 字节修改技术。导入 cglib 会间接导入 asm, ant, ant-launcher 三个jar 包。

<!-- cglib 动态代理依赖 begin -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.5</version></dependency>
<!-- cglib 动态代理依赖 stop -->

CGLIB的核心类:

  • net.sf.cglib.proxy.Enhancer – 主要的增强类
  • net.sf.cglib.proxy.MethodInterceptor – 主要的方法拦截类,它是Callback接口的子接口,需要用户实现
  • net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用,如使用:
  • Object o = methodProxy.invokeSuper(proxy, args);//虽然第一个参数是被代理对象,也不会出现死循环的问题。

实现一个业务类,注意,这个业务类并没有实现任何接口:

public class HelloService {

    public HelloService() {
System.out.println("HelloService构造");
} public void sayHello() {
System.out.println("HelloService:sayHello");
}

net.sf.cglib.proxy.MethodInterceptor接口是最通用的回调(callback)类型,它经常被基于代理的AOP用来实现拦截(intercept)方法的调用。这个接口只定义了一个方法

public Object intercept(Object object, java.lang.reflect.Method method,

Object[] args, MethodProxy proxy) throws Throwable;

方法拦截器 实现 MethodInterceptor 接口:

public class HelloServiceInterceptor implements MethodInterceptor{

    /**
* sub:cglib生成的代理对象
* method:被代理对象方法
* objects:方法入参
* methodProxy: 代理方法
*/
@Override
public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("======插入前置通知======");
Object object = methodProxy.invokeSuper(sub, objects);
System.out.println("======插入后置通知======");
return object;
}

测试类,生成CGLIB代理对象调用目标方法:

public class CglibTest {
public static void main(String[] args) {
// 通过CGLIB动态代理获取代理对象的过程
Enhancer enhancer = new Enhancer();
// 设置enhancer对象的父类
enhancer.setSuperclass(HelloService.class);
// 设置enhancer的回调对象
enhancer.setCallback(new HelloServiceInterceptor());
// 创建代理对象
HelloService proxy= (HelloService)enhancer.create();
// 通过代理对象调用目标方法
proxy.sayHello();
}
}

Cglib 总结

  • CGlib可以传入接口也可以传入普通的类,接口使用实现的方式,普通类使用会使用继承的方式生成代理类.
  • 由于是继承方式,如果是 static方法,private方法,final方法等描述的方法是不能被代理的
  • 做了方法访问优化,使用建立方法索引的方式避免了传统JDK动态代理需要通过Method方法反射调用.
  • 提供callback 和filter设计,可以灵活地给不同的方法绑定不同的callback。编码更方便灵活。
  • CGLIB会默认代理Object中equals,toString,hashCode,clone等方法。比JDK代理多了clone。

性能优于JDK代理,CGLib如何实现动态代理的更多相关文章

  1. 死磕Spring之AOP篇 - 初识JDK、CGLIB两种动态代理

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...

  2. 基于 CGLIB 库的动态代理机制

    之前的文章我们详细的介绍了 JDK 自身的 API 所提供的一种动态代理的实现,它的实现相对而言是简单的,但是却有一个非常致命性的缺陷,就是只能为接口中的方法完成代理,而委托类自己的方法或者父类中的方 ...

  3. 代理模式 & Java原生动态代理技术 & CGLib动态代理技术

    第一部分.代理模式  代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常 ...

  4. Cglib方法实现动态代理

    除了使用JDK方式产生动态代理外,Java还给我们提供了另外一种产生动态代理的方法,那就是使用cglib. cglib是这样实现动态代理的: · ①.针对类来实现代理 · ②对指定目标类产生一个子类 ...

  5. java提供类与cglib包实现动态代理

    终于有点空余时间,决定把之前学习的知识点整理一下,备以后复习. 动态代理有三角色:抽象角色,代理角色,真是角色. 第一个记录下java提供的动态代理.即使用Proxy类和InvocationHande ...

  6. CGLIB和Java动态代理的区别(笔记)

    java常用知识点: 1.Java动态代理只能够对接口进行代理,不能对普通的类进行代理(因为所有生成的代理类的父类为Proxy,Java类继承机制不允许多重继承):CGLIB能够代理普通类:2.Jav ...

  7. java--动态代理设计模式,CGLIB实现的动态代理设计模式

    代理设计模式 代理设计模式的基本形式 代理设计模式的核心思路,一个接口两个子类,一个子类完成核心业务操作,另一个完成与核心业务有关的辅助性操作.例如,编写一个简单的设计模式. package com. ...

  8. JDK动态代理(3)--------动态代理具体实现

    写个HelloWorld 接口 package com.spring.aop.proxy; public interface HelloWorld { public void sayHello(); ...

  9. java 代理模式二:动态代理

    java动态代理: java动态代理类位于java.lang.reflect包下,一般主要涉及两个类: 1.Interface InvocationHandler 该接口中仅定义了一个方法:Objec ...

随机推荐

  1. Django学习小记1-安装配置

    Django是一个开放源代码的Web应用框架,由Python写成. python 中的web框架有许多例如:Django.Tornado.Flask..而Django相较与其他WEB框架其优势为:大而 ...

  2. 轻松搭建基于 SpringBoot + Vue 的 Web 商城应用

    背景介绍 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传.函数 ...

  3. 从零开始のcocos2dx生活(七)ParticleSystem

    CCParticleSystem是用来设置粒子效果的类 1.粒子分为两种模式:重力模式 和 半径模式 重力模式独占属性: gravity 重力方向,Vec2类型,可以分别指定不同方向的重力大小 spe ...

  4. idea编辑器的使用

    编辑器下载和安装就不说了,网上每次版本都更换得好快 ,发新版的人很多idea2019:https://pan.baidu.com/s/1zc1wkQLLVxbXSjy4ISN4aQ 提取码:cgah, ...

  5. drop-out栈

    1.drop-out栈能够用来做什么? 在许多提供编辑功能的软件,如word.ps.画图,都会提供“撤销”和“恢复”功能,使用drop-out能够实现这些功能. 2.drop-out栈特性 drop- ...

  6. 【Python3爬虫】突破反爬之应对前端反调试手段

    一.前言 在我们爬取某些网站的时候,会想要打开 DevTools 查看元素或者抓包分析,但按下 F12 的时候,却出现了下面这一幕:   此时网页暂停加载,自动跳转到 Source 页面并打开了一个 ...

  7. Win10删除桌面上的回收站、计算机、网络等图标

    解决方案: 桌面上鼠标右键,选择个性化 个性化窗口左边侧栏选择主题 移动至最下方点击"桌面图标设置"即可看到系统中的五个桌面图标

  8. 使用Eureka中遇到的一些问题

    1.情况 :   服务已经注册到eureka,eureka中可以看到,但是 consumer和provider这两个服务,一直报错, 错误信息:DiscoveryClient_CONSUMER-DEM ...

  9. 带有外部Tomcat的Spring Boot

    在本文中,我将如何在外部Tomcat上运行Spring Boot应用程序.对我来说,这是一个现实的场景,我必须解决这个问题,因此也请教了一下优锐课老师,得到了很多帮助.也希望当你遇到类似问题时,能为你 ...

  10. ArcEngine连接Oracle数据库

    问题1: 最近写服务需要用ArcEngine连接Oracle数据库,以前连接数据库都会弹出一个窗体.然后填好之后就可以连接了,这样很麻烦. 代码如下: private bool ConnectToSd ...