反射
运行状态下,给定任何一个类,都可以获取该类的属性和方法,给定任意对象,都可以获取内衣并且调用方法。
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是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法