java设计模式-代理模式

代理模式(proxy)

基本介绍

1、代理模式:为一个对象提供一个替身,一控制对这个对象的访问。即通过代理对象访问目标对象。这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,及扩展目标对象的功能。

2、被代理的对象可以是远程对象、创建开销大的对象或者需要安全控制的对象.

3、代理模式有不同的形式,主要三种静态代理、动态代理(JDK代理,接口代理)和Cglib代理(可以再内存中动态的创建对象,而不需要实现接口,他是属于动态代理的范畴)

4、原理图

1、静态代理

  • Client

1、创建TeacherDaoProxy代理对象

2、创建TeacherDao对象

3、将TeacherDao对象,交给TeacherDaoProxy对象,执行方法

java 复制代码
public interface ITeacherDao {
    //授课方法
    void teacher();
}
@Slf4j
public class TeacherDao implements ITeacherDao {
    @Override
    public void teacher() {
        log.info("老师授课中...");
    }
}
@Slf4j
public class TeacherDaoProxy implements  ITeacherDao{
    //目标对象 通过接口来聚合
    private ITeacherDao target;

    public TeacherDaoProxy(ITeacherDao target) {
        this.target = target;
    }
    @Override
    public void teacher() {
        log.info("开始代理 完成某些操作......");
        target.teacher();
        log.info("提交......");
    }
}
public class Client {
    public static void main(String[] args) {
        //创建目标对象
        TeacherDao teacherDao = new TeacherDao();
        //创建代理对象,同时将被代理对象传递给代理对象
        TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);
        //通过代理对象,调用到被代理对象的方法
        //即:执行的是代理对象的方法,代理对象再去调用目标对象的方法
        teacherDaoProxy.teacher();
    }
}

静态代理优缺点

1、优点:在不修改目标对象的的功能前提下,能通过代理对象对目标对象扩展。

2、缺点:因为代理对象需要和目标对象一样的接口,所以回有很多代理类。

3、一旦接口增加了方法,目标对象与代理对象都要维护。

2、动态代理

动态代理简介

1、代理对象,不许哟啊海鲜接口,但是目标对象要实现接口,否则不能用动态代理。

2、代理对象的额生成,是利用JDK的API,动态的在内存中构建代理对象。

3、动态代理也叫作:JDK代理,接口代理。

JDK中生成代理对象的API

1、代理类所在包:java.lang.reflect.Proxy

2、JDK实现代理只需要使用newProxyInstance方法,但是该方法需要接受三个参数,完整的写法是:

static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

java 复制代码
public interface ITeacherDao {
    //授课方法
    public void teacher();
    public void sayHello(String name);
}
@Slf4j
public class TeacherDao implements ITeacherDao {
    @Override
    public void teacher() {
        log.info("老师授课中...");
    }
    @Override
    public void sayHello(String name) {
        log.info("hello :{}",name);
    }
}
//代理类
@Slf4j
public class ProxyFactory {
    //维护一个目标对象,Object
    private Object target;

    //构造器,对target进行初始化
    public ProxyFactory(Object target) {
        this.target = target;
    }
    public Object getProxyInstance() {
        /**
         *     public static Object newProxyInstance(ClassLoader loader,
         *                                           Class<?>[] interfaces,
         *                                           InvocationHandler h)
         */
        //1、ClassLoader loader:指定当前目标对象中适用的类加载器
        //2、Class<?>[]  interfaces:目标对象实现的接口类型,使用泛型方法确认类型。
        //3、InvocationHandler 事件处理,直行目标对象的方法,会触发事件处理器的方法。

        ClassLoader classLoader = target.getClass().getClassLoader();
        Class<?>[] interfaces = target.getClass().getInterfaces();
        InvocationHandler invocationHandler = (proxy, method, args) -> {
            log.info("jdk代理开始...");
            return method.invoke(target, args);
        };
        return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
    }
}
@Slf4j
public class Client {
    public static void main(String[] args) {
        //创建目标对象
        ITeacherDao target=new TeacherDao();
        //给目标对象,创建代理对象,可以转成ITeacherDao
        ITeacherDao proxyInstance = (ITeacherDao)new ProxyFactory(target).getProxyInstance();
        // proxyInstance=class com.sun.proxy.$Proxy0 内存中动态生成了代理对象
        log.info("proxyInstance={}",proxyInstance.getClass());
        //通过代理对象调用目标对象的方法。
        proxyInstance.teacher();
        proxyInstance.sayHello(" 张三 ");
    }
}

3、CGlib代理

基本介绍

1、静态代理和jdk代理模式都要求目标对象时实现一个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候使用目标对象子类来实现代理也就是-CGlib代理。

2、CGlib代理也叫作子类代理,他是在内存中构建一个子类对象从而实现对目标对象功能扩展,有些书也将Cglib代理归属到动态代理中。

3、Cglib是一个强大的高性能的二代码生成宝,他可以再运行期扩展java类与实现java接口,他管饭的额被许多AOP的框架使用例如Spring AOP,实现方法拦截。

4、在AOP编程中如何使用代理模式

1、目标对象需要实现接口,用JDK代理

2、目标对象不需要实现接口,使用Cglib代理

5、Cglib包的底层是通过使用字节码处理框架ASM来转换字节码并生成新的类。

Cglib代理实现步骤

1、需要的jar包:asm.jar,asm-commons.jar,asm-tree.jar,cglib-2.2.jar

2、在内存中动态构建子类,注意代理的类不能为final,否则报错java.lang.IllegalArgumentException;

3、目标对象的方法如果为final/static,阿么就不会被拦截,即不会执行目标对象外的业务方法,

java 复制代码
public class Client {
    public static void main(String[] args) {
        //创建目标对象
        TeacherDao teacherDao=new TeacherDao();
        //获取到代理对象,并且将目标对象传递给代理对象
        TeacherDao proxyInstance = (TeacherDao)new ProxyFactory(teacherDao).getProxyInstance();
        //执行代理对象的方法,intercept,从而实现对目标对象的调用。
        proxyInstance.teacher();
    }
}
@Slf4j
public class ProxyFactory implements MethodInterceptor {
    //维护一个目标对象
    private Object target;
    //构造器,传入一个被代理的对象
    public ProxyFactory(Object target) {
        this.target = target;
    }
    // 返回一个代理对象: 是target对象的代理对象
    public Object getProxyInstance(){
        //1、创建一个工具类
        Enhancer enhancer=new Enhancer();
        //2、设置父类
        enhancer.setSuperclass(target.getClass());
        //3、设置回调函数(就是他自己)
        enhancer.setCallback(this);
        //4、创建自雷对象,即代理对象
        return enhancer.create();
    }

    @Override
    public Object intercept(Object arg0, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        log.info("Cglib代理模式 ~ 开始");
        Object invoke = method.invoke(target, args);
        log.info("Cglib代理模式 ~ 提交");
        return  invoke;
    }
}
@Slf4j
public class TeacherDao {
    public void teacher(){
        log.info(" 老师授课中, 我是cglib代理,不需要实现接口 ");
    }
}
相关推荐
num_killer1 小时前
小白的Langchain学习
java·python·学习·langchain
期待のcode2 小时前
Java虚拟机的运行模式
java·开发语言·jvm
程序员老徐2 小时前
Tomcat源码分析三(Tomcat请求源码分析)
java·tomcat
a程序小傲2 小时前
京东Java面试被问:动态规划的状态压缩和优化技巧
java·开发语言·mysql·算法·adb·postgresql·深度优先
仙俊红2 小时前
spring的IoC(控制反转)面试题
java·后端·spring
阿湯哥2 小时前
AgentScope Java 集成 Spring AI Alibaba Workflow 完整指南
java·人工智能·spring
小楼v2 小时前
说说常见的限流算法及如何使用Redisson实现多机限流
java·后端·redisson·限流算法
与遨游于天地2 小时前
NIO的三个组件解决三个问题
java·后端·nio
czlczl200209253 小时前
Guava Cache 原理与实战
java·后端·spring
yangminlei3 小时前
Spring 事务探秘:核心机制与应用场景解析
java·spring boot