Spring的AOP其就是通过动态代理的机制实现的,所以理解动态代理尤其重要。

动态代理比静态代理的好处:

1.一个动态代理类可以实现多个业务接口。静态代理的一个代理类只能对一个业务接口的实现类进行包装,如果有多个业务接口的话就要定义很多实现类和代理类才行。

2.提供统一的方法前后处理。如果代理类对业务方法的预处理、调用后操作都是一样的(比如:调用前输出提示、调用后自动关闭连接),则多个静态代理类就会有很多重复代码。这时我们可以定义这样一个代理类,它能代理所有实现类的方法调用:根据传进来的业务实现类和方法名进行具体调用。——那就是动态代理。

一.JDK动态代理(针对接口)

一个类(BookManage)实现了一个接口(IBookManage),这个类就是我们需要代理的真实对象。

proxy = Proxy.newProxyInstance()创建动态代理对象,然后proxy.真实对象的方法。这时就会进入动态代理对象的invoke()方法里。

动态代理类:实现InvocationHandler接口,并实现里面的invoke()方法。invoke()方法里传入的是真实对象(BookManage),通过代理对象来调用方法时,是委托由其关联到的 handler 对象的invoke方法中来调用,并不是自己来真实调用,而是通过代理的方式来调用的。

代码实现:

1.1 接口类

package jdkproxy;

/**
* @author admin
*接口类
*/
public interface IBookManage {
//添加图书
public void addBook();
}

1.2 接口实现类

package jdkproxy;

/**
* @author admin
*接口实现类,真实对象
*/
public class BookManage implements IBookManage { @Override
public void addBook() {
System.out.println("addBook...");
} }

1.3 动态代理类

package jdkproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author 梦里南柯
* 动态代理类
*/
public class DynamicProxy implements InvocationHandler {
private Object target;// 这其实业务实现类对象,用来调用具体的业务方法
/**
* 绑定业务对象并返回一个代理类
*
* @param target
* @return
*/
public Object bind(Object target) {
this.target = target; // 接收业务实现类对象参数
/*
* 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数 第一个参数
* handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
* 第二个参数realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,
* 表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了 第三个参数handler, 我们这里将这个代理对象关联到了上方的
* InvocationHandler 这个对象上
*/
IBookManage proxy = (IBookManage) Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
return proxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在代理真实对象前我们可以添加一些自己的操作
System.out.println("before add book...");
System.out.println("开始调用真实对象的方法: :" + method);
// 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
Object result = method.invoke(target, args);
// 在代理真实对象后我们也可以添加一些自己的操作
System.out.println("after add book...");
return result;
}
}

代理对象最重要的方法:invoke()。

作用:当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用

Object invoke(Object proxy, Method method, Object[] args) throws Throwable

proxy:  指代我们所代理的那个真实对象
method:  指代的是我们所要调用真实对象的某个方法的Method对象
args:  指代的是调用真实对象某个方法时接受的参数
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

loader:  一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载

interfaces:  一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了

h:  一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

1.4 测试

package jdkproxy;

public class Client
{
public static void main(String[] args) {
BookManage bookManage = new BookManage();
DynamicProxy proxy = new DynamicProxy();
IBookManage iBookManage = (IBookManage) proxy.bind(bookManage);
System.out.println("代理对象的类名: " + iBookManage.getClass().getName());
iBookManage.addBook();
}
}

运行结果:

代理对象的类名: com.sun.proxy.$Proxy0
before add book...
开始调用真实对象的方法: :public abstract void jdkproxy.IBookManage.addBook()
addBook...
after add book...

其中com.sun.proxy.$Proxy0,就是我们代理对象的名字,它是jvm运行时动态生成的一个对象。

那为什么Proxy.newProxyInstance()方法可以转型为IBookManage?因为这个方法里面的第二个参数给代理对象提供的是我们真实对象所实现的接口,所以代理对象实现了这组接口,当然可以转化为IBookManage类型了。然后就是代理对象(IBookManage).方法(addBook)调用。

通过代理对象调用方法的时候,其实就是委托由其关联到的 handler 对象的invoke方法中来调用,并不是自己来真实调用,而是通过代理的方式来调用的。

弊端:

1. 如果业务实现类是没有实现接口而是直接定义业务方法的话,就无法使用JDK动态代理了。

2. 如果业务实现类中新增了接口中没有的方法,这些方法是无法被代理的(因为无法被调用)。

二.CGLIB动态代理(针对类)

2.1 创建一个类不需要实现任何接口

2.2 绑定一个业务类

  • 创建一个加强器:Enhancer enhancer = new Enhancer();//用来创建动态代理类
  • 指定加强器要代理的业务类(父类)
  • 设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦截 enhancer.setCallback(this);
  • return enhancer.create(); // 创建动态代理类对象并返回
// 实现回调方法
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("预处理——————");
proxy.invokeSuper(obj, args); //调用业务类(父类中)的方法
System.out.println("调用后操作——————");
return null;
}

2.3 测试:创建业务类和代理类对象,然后通过  代理类对象.getInstance(业务类对象)  返回一个动态代理类对象(它是业务类的子类,可以用业务类引用指向它)。最后通过动态代理类对象进行方法调用。

三.比较

静态代理是通过在代码中显式定义一个业务实现类一个代理,在代理类中对同名的业务方法进行包装,用户通过代理类调用被包装过的业务方法;

JDK动态代理是通过接口中的方法名,在动态生成的代理类中调用业务实现类的同名方法;

CGlib动态代理是通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行代理;不能对 final类进行继承

源码级分析见:

https://blog.csdn.net/john_lw/article/details/79539070

http://ifeve.com/jdk动态代理代理与cglib代理原理探究/

https://www.jianshu.com/p/9a61af393e41?from=timeline&isappinstalled=0

JDK动态代理、CGLIB动态代理详解的更多相关文章

  1. Atitit 代理CGLIB 动态代理 AspectJ静态代理区别

    Atitit 代理CGLIB 动态代理 AspectJ静态代理区别 1.1. AOP 代理主要分为静态代理和动态代理两大类,静态代理以 AspectJ 为代表:而动态代理则以 spring AOP 为 ...

  2. 【Java入门提高篇】Day12 Java代理——Cglib动态代理

    今天来介绍另一种更为强大的代理——Cglib动态代理. 什么是Cglib动态代理? 我们先回顾一下上一篇的jdk动态代理,jdk动态代理是通过接口来在运行时动态创建委托类的代理对象,但是跟静态代理一样 ...

  3. ssh转发代理:ssh-agent用法详解

    SSH系列文章: SSH基础:SSH和SSH服务 SSH转发代理:ssh-agent用法详解 SSH隧道:端口转发功能详解 使用ssh-agent之前 使用ssh公钥认证的方式可以免去ssh客户端(如 ...

  4. 数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解

    数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解 对数组有不了解的可以先看看我的另一篇文章,那篇文章对数组有很多详细的解析,而本篇文章则着重讲动态数组,另一篇文章链接 ...

  5. 【原创】JDK 9-17新功能30分钟详解-语法篇-var

    JDK 9-17新功能30分钟详解-语法篇-var 介绍 JDK 10 JDK 10新增了新的关键字--var,官方文档说作用是: Enhance the Java Language to exten ...

  6. Java的三种代理模式:静态代理/JDK动态代理/Cglib动态代理

    1.静态代理:需要定义接口或者父类,目标对象与代理对象均实现同一接口或继承同一父类. 2.JDK动态代理:需要目标对象实现一个接口,通过动态反射的机制,生成代理对象,实现同一个接口 3.Cglib动态 ...

  7. java 静态代理 JDK动态代理 Cglib动态代理

    下面以一个简单的银行账户为例讲述讲述动态代理. 设计一个银行账户类,包含用户的账户余额,实现查询和更新余额功能 这个系统用了一段时间,有客户要求对账说账户余额给弄错了?因为上面没有存取款记录,最后银行 ...

  8. 《Java基础知识》动态代理(InvocationHandler)详解

    1. 什么是动态代理 对象的执行方法,交给代理来负责.比如user.get() 方法,是User对象亲自去执行.而使用代理则是由proxy去执行get方法. 举例:投资商找明星拍广告,投资商是通过经纪 ...

  9. Nginx 反向代理与负载均衡详解

    序言 Nginx的代理功能与负载均衡功能是最常被用到的,关于nginx的基本语法常识与配置已在Nginx 配置详解中有说明,这篇就开门见山,先描述一些关于代理功能的配置,再说明负载均衡详细. Ngin ...

  10. c# 把一个匿名对象赋值给一个Object类型的变量后,怎么取这个变量? c# dynamic动态类型和匿名类 详解C# 匿名对象(匿名类型)、var、动态类型 dynamic 深入浅析C#中的var和dynamic

    比如有一个匿名对象,var  result =......Select( a=>new {  id=a.id, name=a.name});然后Object  obj =  result ;我怎 ...

随机推荐

  1. elementui按需加载

    定义一个ele.js文件 官网:https://element.eleme.io/#/zh-CN/component/quickstart // 方法1 import 'element-ui/lib/ ...

  2. MySQL的基本操作一

    本文主要涉及到的SQL知识点包括CREATE创建数据库和表.INSERT插入数据.SUM()求和.GROUP BY分组.DATE_FORMAT()格式化日期.ORDER BY排序.COUNT()统计行 ...

  3. 让框架内循环或者指定元素 指定CSS

    p:nth-child(3n+) { background:#ff0000; } http://www.w3school.com.cn/cssref/selector_nth-child.asp

  4. fastadmin 相同的查询条件在不同的控制器里where条件为什么会不一样

    第一个图片在id前面加了模型名是因为第一个控制器 //当前是否为关联查询 $this->relationSearch = true;

  5. Android 计算器制作 2.注册View 构建函数

    鄙人新手 整了 快两天 终于搞定了.. 1.首先是MainActivity 中 在Oncreate函数中 注册 2.按+ 或者 - 号 来分成两大字符串 s1 和 s2 再将s2 分为更小的s1 和 ...

  6. Vim技巧----光标移动

    w:向前移动,光标停留在下个单词词首,每次一个单词(单词中不含其他字符如:- \ = +等) W:向前移动,光标停留在下个单词词首,每次一个字符串(字符串可以含有其字符如:- \ = +等,is-a ...

  7. PTA ”写出这个数“

      读入一个正整数 n,计算其各位数字之和,用汉语拼音写出和的每一位数字. 输入格式: 每个测试输入包含 1 个测试用例,即给出自然数 n 的值.这里保证 n 小于 10的100次方. 输出格式: 在 ...

  8. js页面重定向跳转代码总结(待续)

    情形一:东八区,浏览器中文跳转 <script type="text/javascript"> var sLang = (navigator.language ? na ...

  9. 网络协议相关面试问题-http协议相关面试问题

    HTTP协议简介: 一些基本概念: 协议:指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则. HTTP协议:超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML ...

  10. metapath2vec 笔记

    Homogeneous networks: representative of singular type of nodes and relationships Challenges: multipl ...