Java 反射和动态代理

215 阅读3分钟

反射

运行状态下,给定任何一个类,都可以获取该类的属性和方法,给定任意对象,都可以获取内衣并且调用方法。

class文件会以二进制流加载到jvm中,储存了该类的全部信息(例如:版本号,常量池,访问标志,相关类索引集合,字段表集合,方法集合等),根据类名可以定位到该类在jvm的存储位置,可以得到相应的信息。

一般情况下我们使用反射获取一个对象的步骤:

获取类的 Class 对象实例 Class clz = Class.forName(calssName); 根据 Class 对象实例获取 Constructor 对象 Constructor appleConstructor = clz.getConstructor(); 使用 Constructor 对象的 newInstance 方法获取反射类对象 Object appleObj = appleConstructor.newInstance(); 而如果要调用某一个方法,则需要经过下面的步骤:

获取方法的 Method 对象 Method setPriceMethod = clz.getMethod(方法名, 参数列表...); 利用 invoke 方法调用方法 setPriceMethod.invoke(appleObj, 参数值...);

代理

代为处理

优点一:可以隐藏委托类的实现;

优点二:可以实现客户与委托类间的解耦,在不修改委托类代码的情况下能够做一些额外的处理

静态代理

public interface Flyable { void fly(); }

public class Bird implements Flyable {

@Override
public void fly() {
    System.out.println("Bird is flying...");
    try {
        Thread.sleep(new Random().nextInt(1000));
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

}

public class BirdLogProxy implements Flyable { private Flyable flyable;

public BirdLogProxy(Flyable flyable) {
    this.flyable = flyable;
}

@Override
public void fly() {
    System.out.println("Bird fly start...");

    flyable.fly();

    System.out.println("Bird fly end...");
}

}

public static void main(String[] args) { Bird bird = new Bird(); BirdLogProxy p1 = new BirdLogProxy(bird); BirdTimeProxy p2 = new BirdTimeProxy(p1);

    p2.fly();
}

BirdTimeProxy,在它的fly方法中我们直接调用了flyable->fly()方法。换而言之,BirdTimeProxy其实代理了传入的Flyable对象,这就是典型的静态代理实现。

静态代理至少有以下两个局限性问题:

如果同时代理多个类,依然会导致类无限制扩展 如果类中有多个方法,同样的逻辑需要反复实现

动态代理

动态生成代理类

1、JDK 动态代理

定义中介类实现InvocationHandler接口
@Override
public Object invoke(Object proxy, Method method, Object[] args)
需要实现该方法,处理逻辑写在这里,执行动态生成的代理类的方法时最终会执行该方法。

public class MyInvocationHandler implements InvocationHandler { private Bird bird;

public MyInvocationHandler(Bird bird) {
    this.bird = bird;
}

@Override
public void invoke(Object proxy, Method method, Object[] args) {
    long start = System.currentTimeMillis();

    try {
        method.invoke(bird, new Object[] {});
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }

    long end = System.currentTimeMillis();
    System.out.println("Fly time = " + (end - start));
}

}

MyInvocationHandler handler = new MyInvocationHandler(); Flyable proxy = Proxy.newProxyInstance(Flyable.class, handler); proxy.fly();

handle相当于一个全局代理,在invoke方法中添加为拖累的加强处理,proxy生成handle的代理类,继承了Proxy方法 实现了委托类的接口。

2、cglib

public class UserInterceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("cglib 代理"); return proxy.invokeSuper(obj, args); } }

private static void cglibProxy(){
    UserInterceptor proxy = new UserInterceptor();
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(UserServiceImpl.class);
    enhancer.setCallback(proxy);
    UserServiceImpl user = (UserServiceImpl) enhancer.create();
    user.getAge();
    System.out.println(1);
}

3、区别

JDK动态代理只能对实现了接口的类生成代理,而不能针对类 。
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法