代理模式定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
来源《大话设计模式》
一:静态代理 扩展不方便,需要知道具体的目标类,下面例子实际就是母亲给儿子,儿子的eat方法之前或之后增加一些业务逻辑,但是母亲目前只能给儿子做饭,不能给儿子的爸爸做饭,这就是静态代理的局限之处,无法实现动态扩展。
//人类 public interface Person { void eat(); } //儿子 public class Son implements Person { @Override public void eat() { System.out.println("吃饭"); } } //母亲 public class Mother implements Person { private Person son; public Mother(Person son) { this.son = son; } @Override public void eat() { System.out.println("妈妈做饭"); son.eat(); System.out.println("妈妈洗碗"); } } public class StaticProxyTest { //静态代理 public static void main(String[] args) { Person person = new Mother(new Son());
person.eat();
} }
结果:
二:动态代理 动态代理其实相比静态代理而言,而且在代理之前,目标类中的方法可以为未知的。动态代理实现方式一般都有两种:JDK动态代理和CGLib动态代理
JDK动态代理
接口:Subject.java
public interface Subject { //干活 void doThing(); }
真实对象:RealSubject.java
public class RealSubject implements Subject { @Override public void doThing() { System.out.println("干活"); } }
代理对象生成:实现InvocationHandler接口
public class MyInvocationHander implements InvocationHandler { private Subject sub; public Object getInstance(Subject target){ this.sub = target; Object o = Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this); return o; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before doThing");//前置行为 method.invoke(sub,args); System.out.println("after doThing");//后置行为 return proxy;
} }
测试类:JdkDynamicProxyTest .java
public class JdkDynamicProxyTest { //jdk动态代理测试 public static void main(String[] args) { RealSubject subject = new RealSubject(); Subject target = (Subject)new MyInvocationHander().getInstance(subject); target.doThing(); } }
CGLib动态代理:上面基于JDK的动态代理必须实现接口, CGLib动态代理没有这个限制,private或是final类修饰的方法,则不会被重写。
接口:Engineer
public class Engineer { public void work() { System.out.println("工程师正在工作"); } }
CGLIB 代理类:CglibProxy
public class CglibProxy implements MethodInterceptor { private Object target; public CglibProxy(Object target) { this.target = target; } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("前置行为"); Object result = method.invoke(target, objects); System.out.println("后置行为"); return result; } public static Object getProxy(Object target) { Enhancer enhancer = new Enhancer(); // 设置需要代理的对象 enhancer.setSuperclass(target.getClass()); // 设置代理人 enhancer.setCallback(new CglibProxy(target)); return enhancer.create(); } }
测试类:
public class CglibMainTest { public static void main(String[] args) { // 生成 Cglib 代理类 Engineer engineerProxy = (Engineer) CglibProxy.getProxy(new Engineer()); // 调用相关方法 engineerProxy.eat(); } }
总结:
主要优点有:
- 代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
- 代理对象可以扩展目标对象的功能;
- 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度;
主要缺点是:
- 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢;
- 增加了系统的复杂度;