反射与动态代理
来源:互联网 发布:php微信关注事件推送 编辑:程序博客网 时间:2024/06/14 02:46
java中反射与动态代理是java程序员不可忽略的一门功课,关于其概念、基本使用方式,网上一大堆,本文主要讲解本人对于这两者的认识,以及关于开源项目中典型用法。
反射
Java反射机制:在程序运行时获取已知名称的类或已有对象的相关信息的一种机制,包括类的方法、属性、父类等,还包括实例的创建和实例类型的判断等。
是不是很抽象?来看个例子,在Spring中经常有如下的配置:
<bean id="person" class="com.linuer.test.Person"></bean>
(在此不讨论具体Spring容器启动细节,只是讨论与反射相关的知识点。)
可以想象到的是Spring框架会读取上面的配置,获取类的名称。然后根据已知类的名称创建实例类型。是否很熟悉描述,在看看反射机制的描述。
看不懂?没事,下面一个实际的例子
/** * 此字符串的获取你可以想象是从配置文件中,读取XMl,获取相关字符串。 **/String className = "com.linuer.test.Person"; Class cls = Class.forName(className);Object object = cls.newInstance(); //创建实例
上面的操作,用大白话说就是:根据一字符串 来得到类信息或者类方法,或者创建类实例。
至于这个 字符串 你是从哪里得来,配置文件?网络?都行,只要你想象到的方式。
除了上面操作,在实际使用过程中还有许多使用的方式。
在实际学习中关于反射相关的类主要关注:
Class类、类得属性:Field、类得方法: Method 。
动态代理
说动态代理之前,先说代理这个行为。
代理简单来说就是通过中间人来做。
来个图来说明吧
图中可以看出,有个代理之后依旧是送花这个动作,可是送花的动作的含义与原先不相同了哦。
大家都知道,代理分为:静态代理与动态代理,具体有什么区别呢?以下结合代码来说:
public interface Calculator { public void add(Integer x, Integer y); public void div(Integer x, Integer y);}--------------------------------------------------------------------------------------------------public class CalculatorImpl implements Calculator{ @Override public void add(Integer x, Integer y) { System.out.println(x+y); } @Override public void div(Integer x, Integer y) { System.out.println(x-y); }}--------------------------------------------------------------------------------------------------//正常的使用方式(对应与图中的上面两个小人的情况) Calculator calculator = new CalculatorImpl(); calculator.add(7,6)输出: 13
上面是计算数值,现在我想在计算数值的前后,分别要输出一些信息,那该怎么做呢?直接在CalculatorImpl 类中的方法添加,这么做肯定不够优雅,作为立志成为资深程序员的我们,是绝对不能这么干的。
我们要用代理模式来做。来看看静态代理怎么做的吧
public class CalcProxy implements Calculator { private Calculator calc; public CalcProxy(){ calc = new CalculatorImpl(); } @Override public void add(Integer x, Integer y) { before(); calc.add(x,y); after(); } @Override public void div(Integer x, Integer y) { before(); calc.div(x,y); after(); } private void before() { System.out.println("before"); } private void after() { System.out.println("after"); }}--------------------------------------------------------------------- Calculator calc = new CalcProxy(); calc.add(7,6);输出:before13after8
既然静态代理能够完成工作,为什么还需要改进,变成动态代理呢?原因在于:一个静态代理只能代理一个接口,这样就导致项目中到处都是XxxProxy。看动态代理是如何解决这个方案的。
public class DynamicProxy implements InvocationHandler{ private Object target; public DynamicProxy(Object target){ this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(); Object result = method.invoke(target,args); after(); return result; }.......}代码中target变量就是我们被代理的目标对象,如果用来做Calculator 代理的话,就是Calculator 对象。调用: Calculator calculator = new CalculatorImpl(); DynamicProxy dynamicProxy = new DynamicProxy(calculator); Calculator calc = (Calculator) Proxy.newProxyInstance( calculator.getClass().getClassLoader(), calculator.getClass().getInterfaces(), dynamicProxy ); calc.add(7,6);输出:before13after
上面的意思在于用dynamicProxy 去包装CalculatorImpl实例,然后调用JDK给我们提供的Proxy类的newProxyInstance去动态创建一个Calculator 接口的代理类。
对于newProxyInstance方法的参数真是让人“蓝廋”。
* 参数1:ClassLoader
* 参数2:该实现类的所有接口
* 参数3:动态代理对象
其实这块可以进一步封装下,避免程序中到处调用newProxyInstance
public class DynamicProxy implements InvocationHandler{ ..... public <T> T getProxy(){ return (T) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), this ); } ......}----------------------调用: Calculator calculator = new CalculatorImpl(); DynamicProxy dynamicProxy = new DynamicProxy(calculator); Calculator calc = dynamicProxy.getProxy(); calc.add(7,6);这样是不是简单很多了。
不知道你们注意到了没有,在DynamicProxy 中不管其代理的对象,如CalculatorImpl实例中接口增加或者减少,DynamicProxy 都不会改动,这也算是动态代理这个优点。但是如果被代理对象,是没有任何接口的类,那么它是不是就没有用武之地了呢?是的。那有没什么办法解决呢?依旧使用动态代理,但是其被代理的对象不必要是一个接口类。答案是:有的。CGLIB的动态代理。
public class CGLibProxy implements MethodInterceptor { public <T> T getProxy(Class<T> cls){ return (T) Enhancer.create(cls,this); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { before(); Object result = methodProxy.invokeSuper(obj,args); after(); return result; }......}我们需要实现CGLIB给我们提供的MethodInterceptor 实现类,并编写intercept方法,此方法的最后一个参数MethodProxy值得注意,这个是一个方法的代理。什么意思?看下面的调用:CGlibProxy cgLibProxy = new CGlibProxy();Calculator calc = cgLibProxy.getProxy(CalculatorImpl.class);calc.add(7,6);注意到没,在传入参数的时候,并没有传入接口信息。
关于反射与动态代理讲解远远不止这些,还有许多实际的应用,接下来的两篇文章中会针对动态代理的应用进行论述。
由于本人水平有限,有什么问题可以评论,喜欢的可以关注。
- 反射与动态代理
- 反射与动态代理
- 反射与动态代理
- 反射与动态代理
- JVM,反射与动态代理
- Java反射与动态代理
- java反射与动态代理
- java反射与动态代理
- 反射 动态代理与AOP
- Java反射与动态代理
- JavaVM,反射与动态代理
- Java反射与动态代理
- Java 反射与动态代理
- Java反射与动态代理
- 反射机制与动态代理
- 【反射】JAVA代理模式与动态代理
- 反射之-反射与泛型 反射实现动态代理
- 代理,动态代理,反射
- 关于android:title不起作用
- 【安全牛学习笔记】被动信息收集
- java 反射机制-学习笔记(1)
- 周中训练笔记+uva11417 poj1305
- Centos7配置Django+Gunicorn+Nginx
- 反射与动态代理
- JAVA课程3九九乘法口诀
- JSON
- C语言中const的详细用法及声明规则
- arcgis 无法打开excel文件 提示 无法注册类
- 反射与动态代理的应用(一):在RPC中的使用
- 基于FormsAuthentication的用户、角色身份认证
- 爬格子呀6-10、6-11、6-12
- 内存分配-slab分配器1