1.装饰者模式的缺点:
很麻烦 做到了无侵入式增强,缺憾 代码工作量多 会导致类结构爆炸。
2.动态代理技术优化
保留 无侵入增强的特色
去除 写大量代码 写大量类
3 动态代理技术 在java领域两种实现方式:
1.jdk自带方法
好处不需要引入别的jar包 用起来简单 缺点 如果增强一个对象 被增强 必须有个接口
2.第三方jar包
asm 难度第一 性能最好
cglib 难度第二 性能第二
javassist 难度最低 性能跟第二个差不多
缺点引入第三方jar包 优点 不需要接口也可以增强
4.jdk动态代理
在java.lang.reflect 包 有一个类 Proxy 有一个方法 帮助实现
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) ;
使用这个方法 可以直接帮你产出一个已经被增强过的对象
三个参数:
ClassLoader:类加载器 随便一个类加载器(给一个除去特殊 引导类加载,和扩展类加载 使用自己引入第三方自己的类 得到那个类加载器)
interfaces:接口数组 传入原本对象实现所有接口数组
InvocationHandler:执行处理类对象(难点);
实现它InvocationHandler接口
Object invoke(Object proxy, Method method, Object[] args)
proxy:代表的是 即将返回的增强对象
method:代表的是增强对象调用方法的时候的方法本身
args:代表的是增强对象调用方法传入实参本身
public class Demo01 {
public static void main(String[] args) {
//目的增强逻辑
QQ qq=new QQ();
//换动态代理 返回一个增强的对象
Car zq = (Car) Proxy.newProxyInstance(
Demo01.class.getClassLoader(),
qq.getClass().getInterfaces(),
new MyInvocationHandler(qq)
);
//zq.run();
//zq.stop();
//zq.driver("小明");
//int i = zq.oilTank();
//System.out.println(i);
zq.didi().didi().didi();
}
private static class MyInvocationHandler implements InvocationHandler{
private Car car;
public MyInvocationHandler(Car car) {
this.car = car;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//System.out.println(proxy);
//System.out.println(method.getName());
if ("run".equals(method.getName())){
long start = System.currentTimeMillis();
// 平常调用方法 对象.方法
// 方法.invoke(对象)
method.invoke(car);
long end = System.currentTimeMillis();
System.out.println("百公里加速用时"+(end-start));
}else if("driver".equals(method.getName())) {
System.out.println(Arrays.toString(args));
method.invoke(car,args[0]+"的媳妇儿")
}else if("oilTank".equals(method.getName())) {
Integer invoke = (Integer) method.invoke(car, args);
return invoke+100;
}else if("didi".equals(method.getName())) {
System.out.print("增强对象在调用:");
method.invoke(car);
return proxy;
}else {
//调用原来的方法
method.invoke(car);
}
return null;
}
}
注意:a.didi().didi().didi()为链式编程(递归)
5.javassist 实现动态代理
无接口也可实现
首先导入jar包
材料准备
本来的功能,接下开始增强
public class Demo {
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
User user = new User();
user.setUsername("小明");
//偷偷改掉你这个方法
ProxyFactory proxyFactory=new ProxyFactory();
//User.class父类
proxyFactory.setSuperclass(User.class);
proxyFactory.setHandler(new MethodHandler() {
@Override
public Object invoke(Object o, Method method, Method method1, Object[] objects) throws Throwable {
System.out.println(method.getName());
System.out.println("自己补充逻辑");
return "我偷偷把你的返回值改了";
}
});
Class<?> aClass = proxyFactory.createClass();
User o = (User) aClass.newInstance();
String username = o.getUsername();
System.out.println(username);
}
}