五:代理模式详解

动态代理:是指为其他对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用,代理模式属于结构型设计模式。代理分为静态代理和动态代理

1.静态代理

public interface Iperson {
    //找对象
    void findlove();
    //void findwork(String args);
}
public class Zhangsan implements Iperson {
    //找对象,提要求
    @Override
    public void findlove() {
        System.out.println("是个美女就行");
    }
}
//父亲帮儿子相亲,实现
public class ZhangLaosan {
    private Zhangsan zhangsan;
    public ZhangLaosan(Zhangsan zhangsan) {
        this.zhangsan = zhangsan;
    }
    public void findlove() {
        System.out.println("开始帮儿子看女孩子");
        zhangsan.findlove();
        System.out.println("开始交往");
    }
}
public class Test {
    public static void main(String[] args) {
        Zhangsan iperson = new Zhangsan();
        //只能帮儿子找对象
        ZhangLaosan zhangLaosan = new ZhangLaosan(iperson);
        zhangLaosan.findlove();
    }
}

以上是静态代理,父亲帮儿子找对象

下面通过jdk动态代理实现

public class JdkMmeiPo implements InvocationHandler{
    private Iperson target;
    public Iperson getInstace(Iperson target){
        this.target = target;
        Class<?> aClass = target.getClass();
        return (Iperson) Proxy.newProxyInstance(aClass.getClassLoader(),aClass.getInterfaces(),this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object invoke = method.invoke(this.target, args);
        after();
        return invoke;
    }
    private void before() {
        System.out.println("开始----");
    }
    private void after() {
        System.out.println("结束-----");
    }
}
public class JdkProxyTest {
    public static void main(String[] args) {
        JdkMmeiPo jdk = new JdkMmeiPo();
        Iperson zhansan = jdk.getInstace(new Zhangsan());
        zhansan.findlove();
    }
}

如果再想干一件事情,直接加方法即可,JdkMmeiPo类不需要任何改动

public interface Iperson {
    //找对象
    void findlove();
    void findwork();
}
public class Zhangsan implements Iperson {
    //找对象,提要求
    @Override
    public void findlove() {
        System.out.println("是个美女就行");
    }

    @Override
    public void findwork() {
        System.out.println("张三找工作");
    }
}

 

public final class $Proxy0 extends Proxy
    implements Iperson
{

    private static Method m1;
    private static Method m2;
    private static Method m4;
    private static Method m0;
    private static Method m3;

    public $Proxy0(InvocationHandler invocationhandler)
    {
        super(invocationhandler);
    }

    public final boolean equals(Object obj)
    {
        try
        {
            return ((Boolean)super.h.invoke(this, m1, new Object[] {
                obj
            })).booleanValue();
        }
        catch (Error ) { }
        catch (Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final String toString()
    {
        try
        {
            return (String)super.h.invoke(this, m2, null);
        }
        catch (Error ) { }
        catch (Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final void findwork()
    {
        try
        {
            super.h.invoke(this, m4, null);
            return;
        }
        catch (Error ) { }
        catch (Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final int hashCode()
    {
        try
        {
            return ((Integer)super.h.invoke(this, m0, null)).intValue();
        }
        catch (Error ) { }
        catch (Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final void findlove()
    {
        try
        {
            super.h.invoke(this, m3, null);
            return;
        }
        catch (Error ) { }
        catch (Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    static 
    {
        try
        {
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
                Class.forName("java.lang.Object")
            });
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m4 = Class.forName("com.example.test301.jdkproxy.Iperson").getMethod("findwork", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
            m3 = Class.forName("com.example.test301.jdkproxy.Iperson").getMethod("findlove", new Class[0]);
        }
        catch (NoSuchMethodException nosuchmethodexception)
        {
            throw new NoSuchMethodError(nosuchmethodexception.getMessage());
        }
        catch (ClassNotFoundException classnotfoundexception)
        {
            throw new NoClassDefFoundError(classnotfoundexception.getMessage());
        }
    }
}

通过反编译查看源码

JDK动态代理的实现原理
获取被代理对象的引用,并且获取它的所有接口(反射获取)。

JDK Proxy类重新生成一个新的类,实现了被代理类所有接口的方法。

动态生成Java代码,把增强逻辑加入到新生成代码中。

编译生成新的Java代码的class文件。

加载并重新运行新的class,得到类就是全新类。

静态代理,张三父亲只能给张三找媳妇,而动态代理媒婆可以给张三找媳妇,也能帮李四找媳妇

下面看一下另一种cglib代理

public class Zhangsan{
    //找对象,提要求
    public void findlove() {
        System.out.println("是个美女就行");
    }

}
public class CglibMmeiPo implements MethodInterceptor {
    public Object getInstace(Class<?> clazz){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    private void before() {
        System.out.println("开始----");
    }

    private void after() {
        System.out.println("结束-----");
    }


    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before();
        Object o1 = methodProxy.invokeSuper(o, objects);
        after();
        return o1;
    }
}
public class CglibTest {
    public static void main(String[] args) {
        CglibMmeiPo cglib = new CglibMmeiPo();
        Zhangsan instace = (Zhangsan)cglib.getInstace(Zhangsan.class);
        instace.findlove();
    }
}

JDK是采用读取接口的信息
CGLib覆盖父类方法
目的:都是生成一个新的类,去实现增强代码逻辑的功能

JDK Proxy 对于用户而言,必须要有一个接口实现,目标类相对来说复杂
 CGLib 可以代理任意一个普通的类,没有任何要求

CGLib 生成代理逻辑更复杂,效率,调用效率更高,生成一个包含了所有的逻辑的FastClass,不再需要反射调用
JDK Proxy生成代理的逻辑简单,执行效率相对要低,每次都要反射动态调用

CGLib 有个坑,CGLib不能代理final的方法

代理模式的优缺点

代理模式具有以下优点:

(1)代理模式能将代理对象与真实被调用目标对象分离。

(2)在一定程度上降低了系统的耦合性,扩展性好。

(3)可以起到保护目标对象的作用。

(4)可以增强目标对象的功能。

缺点:

(1)代理模式会造成系统设计中类的数量增加。

(2)在客户端和目标对象中增加一个代理对象,会导致请求处理速度变慢。

(3)增加了系统的复杂度。

Spring中的代理选择原则

(1)当Bean有实现接口时,Spring就会用JDK动态代理。

(2)当Bean没有实现接口时,Spring会选择CGLib代理。

(3)Spring可以通过配置强制使用CGLib代理,只需在Spring的配置文件中加入如下代码

<aop:aspectj-autoproxy proxy-target-class="true"/>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值