博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
来谈谈 Java 反射机制,动态代理是基于什么原理?
阅读量:4288 次
发布时间:2019-05-27

本文共 2837 字,大约阅读时间需要 9 分钟。

目录

1 一些概念

首先我们来看一些概念性的描述:

注解(Annotation):也叫元数据。一种代码级别的说明。它是JDK 1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

反射:赋予程序在运行时自省(introspect)的能力。指的是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性。

静态代理:事先写好代理类,缺点是每个业务类都要对应一个代理类,非常不灵活。

动态代理:运行时自动生成代理对象,是一种方便运行时动态处理代理方法调用的机制。很多场景都是利用类似机制,比如:用来包装RPC调用、面向切面编程(AOP)。通过代理可以让调用者和实现者之间解耦。

JDK动态代理:代理类需要实现JDK的  InvocationHandler 接口 ,其中 完成真实方法的调用是通过 invoke 方法来实现的。必须实现了接口的类才能用这种办法生成代理对象,依赖接口。

cglib动态代理:通过生成类的子类作为代理类,对于接口的依赖被克服了。

AOP:面向切面编程。在不影响原有功能的情况下,对程序进行横向扩展。说说我自己的理解吧。某个类的方法已经封装好了,现在我们要对原有的方法进行干预,但是又不能破坏原来的类,这时候就需要aop的思想,把这个切点扩展成一个面来进行操作。(也就是生成该类的代理,对代理进行操作

依赖注入(控制反转):Spring是通过反射来实现依赖注入的。什么是依赖呢? 如果在A类里面调用B类,那么A类需要依赖于B类,通常的话,是A类来创建B类的示例。但是spring 里面,创建的动作由spring容器来完成,然在在运行的时候注入到A类中,所以叫做依赖注入。比如说注解@Resource和@Autowired等

  • 正常方式:通过完整的类名—>通过new实例化—>取得实例化对象
  • 反射方式:实例化对象—>getClass()方法—>通过完整的类名

总结: 反射和动态代理都是运行时的机制。通过反射,我们可以在运行时操作类或者对象。而动态代理,它是一个代理机制,代理可以看做是对调用目标的一个包装,代理除了可以调用目标,还可以做一些其他的操作。通过代理可以让调用者与实现者解耦。动态代理是运行的时候才自动生成代理对象,如果是编码阶段显式的指定代理类,就是静态代理了。

 

2 动态代理解决了什么问题,在你的业务系统中的应用场景是什么?

通过代理可以让调用者和实现者之间解耦。

JDK的动态代理:通常代理类需要实现JDK的  InvocationHandler 接口 ,其中 完成真实方法的调用是通过 invoke 方法来实现的。通过InvocationHandler接口,所有方法都由该Handler来进行处理,即所有被代理的方法都由InvocationHandler接管实际的处理任务。此外,我们常可以在invoke方法实现中增加自定义的逻辑实现,实现对被代理类的业务逻辑无侵入。

public class DynamicProxy {    public static void main(String[] args) {        HelloImpl hello = new HelloImpl();        //实现对应的InvocationHandler        MyInvocationHandler handler = new MyInvocationHandler(hello);        // 构造代码实例        Hello proxyHello = (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(), HelloImpl.class.getInterfaces(), handler);        // 调用代理方法        proxyHello.sayHello();    }}    interface Hello {        void sayHello();    }    class HelloImpl implements  Hello {        @Override        public void sayHello() {            System.out.println("Hello World");        }    }    class MyInvocationHandler implements InvocationHandler {        private Object target;        public MyInvocationHandler(Object target) {            this.target = target;        }        @Override        public Object invoke(Object proxy, Method method, Object[] args)                throws Throwable {            System.out.println("Invoking sayHello");            Object result = method.invoke(target, args);            return result;        }    }

JDK proxy 的动态代理,其实现过程可以简化为:

  • 提供一个基础的接口,作为被调用类型和代理类型之间的统一入口,如上面代码的interface Hello
  • 实现 invocationHandle接口,即被调用的方法都由 invocationHandle 来处理,其方法 invoke ()是真正的动作逻辑。
  • 通过Proxy 类,调用  newProxyInstance ,在运行时动态生成代理类的实例。(动态代码生成就在这个阶段)

 

JDK proxy 的方法,有接口的依赖,那如果被调用者没有实现接口,而我们还希望利用动态代理机制,怎么办? 

我们知道,Spring AOP 支持两种方式的动态代理,JDK proxy 和 cglib,如果我们选择cglib方式,cglib 是通过 asm 直接操作字节码,所以可以不实现接口。cglib 动态代理采用的是创建目标类的子类的方式,因为是子类,可以达到近似使用被调用者本身的效果。

通过代理静默的解决一些业务无关的问题,比如:安全、事务、日志、资源关闭,让开发者可以只关心于他的业务。

 

以上,有点晦涩。有时间再补充扩展吧。?

 

 

 

转载地址:http://znlgi.baihongyu.com/

你可能感兴趣的文章
程序员常用的自助建站资源汇总!
查看>>
分布式与集群的区别是什么?
查看>>
MySql常用必备脚本大全
查看>>
Velocity初探小结--velocity使用语法详解
查看>>
设计模式学习 - Singleton Pattern
查看>>
学习Spring——依赖注入
查看>>
CSS3 transform 属性详解
查看>>
Java对象内存结构及大小计算
查看>>
Spring MVC注解的一些案列
查看>>
Web大文件断点续传,快来看看吧!
查看>>
javascript高级编程3第二章:在html中使用javascript
查看>>
Android中热修复框架AndFix原理解析及案例使用
查看>>
手写代码实现EventBus
查看>>
关于JSON的相关知识
查看>>
SpringMVC基础_常用注解
查看>>
Spring框架-IOC容器和Bean的配置(1)
查看>>
查询内容在网页里面分页显示+跳页查看
查看>>
mysql substring函数截取值后赋给一个declare变量
查看>>
Java Thread 的 sleep() 和 wait() 的区别
查看>>
DbUtils入门
查看>>