AOP---jdk动态代理的思考
引出问题:动态代理中是谁调用了invoke方法
为了更好的说明情况,我先写一个动态代理类
a.Person类
- public interface Person {
- public void eating();
- }
b.PersonImpl类
- public class PersonImpl implements Person{
- public void eating() {
- System.out.println("我能吃!");
- }
- }
c.PersonProxy动态代理类
- public class PersonProxy implements InvocationHandler{
- //传入的对象
- private Object target;
- //真实对象与代理对象绑定
- public Object bind(Object target){
- this.target=target;
- //this指的是personProxy的一个实例
- Object proxy =Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);return proxy;
- }
- //invocationHandler的默认方法
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- System.out.println("调用代理前");
- Object object =method.invoke(target, args);
- System.out.println("调用代理后");
- return object;
- }
- }
d.test类
- public class test {
- public static void main(String[] args) {
- PersonProxy proxy=new PersonProxy();
- Person person=(Person)proxy.bind(new PersonImpl());
- person.eating();
- }
- }
e.运行结果
- 调用代理前
- 我能吃!
- 调用代理后
f.从以上代码和结果可以看出,我们并没有显示的调用invoke()方法,但是这个方法确实执行了。下面就整个的过程进行分析一下,
g.我们先想一下,为什么我们在test类中只调用了代理类的bind函数,返回的代理对象就可以调用我们在实现Person类中的eating()方法?并且不是直接调用eating()方法,还在eating()的方法上添加了一些功能(输出调用代理前,调用代理后),这不就是代理的概念吗?不由的让我想起一个介绍代理的例子,火车站相当于一个实体,如果你去火车站买票,那就没啥事,如果你要去火车售票代理点买票,这个时候你就得掏点手续费,火车代理点可以给你提供一些额外的功能。扯的哪去了,说正事,从运行结果上可以看出来,当我们调用person.eating()的时候实际上调用了代理类PersonProxy中的invoke方法,但是是谁调用的呢?可以bind()函数中的newProxyInstance这个方法作为突破口,我们先来看一下Proxy类中newProxyInstance方法的源代码:
- public static Object newProxyInstance(ClassLoader loader,
- Class<?>[] interfaces,
- InvocationHandler h)
- throws IllegalArgumentException
- {
- if (h == null) {
- throw new NullPointerException();
- }
- /*
- * Look up or generate the designated proxy class.
- */
- Class cl = getProxyClass(loader, interfaces);
- /*
- * Invoke its constructor with the designated invocation handler.
- */
- try {
- /*
- * private final static Class[] constructorParams = { InvocationHandler.class };
- * cons即是形参为InvocationHandler类型的构造方法
- */
- Constructor cons = cl.getConstructor(constructorParams);
- return (Object) cons.newInstance(new Object[] { h });
- } catch (NoSuchMethodException e) {
- throw new InternalError(e.toString());
- } catch (IllegalAccessException e) {
- throw new InternalError(e.toString());
- } catch (InstantiationException e) {
- throw new InternalError(e.toString());
- } catch (InvocationTargetException e) {
- throw new InternalError(e.toString());
- }
- }
从源码中我们可以看到:根据参数loader和interfaces调用方法 getProxyClass(loader, interfaces)创建代理类$Proxy0.$Proxy0类 实现了interfaces的接口,并继承了Proxy类。
h.既然newProxyInstance()返回的对象能调用eating()方法,那我们看看代理实例proxy的方法有那些?
- public class PersonProxy implements InvocationHandler{
- //传入的对象
- private Object target;
- //真实对象与代理对象绑定
- public Object bind(Object target){
- this.target=target;
- //this指的是personProxy的一个实例
- Object proxy =Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
//查看proxy中的方法- for (Method name : proxy.getClass().getMethods()) {
- System.out.println(name);
- }
- return proxy;
- }
- //invocationHandler的默认方法
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- System.out.println("调用代理前");
- Object object =method.invoke(target, args);
- System.out.println("调用代理后");
- return object;
- }
- }
运行结果:
- public final int $Proxy0.hashCode()
- public final boolean $Proxy0.equals(java.lang.Object)
- public final java.lang.String $Proxy0.toString()
- public final void $Proxy0.eating()
- public static boolean java.lang.reflect.Proxy.isProxyClass(java.lang.Class)
- public static java.lang.Object java.lang.reflect.Proxy.newProxyInstance(java.lang.ClassLoader,java.lang.Class[],java.lang.reflect.InvocationHandler) throws java.lang.IllegalArgumentException
- public static java.lang.reflect.InvocationHandler java.lang.reflect.Proxy.getInvocationHandler(java.lang.Object) throws java.lang.IllegalArgumentException
- public static java.lang.Class java.lang.reflect.Proxy.getProxyClass(java.lang.ClassLoader,java.lang.Class[]) throws java.lang.IllegalArgumentException
- public final void java.lang.Object.wait() throws java.lang.InterruptedException
- public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
- public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
- public final native java.lang.Class java.lang.Object.getClass()
- public final native void java.lang.Object.notify()
- public final native void java.lang.Object.notifyAll()
- 调用代理前
- 我能吃!
- 调用代理后
我们看到了方法中有eating()方法,我们试试看
- Object proxy =Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
- ((Person) proxy).eating();
运行结果:
- 调用代理前
- 我能吃!
- 调用代理后
- public final int $Proxy0.hashCode()
- public final boolean $Proxy0.equals(java.lang.Object)
- public final java.lang.String $Proxy0.toString()
- public final void $Proxy0.eating()
- public static boolean java.lang.reflect.Proxy.isProxyClass(java.lang.Class)
- public static java.lang.Object java.lang.reflect.Proxy.newProxyInstance(java.lang.ClassLoader,java.lang.Class[],java.lang.reflect.InvocationHandler) throws java.lang.IllegalArgumentException
- public static java.lang.reflect.InvocationHandler java.lang.reflect.Proxy.getInvocationHandler(java.lang.Object) throws java.lang.IllegalArgumentException
- public static java.lang.Class java.lang.reflect.Proxy.getProxyClass(java.lang.ClassLoader,java.lang.Class[]) throws java.lang.IllegalArgumentException
- public final void java.lang.Object.wait() throws java.lang.InterruptedException
- public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
- public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
- public final native java.lang.Class java.lang.Object.getClass()
- public final native void java.lang.Object.notify()
- public final native void java.lang.Object.notifyAll()
- 调用代理前
- 我能吃!
- 调用代理后
这就说明了Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this)这句相当于在代理对象中重写了实例中的eating()方法,并且在其中调用了invoke()方法。
i.证明是谁调用了invoke方法
既然可以看到代理对象proxy的所有方法,我们试试代理对象的其他代理实例的方法,从h中可以看到代理方法有:hashcode(),equals(),toString(),eating()
- Object proxy =Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
- //哈希值
- System.out.println(proxy.hashCode());
运行结果:
- 调用代理前
- 调用代理后
- 7486844
- 调用代理前
- 我能吃!
- 调用代理后
- Object proxy =Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
- //toString
- System.out.println(proxy.toString());
运行结果:
- 调用代理前
- 调用代理后
- com.huhu.aop.PersonImpl@723d7c
- 调用代理前
- 我能吃!
- 调用代理后
j.反编译.class文件
- public final class $Proxy0 extends Proxy implements Person {
- private static Method m1;
- private static Method m0;
- private static Method m3;
- private static Method m2;
- static {
- try {
- m1 = Class.forName("java.lang.Object").getMethod("equals",
- new Class[] { Class.forName("java.lang.Object") });
- m0 = Class.forName("java.lang.Object").getMethod("hashCode",
- new Class[0]);
- m3 = Class.forName("***.RealSubject").getMethod("request",
- new Class[0]);
- m2 = Class.forName("java.lang.Object").getMethod("toString",
- new Class[0]);
- } catch (NoSuchMethodException nosuchmethodexception) {
- throw new NoSuchMethodError(nosuchmethodexception.getMessage());
- } catch (ClassNotFoundException classnotfoundexception) {
- throw new NoClassDefFoundError(classnotfoundexception.getMessage());
- }
- } //static
- public $Proxy0(InvocationHandler invocationhandler) {
- super(invocationhandler);
- }
- @Override
- public final boolean equals(Object obj) {
- try {
- return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();
- } catch (Throwable throwable) {
- throw new UndeclaredThrowableException(throwable);
- }
- }
- @Override
- public final int hashCode() {
- try {
- return ((Integer) super.h.invoke(this, m0, null)).intValue();
- } catch (Throwable throwable) {
- throw new UndeclaredThrowableException(throwable);
- }
- }
- public final void eating() {
- try {
- super.h.invoke(this, m3, null);
- return;
- } catch (Error e) {
- } catch (Throwable throwable) {
- throw new UndeclaredThrowableException(throwable);
- }
- }
- @Override
- public final String toString() {
- try {
- return (String) super.h.invoke(this, m2, null);
- } catch (Throwable throwable) {
- throw new UndeclaredThrowableException(throwable);
- }
- }
- }
反编译的结果证明了我们h中得到的结论,顺便看到了为什么jdk动态代理只能代理接口。
AOP---jdk动态代理的思考的更多相关文章
- AOP jdk动态代理
一: jdk动态代理是Spring AOP默认的代理方法.要求 被代理类要实现接口,只有接口里的方法才能被代理,主要步骤是先创建接口,接口里创建要被代理的方法,然后定义一个实现类实现该接口,接着将被代 ...
- Spring AOP --JDK动态代理方式
我们知道Spring是通过JDK或者CGLib实现动态代理的,今天我们讨论一下JDK实现动态代理的原理. 一.简述 Spring在解析Bean的定义之后会将Bean的定义生成一个BeanDefinit ...
- Spring AOP JDK动态代理与CGLib动态代理区别
静态代理与动态代理 静态代理 代理模式 (1)代理模式是常用设计模式的一种,我们在软件设计时常用的代理一般是指静态代理,也就是在代码中显式指定的代理. (2)静态代理由 业务实现类.业务代理类 两部分 ...
- AOP学习心得&jdk动态代理与cglib比较
什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入 ...
- Spring AOP详解 、 JDK动态代理、CGLib动态代理
AOP是Aspect Oriented Programing的简称,面向切面编程.AOP适合于那些具有横切逻辑的应用:如性能监测,访问控制,事务管理以及日志记录.AOP将这些分散在各个业务逻辑中的代码 ...
- jdk动态代理与cglib代理、spring aop代理实现原理
原创声明:本博客来源与本人另一博客[http://blog.csdn.net/liaohaojian/article/details/63683317]原创作品,绝非他处摘取 代理(proxy)的定义 ...
- jdk动态代理与cglib代理、spring aop代理实现原理解析
原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象 ...
- 何为代理?jdk动态代理与cglib代理、spring Aop代理原理浅析
原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象 ...
- Spring AOP高级——源码实现(3)AopProxy代理对象之JDK动态代理的创建过程
spring-aop-4.3.7.RELEASE 在<Spring AOP高级——源码实现(1)动态代理技术>中介绍了两种动态代理技术,当然在Spring AOP中代理对象的生成也是运用 ...
- 【转载】Spring AOP详解 、 JDK动态代理、CGLib动态代理
Spring AOP详解 . JDK动态代理.CGLib动态代理 原文地址:https://www.cnblogs.com/kukudelaomao/p/5897893.html AOP是Aspec ...
随机推荐
- mybatis if-else(写法)
mybaits 中没有else要用chose when otherwise 代替 范例一 <!--批量插入用户--> <insert id="insertBusinessU ...
- navicat创建存储过程、触发器和使用游标
创建存储过程和触发器 1.建表 首先先建两张表(users表和number表),具体设计如下图: 2.存储过程 写一个存储过程,往users表中插入数据,创建过程如下: 代码如下: BEGIN #Ro ...
- MySQL学习(二)复制
复制解决的问题是保持多个服务器之间的数据的一致性,就如同通过复制保持两个文件的一致性一样,只不过MySQL的复制要相对要复杂一些,其基本过程如下: 1)在主库上将数据更改记录到二进制日 ...
- 【MySQL】数据库字段类型
1.数值型 整型 TINYINT SMALLINT MEDIUMINT INT BIGINT 浮点型 FLOAT(m,n) - m表示总位数,n表示小数位数. DOUBLE(m,n) DECIMAL( ...
- asp.net mvc 下拉列表
第一步:新建一个格式化下拉列表的公共类文件 using System; using System.Collections; using System.Collections.Generic; usin ...
- 前端模块化:RequireJS(转)
前言 前端模块化能解决什么问题? 模块的版本管理 提高可维护性 -- 通过模块化,可以让每个文件职责单一,非常有利于代码的维护 按需加载 -- 提高显示效率 更好的依赖处理 -- 传统的开发模式,如果 ...
- iOS 环信透传cmd消息多次重复接收,解决办法
由于项目需求,需要在项目中接到消息的时候做不同界面的不同的操作,哪儿需要哪儿就要添加代理:引起代理事件重复执行:所以要在VC显示的时候添加代理,消失的时候删除代理 环信 透传 消息多次接收情况(由于代 ...
- Linux权限分析
我看过网上的一些有关Linux的权限分析,有些说的不够清楚,另外一些说的又太复杂.这里我尽量简单.清楚的把Linux权限问题阐述明白,Linux权限没有那么复杂. Linux权限问题要区分文件权限和目 ...
- React:入门计数器
---恢复内容开始--- 把React的官网入门例子全看一遍,理解了,但自己从头开始写有点困难,这次强迫自己从头开始写,并写好注释: import React, { Component } from ...
- HTML篇(下·)
13.Label的作用是什么?是怎么用的? label标签来定义表单控制间的关系,当用户选择该标签时,浏览器会自动将焦点转到和标签相关的表单事件上. <label for="Name& ...