代理模式(静态和动态)

  • 代理模式:为另一个对象提供一个替身或占位符,以便于控制对这个对象的访问

    • 静态代理:

      就是将一些在方法中重复的功能提取出来,通过一个专门的类去封装,在具体类中需要的时候就用那个专门的类的对象去调用

    • 动态代理:

      原理和静态代理差不多,只是用了一个反射的接口,去调用一些方法方便进行动态调度

动态代理的步骤就是:

先把代理类实例化,再实例化被代理类,将被代理类的对象传到代理类的方法中,因为是Object类型,所以需要转型再输出那个方法

在这里插入图片描述

在这里插入图片描述

静态代理

package com.carl.agent;

/**
 * @Version 1.0.0
 * @author carl蔡先生
 * @Date 2022/10/03
 * @Description 租房
 */
public interface RentHouse {

    /**
     * 租房流程
     */
    void rent();
}
package com.carl.agent;

/**
 * @Version 1.0.0
 *
 * @author carl蔡先生
 * @Date 2022/10/03
 * @Description 房东--要租房
 */
public class Landlord implements RentHouse {
    @Override
    public void rent() {
        System.out.println("三室一厅,独厨独卫,家具齐全!价格面议");
    }
}
package com.carl.agent;


/**
 * @Version 1.0.0
 *
 * @author carl蔡先生
 * @Date 2022/10/03
 * @Description 静态代理
 */
public class StaticProxy {
    private RentHouse rentHouse;
    public StaticProxy(){
    }
    public StaticProxy(RentHouse rentHouse){
        this.rentHouse = rentHouse;
    }
    public void rent(){
        rentHouse.rent();
        System.out.println("中介费用为房价的一半!");
    }
}
@Test
public void testStaticAgent(){
    //租房直接找房东
    RentHouse rentHouse=new Landlord();
    //办理租房流程
    rentHouse.rent();
    //找中介租房子
    StaticProxy staticProxy=new StaticProxy(rentHouse);
    //中介给你办理租房流程
    staticProxy.rent();

}

代理的好处

  • 可以使真实角色的操作更加纯粹,不用关注一些公共的业务

  • 公共的业务交给代理角色,实现业务的分工

  • 公共业务发生扩展的时候,方便集中管理

缺点:

  • 一个真实角色就会产生一个代理角色,代码量增加,开发效率变低

例如:

UserService作为抽象角色,UserServiceImpl作为一个真实角色,需要每次访问该业务类中的方式的时候,都要做权限判断,判断权限是否满足要求

这个时候使用代理角色,调用方法时,都统一进行权限管理,这样权限判断的业务和查询User表的业务就分离了,互不影响。当UserServiceImpl增加一些业务,也可以通过代理,增加权限管理的业务,统一集中管理

这就是AOP的逻辑

动态代理

动态代理和静态代理的角色一致

动态代理的两大类

  • 基于接口的动态代理(JDK动态代理)

  • 基于类的动态代理(CGlib动态代理)

  • java字节码实现:javasist

Proxy类和InvocationHandle类

Proxy类

Proxy提供了创建动态代理类和实例的静态方法(newProxyInstance())

常用方法

  • getInvocationHandler(Object proxy):返回指定代理实例的调用处理程序

  • getProxyClass(ClassLoader loader,类<?>…interfaces):给出类加载器和接口的代理类

  • isProxyClass():如果当且仅当使用getProxyClass方法或newProxyInstance方法将指定的类动态生成代理类时,返回true

  • newProxyInstance(ClassLoader loader,类<?>[] interfaces,InvocationHandler h):返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序

JDK提供了两种方式获取动态代理类的实例:

InvocationHandler handler = new MyInvocationHandler(...);
Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).newInstance(handler); 
/**
 * 获取代理
 * @return {@link Object }
 */
public Object getProxy() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
    /*
     * 第一个参数:this.getClass().getClassLoader(),使用handler对象的classLoader加载代理对象
     * 第二个参数:handler.getClass().getInterfaces(),为代理类提供真实对象的接口,便于调用接口中的所有方法
     * 第三个参数:this,InvocationHandler对象
     */
    return Proxy.newProxyInstance(this.getClass().getClassLoader(), handler.getClass().getInterfaces(),this);
}
InvocationHandler类

InvocationHandler类是被代理实例调用处理程序的接口

Object invoke(Object proxy, Method method, Object[] args):通过反射获取被代理类的示例

proxy:代理类代理的真实对象

method:通过反射获取到的需要调用某个对象的方法

args:指代代理对象方法的传递参数

在invoke对象中,调用被代理对象的处理程序,并可以进行增强,具体实现如下:

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Object result = method.invoke(handler, args);
    return result;
}

动态代理具体实现步骤:

package com.carl.proxy.dynamic;

/**
 * @Version 1.0.0
 *
 * @author carl蔡先生
 * @Date 2022/10/03
 * @Description 租房
 */
public interface RentHouse {

    /**
     * 租金
     */
    void rent();
}
package com.carl.proxy.dynamic;

/**
 * @Version 1.0.0
 *
 * @author carl蔡先生
 * @Date 2022/10/03
 * @Description 房东--要租房
 */
public class Landlord implements RentHouse {
    @Override
    public void rent() {
        System.out.println("三室一厅,独厨独卫,家具齐全!价格面议");
    }
}
package com.carl.proxy.dynamic;

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

/**
 * @Version 1.0.0
 * @see InvocationHandler
 * @author carl蔡先生
 * @Date 2022/10/03
 * @Description 动态代理--必须实现InvocationHandler接口
 */
public class DynamicProxy implements InvocationHandler {
        /**
         * 被代理对象
         */
        private RentHouse rentHouse;

        public void setRentHouse(RentHouse rentHouse) {
                this.rentHouse = rentHouse;
        }
        /**
         * 被代理对象的处理程序
         * @param proxy 代理对象
         * @param method 方法
         * @param args 参数
         * @throws Throwable 抛出最高异常
         * @return {@link Object }
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //前后增加操作
                lookHouse();
                Object result = method.invoke(rentHouse, args);
                fare();
                return result;
        }

        /**
         * 获取代理类
         * @return {@link Object }
         */
        public Object getProxy(){
                return Proxy.newProxyInstance(this.getClass().getClassLoader(), rentHouse.getClass().getInterfaces(),this);
        }

        public void lookHouse(){
                System.out.println("中介带看房源!");
        }
        public void fare(){
                System.out.println("中介收中介费!");
        }
}
package com.carl.proxy.util;

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

/**
 * @Version 1.0.0
 * @see InvocationHandler
 * @author carl蔡先生
 * @Date 2022/10/04
 * @Description 通用代理调用处理程序
 */
public class ProxyInvocationHandler implements InvocationHandler {
    /**
     * @see Object
     * 被代理对象
     */
    private Object handler;

    public ProxyInvocationHandler() {
    }
    public ProxyInvocationHandler(Object handler) {
        this.handler = handler;
    }
    /**
     * 获取代理
     * @return {@link Object }
     */
    public Object getProxy() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        /*
         * 第一个参数:this.getClass().getClassLoader(),使用handler对象的classLoader加载代理对象
         * 第二个参数:handler.getClass().getInterfaces(),为代理类提供真实对象的接口,便于调用接口中的所有方法
         * 第三个参数:this,InvocationHandler对象
         */
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), handler.getClass().getInterfaces(),this);
    }

    /**
     * @param proxy 代理类
     * @param method 方法
     * @param args 参数
     * @throws Throwable 抛出异常
     * @return {@link Object }
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = method.invoke(handler, args);
        return result;
    }
}
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Carl·杰尼龟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值