代理模式应用场景:
生活中的租房中介、售票黄牛、婚介、经纪人、快递、事务代理、非侵入式日志监听等,都是代理模式的实际体现
代理模式主要有两个目的:一是保护目标对象,二是增强目标对象。
静态代理举例:
首先创建代理主题角色ISubject类:
public interface ISubject { void request(); }
创建真实主题角色RealSubject类:
public class RealSubject implements ISubject {
public void request() { System.out.println("real service is called."); }
}
创建代理主题角色Proxy类:
public class Proxy implements ISubject {
private ISubject subject;
public Proxy(ISubject subject){
this.subject = subject;
}
public void request() {
before();
subject.request();
after();
}
public void before(){
System.out.println("called before request().");
}
public void after(){
System.out.println("called after request().");
}
}
客户端调用代码:
public static void main(String[] args) {
Proxy proxy = new Proxy(new RealSubject()); proxy.request();
}
上面这个静态代理有个弊端就是Proxy只能接受ISubject类型的,万一业务扩张怎么办,而且每次都要去改代理类,就很麻烦,所以就有了动态代理:
动态代理的底层实现一般不用我们自己亲自去实现,已经有很多现成的API。在Java生态中,目前最普遍使用的是JDK自带的代理和Cglib提供的类库。下面我们首先基于JDK的动态代理支持如来升级一下代码。
首先,创建媒婆(婚介所)类JdkMeipo:
package proxy.dynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MeiPoProxy implements InvocationHandler{
private IPerson person;
public IPerson getInstance(IPerson person){
this.person = person;
Class<?> clazz = person.getClass();
return (IPerson) Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开始寻找对象!");
method.invoke(this.person,args);
System.out.println("寻找对象完毕!");
return null;
}
}
再创建一个类ZhaoLiu:
package proxy.dynamicProxy;
public class Zhangsan implements IPerson {
public void findlove() {
System.out.println("张三要求:肤白貌美大长腿!");
}
}
测试代码如下:
package ProxyTest;
import proxy.dynamicProxy.MeiPoProxy;
import proxy.dynamicProxy.Zhangsan;
public class dynamicProxyTest {
public static void main(String[] args) {
MeiPoProxy meiPoProxy = new MeiPoProxy();
meiPoProxy.getInstance(new Zhangsan()).findlove();
}
}
CGlib动态代理的例子:
创建一个MeiPoProxy代理类:
package proxy.dynamicProxy.CglibProxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class MeiPoProxy implements MethodInterceptor{
public Object getInstance(Class<?> clazz){
Enhancer enhancer = new Enhancer();
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("开始");
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("结束");
return result;
}
}
三张这块类可以不用实现任何接口:
package proxy.dynamicProxy.CglibProxy;
public class Zhangsan{
public void findlove() {
System.out.println("找对象要求:肤白貌美大长腿!");
}
}
测试如下:
package ProxyTest;
import proxy.dynamicProxy.CglibProxy.MeiPoProxy;
import proxy.dynamicProxy.CglibProxy.Zhangsan;
public class CglibProxyTest {
public static void main(String[] args) {
MeiPoProxy meipoProxy = new MeiPoProxy();
Zhangsan zhangsan = (Zhangsan) meipoProxy.getInstance(Zhangsan.class);
zhangsan.findlove();
}
}
动态代理和静态代理的区别:
静态代理属于硬编码,不灵活,不能做到适配性,如果需要代理的类很多,就没办法实现代理。动态代理是分为JDK和CGlib两种api方式代理,他们底层实现原理都是在内存中生成一个Proxy的类。JDK是实现了接口的方式,所以需要代理的类必须要实现接口,而CGlib是通过继承的方式,拿到了父类的所有方法属性,所以CGlib可以直接传入类的字节码信息就可以完成代理。Cglib还有一个不足之处就是不能有final修饰的方法。