Java代理模式
什么是代理模式:
代理模式是23种设计模式中的一种,其思想是:为目标对象提供代理,外部想要访问目标对象就必须通过代理,这样做的意义在于隔离目标对象,比如 明星跟经纪人,就是很典型的代理模式,明星就是目标,经纪人就是代理,现在有一家公司想要找明星拍广告,怎么办,能直接找这个明星吗,不能,那就去找他的代理(经纪人)吧,具体经纪人如何跟明星商量的,广告公司不用管。画个图:
代理模式.png
三种代理模式:
1. 静态代理:
首先我们定义一个目标对象和代理对象的公共接口(保证在使用者看来,貌似我就是调用了目标对象的方法)
public interface IStart {
void advertising();
}
接下来,我们定义一个目标类
public class Star implements IStart {
String name;
public Star(String name) {
super();
this.name = name;
}
// 拍广告
@Override
public void advertising() {
System.out.println("我是" + name + ",我给你拍霸王洗发水的广告");
}
}
代理类:
public class StarProxy implements IStart {
//我是代理类,我在创建的时候就要给我指定,我要代理谁
private Star star;
public StarProxy(Star star) {
super();
this.star = star;
}
@Override
public void advertising() {
star.advertising();
}
}
好了,所有类都定义好了,我们开始使用
public static void main(String[] args) {
Star star = new Star("成龙");
StarProxy proxy = new StarProxy(star);
//拍广告
proxy.advertising();
}
输出结果:我是成龙,我给你拍霸王洗发水广告,是不是很简单呢,对于使用者来说,我调用的是代理对象的方法,但是真正做事的还是目标对象
大家有没有发现,我的代理类和目标类都实现了同一个接口,IStar,那么如果我现在有新的功能来了,比如,我不仅拍广告,我还可以拍电影,我还可以唱歌,如果添加,那么目标类和代理类都需要维护,这就麻烦了,没关系,下面我们看看动态代理
2. 动态代理
动态代理的代理对象不需要实现接口,动态代理的核心类:java.lang.reflect.Proxy,代理对象的生成一般通过
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法来生成的,需要三个参数:
- ClassLoader 目标对象的类加载器
- interfaces[] 目标对象所实现的所有接口,可以是一个也可以是多个
- InvocationHandler 事件处理的方法(android中的handler有点像,反正只要知道,他是处理事件的,下文会有代码)
我们直接上代码,Star和IStar都不用换,创建StarProxy2
public class StarProxy2 {
Star star;
public StarProxy2(Star star) {
super();
this.star = star;
}
public Object getProxy(){
return Proxy.newProxyInstance(star.getClass().getClassLoader(), star.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//下面代码invoke(),是不是很熟悉,没错,就是反射
Object returnObj = method.invoke(star, args);
return returnObj;
}
});
}
}
public static void main(String[] args) {
Star star = new Star("成龙");
StarProxy2 proxy2 = new StarProxy2(star);
IStart iStart = (IStart) proxy2.getProxy();
iStart.advertising();
}
动态代理和静态代理的区别是,动态代理中,代理类不用实现接口,共同点是目标类需要实现接口,那么有没有目标类和代理类都不用实现接口的代理方式呢,有!哈哈,这就是我们接下来要说的,Cglib代理
3. Cglib代理(这里仅介绍用法)先去github下载Cglib,他还要依赖asm和ant所以都要分别下载
Cglib又叫子类代理,为什么呢,其原理就是在内存中创建目标对象的子类作为代理类。他的用途很广泛,例如 Spring AOP。
//新建一个类,我这里叫StarProxy3,实现MethodInterceptor,这个接口就是来处理代理的方法
public class StarProxy3 implements MethodInterceptor{
Star star;
public StarProxy3(Star star) {
super();
this.star = star;
}
public Object getProxy(){
//这是一个工具,我们告诉他目标对象的Class,因为一会他要给他创建一个子类
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(star.getClass());
//这里是设置回掉接口,就是我们实现MethodInterceptor的方法intercept;
enhancer.setCallback(this);
//开始创建代理类了
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
//通过反射调用,和动态代理一样
Object returnObj = method.invoke(star, args);
return returnObj;
}
}
public static void main(String[] args) {
Star star = new Star("成龙");
//这里的proStar实际是Star类的子类
Star proStar = (Star) new StarProxy3(star).getProxy();
proStar.advertising();
}
注:这里有一个小细节,被代理的类一定要保证有空参构造,因为Cglib代理就是通过目标类的空参构造来创造其子类,并为其代理,若没有,则会报错
总结:三种代理方式,做android开发一般Cglib用的不多(我是这样子的,因为比较麻烦),一般第二种就完全搞定了,想研究Cglib源码的童鞋可以点这里