Spring-静态代理、动态代理
我们先来做一个小案例:
//建立一个Man类
public interface Man {
public void run();
}`
//创建一个CommonMan 类实现Man接口
public class CommonMan implements Man {
public void run() {
System.out.println("跑步。。。");
}
}
//测试
public class ManTest {
public static void main(String[] args) {
Man man = new CommonMan();
man.run();
}
}
//输出结果
/*跑步。。。*/
这是一个简单的通过实现类实现接口的方法,但是现在有一个问题,如果现在有人觉得这个run方法实在是太慢了想要增强这个方法怎么实现?
最简单最的方式是在写一个类继承这个CommonMan 的run方法
方案一:继承
//继承方式,增强CommonMan 的run方法
public class SuperMan extends CommonMan {
@Override
public void run() {
super.run(); //原来的功能没有改变
System.out.println("跑着跑着飞起来了。。。"); //在原有功能的基础上增强
}
}
//测试类中需要修改--直接调用SuperMan中的方法
public class ManTest {
public static void main(String[] args) {
//Man man = new CommonMan();
//man.run();
SuperMan man = new SuperMan();
man.run();
}
}
//输出结果
/*跑步。。。
飞起来。。。*/
方案二:装饰者模式:在不惊动原始设计的基础上,增强某些方法
//装饰者设计模式--增强CommonMan 的run方法
public class SuperMan2 implements Man {
//这里直接创CommonMan 的父类对象增加复用性
private Man cm;
public SuperMan2(Man cm) {
this.cm = cm;
}
@Override
public void run() {
cm.run();
System.out.println("跑着跑着飞起来了。。。");
}
}
//测试类中需要修改--直接调用SuperMan中的方法
public class ManTest {
public static void main(String[] args) {
Man m1 = new CommonMan();
Man m2 = new SuperMan2(m1);
m2.run();
}
}
//输出结果
/*跑步。。。
飞起来。。。*/
方案三:动态代理–JDK
//动态代理--JDK
public class ManTest {
//动态代理
// Object 代理对象=Proxy.newProxyInstance(被代理对象的类加载器, 被代理对象的接口,实际的增强);
//创建被代理对象()
Man m1 = new CommonMan();
ClassLoader classLoader = m1.getClass().getClassLoader();
Class[] interfaces = m1.getClass().getInterfaces();
//创建代理对象
Man m2 = (Man) Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置增强代码...");
Object obj = method.invoke(m1, args);
System.out.println("后置增强代码...");
return obj;
}
});
//调用代理对象的方法测试
m2.run();
}
}
方案四:动态代理-CGLIB
public class ManTest {
Man m1 = new CommonMan(); //创建目标对象
Enhancer enhancer = new Enhancer(); //创建增强器
enhancer.setSuperclass(m1.class); //设置父类
enhancer.setCallback(new MethodInterceptor() { //设置回调
@Override
public Object intercept(Object o, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
System.out.println("前置代码增强....");
//通过调用父类方法实现对原始方法的调用
Object obj= method.invoke(o, args);
//后置增强内容,与JDKProxy区别:JDKProxy仅对接口方法做增强,cglib对所有方法做增强,包括Object 类中的方法
System.out.println("后置代码增强....");
return obj;
}
});
//创建代理对象
Man m2= (Man) enhancer.create();
//调用方法
m2.method();
}
总结
这些方法的统一目标是:对一个类的一个方法不满意,所以要增强这个类的这个方法
方案一
:继承,重写该方法
优点:简单
缺点:继承只能单一继承,而且继承是需要必须重写被继承类的所有方法
方案二
:装饰者设计模式
优点:解决了继承的缺点
缺点:相对比较麻烦,在测试的时候需要先创建原来的类(CommonMan)对象作为参数,在创建一个增强的类(SuperMan2)对象对CommonMan对象进行包装增强,这样层级太多,浪费资源。
方案三
:动态代理
1. JDK的动态代理(JDK自带的)
优点:解决了层数太多,浪费资源的情况
缺点:稍有难度,必须有接口
注意:代理对象和被代理对象之间是兄弟关系
2. CgLib的动态代理(第三方的)
优点:不需要接口
缺点:需要导入jar包
注意:代理对象和被代理对象是父子关系