java反射+动态代理

总感觉作为javaee的程序员应该对spring有一个了解,所以就好好看了一下。

一:学习步骤

倒序:spring框架---->IOC,DI,AOP,工厂模式---->动态代理---->代理----->反射

二:

反射:最近几天真的好好看了一下反射,主要是Thinking in java,所以也就是拾人牙慧,自己做个总结。先写一些概念

需要明白的概念:

类型信息:运行时类型信息是的你可以在程序运行的时候发现和使用类型信息。

运行时识别类型信息的方式:

1RTTI:假定我们在编译时已经知道类型信息

2反射:在运行时发现和使用类型信息

RTTI:直接讲一个数组存储和取值的过程:

记住,数组存放的是引用(和基本类型),不是对象。是引用,是存放的引用。

只要有一个引用,不管你原来什么身份,现在都是Object类型的引用。

但是编译时期:用数组容器和泛型保证它是Shape类型的,

       运行时期用RTTI技术保证的。

.class是字节码文件是java执行文件存在形式。里边有字节码形式的各种属性方法等等。


Class对象:

运行时期,表示类型信息的对象,用于创建类。它来执行RTTI方法。

newInstance()方法---解释:一般要创造一个对象得知道它的类型,就是咱们new类型();

但是,用newInstance()不用知道类型,它的含义就是:我不知道你是什么类型,但是无论如何你得正确创造自己的对象,所以要求该类的有默认构造方法。

每一个类都有自己的Class对象。

Class对象保存在.class文件中。

类加载器:

JVM的子系统。

用于生成Class对象,

有一个类加载器链,只有一个原生类加载器---加载可信类

等等。

类加载器首先加成Class对象是否被加载,--

类加载时机:当程序创建第一个对类的静态成员的引用时,就加载这个类。

Java程序在开心运行之前并非被完全加载。要什么才加载什么。

要想在运行时使用类型信息,必须先取得该类的Class对象的引用

A  forName()不需要该类型的对象就能获取Class对象的引用立即初始化

B  getClass()需要该类型的对象。

C  类字面常量方式取得Class对象的引用:类名.class

D  类字面常量取得Class对象的引用,不会自动初始化该Class对象

1加载:类加载器找字节码,再依据字节码创建Class对象。

2链接:验证类中字节码,为静态域分配存储空间。等

3初始化:超类的初始化。执行静态初始化器和静态初始化块。

初始化被延迟到了对静态方法首次调用和对非常数静态域首次引用才执行。

初始化尽可能的惰性,贼懒

反射:大家期待的反射到了

RTTI告诉你类型信息,但这个类在编译期必须已知,如果在编译期类型不知道,那还想用到类型信息,那就得用反射。

跳过Tinking In Java的许多段,直白说明反射:

反射跟RTTI基本一样,只不过

RTTI:在编译期打开和检查.class文件,

反射:在编译期间获取不到.class文件,需要在运行时期获取.class文件,做的工作和RTTI一样。

反射接触一个对象时,jvm检查这个对象,看它属于哪个类,再加载那个类的.class文件(从网络或者本地获取),再根据这个.class创建类的对象。

反射使用场景:你使用的类并不好,可能它的基类有更适合你的方法,那么就通过反射暴露基类的方法,然后你就可以选择了,eclips的快捷提示也是用到了反射。

动态代理:

你要对一段代码进行维护,可能是打印日志,可能是事务操作,就是在目标代码段前后进行代码插入才能完成的功能,我们希望把这些代码提取出来,目标代码单独存放在一个Java文件,维护的代码放在另一个文件。那么就用到了代理

动态代理更先进,我们可以随机的对目标方法的调用,这个调用是动态的,现取现用的。

所有的调用会转到唯一的调用处理器上,调用处理器会揭示调用的方法类型,并进行确切的操作。

类加载器的获取:可以从一个被加载的对象获取它的加载器。Proxy.newProxyInstance()动态创建代理,但是它需要一个类加载器,一个InvocationHandler接口的实现,动态代理将所有的调用转发到调用处理器,所以向调用处理器构造器传入一个实际的对象的引用,从而使得调用处理器在执行任务时将请求转发(就是InvocationHandler接口的实现类中的invoke方法。)

Invoke方法传递来了代理对象,以防你需要区分请求的来源。

来一段代码吧,

下面例子讲述了一个动态代理Subject.javaRealSubject.javaDynamicSubject.javaClient.java,把他们放在一个包下,代码如下:

Subject.java代码

//抽象角色(之前是抽象类,此处应改为接口)

public interface Subject

{

public void request();

}

//抽象角色(之前是抽象类,此处应改为接口)

public interface Subject

{

public void request();

}

Realsubject.java代码

//具体角色

public class RealSubject implements Subject

{

public RealSubject()

{

}

public void request()

{

System.out.println("真正做事的。");

}

}

//具体角色

public class RealSubject implements Subject

{

public RealSubject()

{

}

public void request()

{

System.out.println("真正做事的。");

}

}

Dynamicsubject.java代码

//代理处理器

/**

* 该代理类的内部属性为Object类,实际使用时通过该类的构造函数DynamicSubject(Object obj)对其赋值;

* 此外,在该类还实现了invoke方法,该方法中的method.invoke(sub,args);

* 其实就是调用被代理对象的将要被执行的方法,方法参数sub是实际的被代理对象,

* args为执行被代理对象相应操作所需的参数。

* 通过动态代理类,我们可以在调用之前或之后执行一些相关操作

*/

public class DynamicSubject implements InvocationHandler

{

private Object sub;

public DynamicSubject()

{

}

public DynamicSubject(Object obj)

{

sub = obj;

}

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

{

System.out.println("调用前" + method);

method.invoke(sub, args);

System.out.println("调用后 " + method);

return null;

}

}

//代理处理器

/**

* 该代理类的内部属性为Object类,实际使用时通过该类的构造函数DynamicSubject(Object obj)对其赋值;

* 此外,在该类还实现了invoke方法,该方法中的method.invoke(sub,args);

* 其实就是调用被代理对象的将要被执行的方法,方法参数sub是实际的被代理对象,

* args为执行被代理对象相应操作所需的参数。

* 通过动态代理类,我们可以在调用之前或之后执行一些相关操作

*/

public class DynamicSubject implements InvocationHandler

{

private Object sub;

public DynamicSubject()

{

}

public DynamicSubject(Object obj)

{

sub = obj;

}

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

{

System.out.println("调用前" + method);

method.invoke(sub, args);

System.out.println("调用后 " + method);

return null;

}

}

Client.java代码

//客户端

public class Client

{

static public void main(String[] args) throws Throwable

{

RealSubject rs = new RealSubject(); // 在这里指定被代理类

InvocationHandler ds = new DynamicSubject(rs);

Class<?> cls = rs.getClass();

// 以下是一次性生成代理

Subject subject = (Subject) Proxy.newProxyInstance(

cls.getClassLoader(), cls.getInterfaces(), ds);

subject.request();

}

 理解代理之前一定要先理解代理模式,代理模式是动态代理的基础,你要明白Proxy.newProxyInstance()方法传入的接口信息是相当于代理模式中代理类的继承。得到目标被代理类的类加载器,用于加载原来的对象,因为传入代理处理器类的是代理对象,所以代理对象也封装了真实对象。还封装了处理器对象,

invocationHandler的实现类是代理器处理器类,用这个类的invoke方法去寻找被代理的方法,在该方法内执行被代理的类的具体的方法。

 未完待续,我会继续更的,不一定什么时候

本来想写自己理解的,但是水平还是不行,基本抄原文了,Thinking in java确实经典啊。

===========鼎哥原创=========


猜你喜欢

转载自blog.csdn.net/masaida/article/details/79164604