文章目录
反射机制
Java中的许多对象在运行时都会出现两种类型:编译时类型和运行时类型。如Person p = new Student();将会产生一个p变量,该变量的编译时类型为Person,运行时类型为Student。又如程序运行时接收到外部传入的一个对象,编译时类型为Object,运行时需要调用运行时的类型的方法。这种在编译时无法预知要使用哪个类型的情形,需要使用反射机制,即运行时获得类信息。
通常在开发通用性比较广的框架、基础平台时会大量使用反射,来动态创建某个类的对象。
Class类
类中之王Class是所有class的类,要在运行时获得类信息,即要在运行时获得Class类对象(见java.lang.Class类)。Class类没有public构造器,是通过JVM自动生成的,但是我们可以获得要通过反射操作的Class对象。
如何获得Class对象?
每个类被加载后会生成一个对应的Class对象存在JVM中。要获得改Class对象信息,有以下三种方式:
1)使用forName静态方法
Class<?> testClass = Class.forName("Test");
2)使用class属性
Class testClass = Test.class
3)使用getClass方法
如何操作Class对象?
1)通过Class对象的newInstance()方法创建类的实例。在许多框架中,需要根据配置文件来创建对象,即使用此方法。
2)或者先获取到Constructor对象,再调用Constructor的newInstance()方法创建实例。这种方法可以指定使用哪个构造器来创建对象实例。
参见java.lang.reflect包下的Method、Constructor、Field。
获得Method数组后,每个Method对象的invoke方法可以用来调用反射操作对象的相应方法。
使用反射生成动态代理
java.lang.reflect包下的Proxy类和InvocationHandler接口,用来生成动态代理。
Proxy提供了用于创建动态代理类和代理对象的静态方法,也是所有动态代理类的父类。
Proxy提供了以下两个方法来创建动态代理类和动态代理实例。
public static Class<?> getProxyClass(ClassLoader loader,
Class<?>... interfaces)
throws IllegalArgumentException
{
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
return getProxyClass0(loader, intfs);
}
创建一个动态代理类的Class对象。第一个ClassLoader参数指定了生成动态代理类的类加载器,动态代理类将实现第二个参数提供的所有接口。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
直接创建一个动态代理实例,实现了所有接口,执行动态代理对象的每个方法都会被替换执行InvocationHandler对象的invoke方法。
Spring框架中的AOP,先实现InvocationHandler接口,重写invoke方法,将横切代码嵌入其中,实现面向切面编程。其中method.invoke()使用反射来调用被代理类。
使用时新建一个代理类,使用代理类来调用被代理类方法。
Spring AOP有哪些方式?
Java Proxy
动态构建代理对象
Cglib
动态构建代理对象
AspectJ
修改目标字节,编译时织入代理字节,基于eclipse
instrumentation
修改目标字节,在类装载时动态拦截并织入代理字节,javaagent