代理模式
在不修改原方法的情况下,可以在方法执行前进行操作,也可以在方法执行后进行操作。
1. 静态代理
实现过程:
- 被代理的接口
public interface Eat {
void lunch();
}
- 被代理的类(实现被代理的接口)
public class Print implements Eat{
public void lunch(){
System.out.println("吃饭");
}
}
- 代理类(含有被代理接口的属性和被代理的方法)
public class Proxy {
private Eat eat;
public Proxy(Eat eat) {
super();
this.eat = eat;
}
public void lunch(){
System.out.println("做饭");
eat.lunch();
System.out.println("洗碗");
}
}
- 测试(将被代理的对象传入代理对象中)
public class test01 {
public static void main(String[] args) {
Proxy proxy = new Proxy(new Print());
proxy.lunch();
}
}
- 运行结果
做饭
吃饭
洗碗
2. jdk实现动态代理
动态代理与静态代理类似, 都是实现了对接口方法的代理, 不过封装了一些代码,提供了一些参数,方便使用。
对上面的Print类进行动态代理
public class test02 {
public static void main(String[] args) {
Eat eat = new Print();
Eat eat2 = (Eat) Proxy.newProxyInstance(eat.getClass().getClassLoader()
, eat.getClass().getInterfaces()
, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("做饭");
method.invoke(eat, args);
System.out.println("洗碗");
return null;
}
});
eat2.lunch();
}
}
容易出错的地方
- 被代理的对象一定要是一个接口类型
Eat eat = new Print();
- 生成的代理对象只能代理传入的接口类型
Eat eat2 = (Eat)...
如果强转为子类实现类将出现转换异常
Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to com.cjw.print.Print
at com.cjw.test.test02.main(test02.java:13)
- 误以为Object proxy对象为被代理的对象,其实这个对象是代理对象,
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("做饭");
method.invoke(proxy, args);
System.out.println("洗碗");
return null;
}
method.invoke(proxy, args); 如果将代理对象当作被代理对象传入, 执行逻辑是:方法被代理对象执行, 方法被代理对象执行,方法有被代理对象执行。。。一直循环下去
3. cglib实现动态代理
jdk动态代理代理是基于面向接口编程的,缺陷是无法代理非接口方法,而cglib就提供了良好的解决方法。通过被代理类字节码对象和拦截方法生成一个被代理类的子类(代理类),实例化代理类对象,调用方法就是实现了动态代理。
还是采用之前的被代理类Print进行测试
- 被代理类
package cglibtest;
public class Print {
public void lunch(){
System.out.println("吃饭");
}
}
- 拦截器, 采用的jar为:cglib-nodep-3.1.jar
package cglibtest;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class cglibfilter implements MethodInterceptor{
@Override
public Object intercept(Object object, Method method, Object[] objects, MethodProxy mProxy) throws Throwable {
System.out.println("做饭");
mProxy.invokeSuper(object, objects);
System.out.println("洗碗");
return null;
}
}
- 测试
package cglibtest;
import net.sf.cglib.proxy.Enhancer;
public class test01 {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Print.class);
enhancer.setCallback(new cglibfilter());
Print create = (Print) enhancer.create();
create.lunch();
}
}
Enhancer是一个字节码生成器, 可以创建一个新的类
- 输出
做饭
吃饭
洗碗