代理模式
- 定义:给某一个对象提供一个代理,并由代理对象控制对原对象的引用。
代理(Proxy)是一种设计模式,提供了间接对目标对象进行访问的方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的功能上,增加额外的功能补充,即扩展目标对象的功能。在java中代理模式很常见。代理模式就是一种思维方式。
这就符合了设计模式的开闭原则,即在对既有代码不改动的情况下进行功能的扩展。
举个例子,比如在国内想要买国外的商品,就需要有代购,需要告诉代购你想买的东西。代购会帮你找到目标商店帮你买。其中这个代购就可以看作是一个代理。目标商店就是被代理的类。
下面来说一下java中三种代理模式。
静态代理
- 静态代理需要目标类和代理类都实现同一个接口。
被代理类
//目标类
public class Ps4Factory implements GameFactory{
public void make() {
System.out.println("Ps4已出库");
}
}
代理类
public class Proxy implements GameFactory{
private GameFactory game;
public Proxy(GameFactory game) {
this.game = game;
}
public void make() {
doBefore();
game.make();
doAfter();
}
private void doAfter() {
System.out.println("After is OK");
}
private void doBefore() {
System.out.println(" Befor is OK");
}
}
测试
public static void main(String[] args) {
//此模式为Proxy的静态代理模式
//优点:可以在不改变目标对象的代码的情况下,增加功能。
//缺点:Proxy和目标对象都需要实现一个共同的接口,这样的话,就会导致Proxy的类中也需要实现这个方法。不益于拓展。
GameFactory ps4Factory = new Ps4Factory();
GameFactory proxy=new Proxy(ps4Factory);
proxy.make();
}
结果
Befor is OK
Ps4y已出库
Afte ris OK
已经是现在在不改变目标类的情况下增加功能。静态代理的前提是需要代理类和被代理类都实现统一个接口。
动态代理
jdk动态代理
- 动态代理是在程序运行过程中,动态生成一个代理对象。
被代理类
public class Ps4Factory implements GameFactory {
public void make() {
System.out.println("Ps4 make。。。");
}
public void sall() {
System.out.println("Ps4 sall。。。");
}
代理类
**
* 动态代理需要实现一个叫invocationHandler的接口。 主要是用来让生成的代理对象动态(代理)的调用目标方法,并且添加对应的辅助功能!!!
*/
public class JdkProxy implements InvocationHandler {
private Object target;
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
public Object getProxy(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
public Object invoke(Object proxyy, Method method, Object[] args) throws Throwable {
doBefore();
Object invoke = method.invoke(target, args);
deAfter();
return invoke;
}
private void deAfter() {
System.out.println(" invoke end!!!!");
}
private void doBefore() {
System.out.println(" invoke start!!!!");
}
}
测试类
public static void main(String[] args) {
GameFactory ps4Factory = new Ps4Factory();
GameFactory gameFactory = new GameBoy();
JdkProxy cglibProxy = new JdkProxy();
cglibProxy.setTarget(ps4Factory);
GameFactory proxy = (GameFactory) cglibProxy.getProxy();//此处生成了一个类似于静态代理的代理对象。可以看成是静态代理了。 由于是动态生成的,所以叫动态代理
proxy.make();
proxy.sall();
}
测试结果
invoke start!!!!
Ps4 make。。。
invoke end!!!!
invoke start!!!!
Ps4 sall。。。
invoke end!!!!
可以看到在每个方法执行之前都实现了,功能拓展。但是此模式要求被代理类要实现某一接口,并且代理类要实现InvocationHandler方法。
cglib动态代理
被代理类
public class User {
public void know(){
System.out.println(" i know !!");
}
}
代理类
public class CglibProxyFactory implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class<?> clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("警卫正在通知领导!!");
methodProxy.invokeSuper(o, objects);
System.out.println("警卫通知领导完毕!!");
return new Object();
}
}
测试类
public static void main(String[] args) {
CglibProxyFactory proxy=new CglibProxyFactory();
User userProxy = (User)proxy.getProxy(User.class);
userProxy.know();
}
警卫正在通知领导!!
i know !!
警卫通知领导完毕!!
在代理类没有实现任何接口的情况下也同样实现了功能拓展。
总结
jdk动态代理就是在与目标类实现同一接口的情况下,创建一个与被代理对象的一个兄弟类,在代理类被调到一个方法是,通过放射去被代理类执行。完成功能拓展。
cglib代理则是创建了一个与被代理类的一个子类,通过继承的规则,在子类中调用某一方法是,通过super来调用父类(被代理类)的方法。从而实现功能拓展。
所以在平时开发中,如果目标类实现类某一接口可以使用jdk动态代理。没有的话,就使用cglib代理。