JAVA【设计模式】代理模式(proxy)

一、基本介绍

1、为一个对象提供一个替身,以控制对这个对象的访问。即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能
2、代理模式有不同的形式, 主要有静态代理和动态代理动态代理分为JDK代理和 Cglib代理 (可以在内存动态的创建对象,而不需要实现接口)。
在这里插入图片描述

二、分类

2.1 静态代理

静态代理在使用时,需要定义接口或者父类,被代理对象(即目标对象)与代理对象一起实现相同的接口或者是继承相同父类

例如:读大学的时候,大家都有遇到过这样的事情吧。某一天你走在校园的林荫小道上,路过了一个漂亮的女生,这时你的内心波涛汹涌,暗暗发誓她一定要成为你的女朋友。但是你直接上去联系或者表达好感这样会有点太唐突了,于是你迂回战术,先跟她的室友闺女拉近关系,让她帮忙送礼物给你的女神,然后。。。
在这里插入图片描述

首先得出现一个美女:BeautifulGirl

package com.qf.staticproxy;

public class BeautifulGirl {
    private String name;

    public BeautifulGirl() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

然后是抽象主题,送礼物:SendGift

package com.qf.staticproxy;

public interface SendGift {
    void sendCard(String name);
    void sendFlower(String name);
    void sendMessage(String name);
}

你小子准备好礼物:You

package com.qf.staticproxy;

public class You implements SendGift {
    @Override
    public void sendCard(String name) {
        System.out.println(name+"送你一个卡片");
    }

    @Override
    public void sendFlower(String name) {
        System.out.println(name+"送你一束花");
    }

    @Override
    public void sendMessage(String name) {
        System.out.println(name+"送你一束花");
    }
}

她得室友闺蜜(代理对象)负责送礼物:HerTeam

package com.qf.staticproxy;

public class HerTeam implements SendGift{

    @Override
    public void sendCard(String name) { new You().sendCard(name); }

    @Override
    public void sendFlower(String name) {
        new You().sendFlower(name);
    }

    @Override
    public void sendMessage(String name) {
        new You().sendMessage(name);
    }
}

最终礼物是成功送了出去,你也捕获到你女神的芳心了。。。

package com.qf.staticproxy;

public class Test {
    public static void main(String[] args) {
        BeautifulGirl girl=new BeautifulGirl();
        girl.setName("小甜甜");

        HerTeam herTeam=new HerTeam();
        herTeam.sendCard(girl.getName());
        herTeam.sendFlower(girl.getName());
        herTeam.sendMessage(girl.getName());
    }
}

运行结果
小甜甜送你一个卡片
小甜甜送你一束花
小甜甜送你一束花

总结:
优点:体会到了代理模式的好处,一定的程度上降低了系统的耦合度,保护了被代理对象
缺点:一旦新增了接口,就要再次维护代理对象和被代理对象

2.2 jdk动态代理

基于jdk的反射机制,在java.lang.reflect.Proxy下面
通过调用newProxyInstance方法得到代理对象,前提是要实现接口newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
例如:每个男人都有信仰,都希望成为超人,拯救地球维护世界和平,但是归根结底还是人类,需要饮食。。。

抽象主题,信仰,吃饭:Man

package com.qf.dynimicproxy;

public interface Man {
    /**
     * 信仰
     * @return
     */
    String getBelief();


    /**
     * 吃东西
     * @param name
     */
    void eat(String name);
}

有思想需要饱腹一日三餐的人类:Human

package com.qf.dynimicproxy;

public class Human implements Man{
    @Override
    public String getBelief() {
        return "I believe i can fly";
    }

    @Override
    public void eat(String name) {
        System.out.println("吃:"+name);
    }
}

基于jdk的动态代理,获取代理对象:ProxyFactory

package com.qf.dynimicproxy;

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

public class ProxyFactory {

    public static Object getProxyInstance(Object obj){  //被代理的对象
        MyInvocationHandler myInvocationHandler=new MyInvocationHandler();
        myInvocationHandler.bind(obj);
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),myInvocationHandler);
    }
}

class MyInvocationHandler implements InvocationHandler {
    private Object obj;
    public void bind(Object obj){
        this.obj=obj;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = method.invoke(obj, args);
        return result;

    }
}

测试运行:ProxyTest

package com.qf.dynimicproxy;


public class ProxyTest {
    public static void main(String[] args) throws NoSuchMethodException {
        Human human=new Human();
        Man proxyInstance = (Man) ProxyFactory.getProxyInstance(human);
        String belief = proxyInstance.getBelief();
        System.out.println(belief);
        proxyInstance.eat("小火锅");

    }
}

运行结果
I believe i can fly
吃:小火锅
总结:
特点:不用每次都像静态代理那样,生成代理对象了,只需要实现接口即可获得

2.3 cglib动态代理

Cglib代理也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能扩展, 有些书也将Cglib代理归属到动态代理。Cglib包的底层是通过使用字节码处理框架ASM来转换字节码并生成新的类。

注意:使用前可以下载cglib的官方jar包,更方便的方式直接导入maven依赖
在这里插入图片描述

 <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
 </dependency>

例如:生活中我们常常需要找房子,这时我们通过房产中介就能很快的找到房子,我们只需要付定金就行了

我,需要找房子,我只要付钱就好了:Person

package com.qf.cglib;

public class Person {
    public void rentHouse(){
        System.out.println("付定金");
    }
}

基于cglib的动态代理,获取代理对象:ProxyUtils

package com.qf.cglib;

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 ProxyUtils implements MethodInterceptor {
    private Object target;
    public  Object createProxyInstance(Object target){
        this.target=target;
        //创建一个工具类
        Enhancer enhancer=new Enhancer();
        //设置父类
        enhancer.setSuperclass(target.getClass());
        //设置回调函数
        enhancer.setCallback(this);
        //创建子类
        return enhancer.create();
    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("代理对象在帮忙找房子");
        Object result = method.invoke(target, objects);
        return result;
    }
}

代理测试:ProxyTest

package com.qf.cglib;

import com.qf.staticproxy.You;

public class ProxyTest {
    public static void main(String[] args) {
        Person person=new Person();
        Person proxyInstance = (Person) new ProxyUtils().createProxyInstance(person);
        proxyInstance.rentHouse();
    }
}

运行结果:
代理对象在帮忙找房子
付定金
总结:
特点:cglib是基于创建子类对象而产生的,不用像静态代理和jdk代理需要实现定义接口
在AOP编程中如何选择代理模式:
目标对象需要实现接口,用JDK代理
目标对象不需要实现接口,用Cglib代理

posted @ 2022-08-30 22:40  雾托邦  阅读(269)  评论(0编辑  收藏  举报