代理模式

一、代理模式的目的
1.保护目标对象
2.增强目标对象
二、代理模式类型
静态代理、动态代理
三、静态代理
其中一种实现逻辑:通过持有被代理对象的引用,在被代理对象执行之前或者之后添加新的处理逻辑,达到增强被代理对象的效果。

package com.ns.proxy.staticproxy.demo1;

/**
 * 顶层接口(Person)
 */
public interface Person {

    void findLove();
}

package com.ns.proxy.staticproxy.demo1;

/**
 * 被代理对象(目标对象)
 */
public class Son implements Person {

    @Override
    public void findLove() {
        System.out.println("儿子也觉得不小了,该给自己找个对象了");
    }
}

package com.ns.proxy.staticproxy.demo1;

/**
 *  代理类(父亲,帮儿子找对象的)
 *  通过持有Son的引用实现对Son的代理
 */
public class Father implements Person{

    private Son son;

    public Father(Son son){
        this.son = son;
    }

    @Override
    public void findLove() {
        System.out.println("爸爸先给儿子物色个肤白貌美的对象");
        son.findLove();
        System.out.println("儿子同意了,可以开始交往了");
    }
}

package com.ns.proxy.dynamicproxy.jdkproxy;

/**
 * 测试类
 */
public class TestJdkProxy {

    public static void main(String[] args) {
        Person person = (Person) new MeiPoJDKProxy().getInstance(new Customer());
        person.findLove();
    }
}

四、动态代理
动态代理分为两种:
JDK动态代理、Cglib动态代理
主要区别:
1.JDK动态代理是实现了被代理对象的接口,Cglib是继承了被代理对象(具体实现逻辑)
2.JDK和Cglib都是在运行期生成字节码,JDK是直接写class字节码,Cglib使用ASM框架写class字节码,Cglib代理更负责,生成代理类比JDK效率低
3.JDK调用代理类方法,是通过反射机制调用,Cglib是通过FastClass机制直接调用方法,执行效率高
JDK动态代理
(1) 原理:
通过实现InvocationHandler(字节码重组)
1.拿到被代理对象的引用,并且获取到它所有的接口,反射获取
2.JDK Proxy类重新生成一个新的类,同时新的类要实现被代理所实现的所有接口
3.动态生成Java代码,把新加的业务逻辑方法由一定的代码逻辑去调用
4.编译新生成的Java代码.class
5.重新加载到JVM并运行
(2)Demo

package com.ns.proxy.dynamicproxy.jdkproxy;

/**
 * 顶层接口类
 */
public interface Person {

    void findLove();
}

package com.ns.proxy.dynamicproxy.jdkproxy;

/**
 * 被代理对象
 */
public class Customer implements Person {
    @Override
    public void findLove() {
        System.out.println("想找个对象");
    }
}

package com.ns.proxy.dynamicproxy.jdkproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 代理类
 */
public class MeiPoJDKProxy implements InvocationHandler {

    private Object target;

    public Object getInstance(Object target){
        this.target = target;
        Class<?> clazz = target.getClass();
        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object obj = method.invoke(this.target,args);
        after();
        return obj;
    }

    private void before() {
        System.out.println("我是媒婆,我要给你物色对象,已经拿到你的需求");
        System.out.println("开始物色对象");
    }

    private void after() {
        System.out.println("你俩觉得合适的话,就办事吧");
    }
}

package com.ns.proxy.dynamicproxy.jdkproxy;

/**
 * 测试类
 */
public class TestJdkProxy {

    public static void main(String[] args) {
        Person person = (Person) new MeiPoJDKProxy().getInstance(new Customer());
        person.findLove();
    }
}

Cglib动态代理
通过实现MethodInterceptor,重写intercept方法实现动态代理

package com.ns.proxy.dynamicproxy.cglibproxy;

/**
 * Person类,策略的通用接口
 */
public interface Person {

    void findLove();
}

package com.ns.proxy.dynamicproxy.cglibproxy;

/**
 * 客户类,被代理类(实现Person类的目的是为了实现简单的策略)
 */
public class Customer implements Person{

    public void findLove(){
     System.out.println("肤白貌美大长腿");
    }
}

package com.ns.proxy.dynamicproxy.cglibproxy;

/**
 * 妹子类,被代理类(实现Person类的目的是为了实现简单的策略)
 */
public class MeiZi implements Person{
    @Override
    public void findLove() {
        System.out.println("高富帅");
    }
}

package com.ns.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 CglibMeiPoProxy 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 {
        before();
        Object obj = methodProxy.invokeSuper(o,objects);
        after();
        return obj;
    }

    private void after() {
        System.out.println("如何合适的话,准备完事");
    }

    private void before() {
        System.out.println("我是媒婆,我要开始给你物色对象了,已经拿到你的需求");
        System.out.println("开始物色");
    }
}

package com.ns.proxy.dynamicproxy.cglibproxy;

/**
 * 测试类
 */
public class CglibTest {
    public static void main(String[] args) {
        CglibMeiPoProxy cglibMeipoProxy = new CglibMeiPoProxy();
        //策略模式,传入的类不同,走不同的具体实现
//        Person person = (Person)cglibMeipoProxy.getInstance(MeiZi.class);
        Person person = (Person)cglibMeipoProxy.getInstance(Customer.class);
        person.findLove();
    }
}

五、总结
静态代理与动态代理的区别
1.静态代理只能通过手动完成代理操作,如果被代理类增加新的方法,代理类需要同步新增,违背开闭原则
2.动态代理采用运行时动态生成代码的方式,取消了被代理类的扩展限制,符合开闭原则
3.若代理模式要对目标类的增强逻辑扩展,结合策略模式,只需要新增策略类即可完成,无需修改代理类的代码
代理模式的优点
1.代理模式能将代理对象与真实的被调用的目标对象分离
2.一定程度上降低了系统的耦合度,扩展性好
3.可以起到保护目标对象的作用
4.可以对目标对象的功能增强
代理模式的缺点
1.代理模式会造成系统设计中类的数量增加
2.在客户端和目标对象增加一个代理对象,会造成请求速度变慢
3.增加了系统的复杂度
Spring中的代理选择原则
当Bean有实现接口时,Spring就会用jdk的动态代理
当Bean没有实现接口时,Spring就用Cglib

注:该文章内容均为学习过程中的记录,若有与其他大哥的文章雷同,请谅解

希望各位都可以学以致用

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值