Java:三种代理模式示例

什么是代理模式?

代理(Proxy)是一种设计模式,为其他对象提供一种代理以控制对这个对象的访问。

代理模式的组成

  • 抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
  • 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
  • 真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。

代理模式的优点

(1).职责清晰

真实的角色就是实现实际的[业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。

(2).代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介的作用和保护了目标对象的作用。

(3).高扩展性

代理模式的关键点是:代理对象与目标对象.代理对象是对目标对象的扩展,并会调用目标对象。

一、静态代理

步骤1:创建接口 Animal.java

复制代码
/**
 * 静态代理步骤1
 *  -创建接口
 * */
public interface Animal {

    void run();
    void eat();

}

步骤2:创建实现类并实现步骤1的接口 AnimalImpl.java

复制代码
/**
 * 静态代理步骤 2
 *  -创建实现类并实现步骤1的接口
 * */
public class AnimalImpl implements Animal{

    @Override
    public void run() {
        System.out.println("猎豹跑的都很快");
    }

    @Override
    public void eat() {
        System.out.println("动物为了生存,一般都喜欢进食");
    }
}

步骤3:创建代理类并实现步骤1的接口 StaticProxy.java

复制代码
/**
 * 静态代理步骤 3
 *  -创建代理类并实现步骤1的接口
 * */
public class StaticProxy implements Animal{

    private Animal animal;// 目标对象

    // 构造函数
    StaticProxy(){}

    StaticProxy(Animal _animal){
        this.animal = _animal;
    }

    @Override
    public void run() {
        System.out.println("事物开始前");
        animal.run();
        System.out.println("事物开始后");
    }

    @Override
    public void eat() {
        System.out.println("事物开始前");
        animal.eat();
        System.out.println("事物开始后");
    }
}

步骤4:实现代理方法:

复制代码
/**
 * 静态代理步骤4
 *  -实现静态代理方法
 * */
public class TestMain {
    /**
     * 总结:
     *
     * 静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现接口或继承相同 的父类
     * 缺点:
     *
     * 因为代理对象需要和被代理对象实现相同的接口或父类,所以会有太多的代理类
     * 一旦接口中增加了方法后,被代理对象和代理对象都需要维护(非常麻烦,不方便)
     * */
    public static void main(String[] args) {
        //1.创建目标对象(通过目标实现类创建目标对象)
        Animal animal = new AnimalImpl();

        //2.创建代理对象(将目标对象传递进代理对象,建立代理关系)
        StaticProxy staticProxy = new StaticProxy(animal);

        //3.执行方法
        staticProxy.run();
        staticProxy.eat();
    }

运行结果:

二、JDK动态代理

步骤1:创建接口 Persion.java

复制代码
/**
 * JDK动态代理步骤1
 *  -创建接口
 * */
public interface Persion {

    void say();

}

步骤2:创建实现类并实现步骤1的接口PersionImpl.java

复制代码
/**
 * JDK动态代理步骤2
 *  -创建实现类并实现步骤1的接口
 * */
public class PersionImpl implements Persion {
    @Override
    public void say() {
        System.out.println("每个人都有说话的权力!");
    }
}

步骤3:创建动态代理类JDKProxy.java

复制代码
/**
 * JDK动态代理步骤3
 *  -创建动态代理类
 * */
public class JDKProxy {

    private Persion persion;// 目标对象

    // 构造函数
    public JDKProxy(Persion _persion){
        this.persion = _persion;
    }


    /**
     *  给目标对象生成代理对象
     *
     * JDK中动态代理类只需要使用java.lang.reflect.Proxy.newProxyInstance方法,该方法需要接收三个参数,完整写法:
     * static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)
     *
     * ClassLoader loader:指定当前目标对象使用类加载器,获取加载器的方法是固定的
     * Class<?>[] interfaces:目标对象实现的接口类型,使用泛型方式确认类型,获取接口类型的方法是固定的
     * InvocationHandler h;事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入
     * */
    public Object getProxyInstance(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),persion.getClass().getInterfaces(),this::invoke);
    }


    /**
     * 生成执行目标对象方法
     * */
    public Object invoke(Object proxy, Method method, Object[] args){
        try{
            System.out.println("开始事务");
            //执行目标对象方法
            Object returnValue = method.invoke(persion, args);
            System.out.println("结束事务");
            return returnValue;
        }catch (Throwable  throwable){
            throwable.getLocalizedMessage();
            return null;
        }

    }
}

步骤4:实现代理方法

复制代码
/**
 * JDK动态代理步骤4
 *  -实现代理方法
 *
 *  测试jdk动态代理
 *      代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理
 *      接口中增加方法时只用在实现类中增加方法,不用修改代理类。
 * */
public class JDKMain {

    public static void main(String[] args) {
        // 目标对象
        Persion persion = new PersionImpl();
        // 【原始的类型 class com.jwt.demo.jdkdl.PersionImpl】
        System.out.println(persion.getClass());

        // 给目标对象,创建代理对象
        Persion jdkProxy = (Persion) new JDKProxy(persion).getProxyInstance();
        // class $JDKProxy   内存中动态生成的代理对象
        System.out.println(jdkProxy.getClass());

        // 执行代理方法
        jdkProxy.say();


    }

}

运行结果:

三、cglib动态代理

步骤1:引入jar包

复制代码
       <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>

步骤2:创建被代理的类UserDao.java

复制代码
public class UserDao{
    public void getUser() {
        System.out.println("cglib动态代理:得到用户信息");
    }
    public void insertUser() {
        System.out.println("cglib动态代理:添加用户");
    }
}

步骤3:创建代理类CglibProxy.java

复制代码
/**
 * cglib动态代理
 *
 * */
public class CglibProxy implements MethodInterceptor {
    //维护目标对象
    private Object target;
    public CglibProxy (Object target) {
        this.target = target;
    }
    //给目标对象创建一个代理对象
    public Object getProxyInstance(){
        //1.工具类
        Enhancer en = new Enhancer();
        //2.设置父类
        en.setSuperclass(target.getClass());
        //3.设置回调函数
        en.setCallback(this);
        //4.创建子类(代理对象)
        return en.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy         
       methodProxy) throws Throwable {
        System.out.println("开始事务...");
        //执行目标对象的方法
        Object returnValue = method.invoke(target, objects);
        System.out.println("提交事务...");
        return returnValue;
    }
}

步骤4:实现代理方法

复制代码
public class CglibProxyMain {
    public static void main(String[] args) {
        //目标对象
        UserDao target = new UserDao();
        System.out.println(target.getClass());
        // 给目标对象,创建代理对象
        UserDao proxy = (UserDao) new Proxy03(target).getProxyInstance();
        System.out.println(proxy.getClass());
        proxy.getUser();//执行的是代理的方法
        proxy.insertUser();
    }
}

运行结果:

相关推荐
seventeennnnn4 分钟前
Java大厂面试真题:谢飞机的技术挑战
java·spring boot·面试·aigc·技术挑战·电商场景·内容社区
wkj00115 分钟前
接口实现类向上转型和向上转型解析
java·开发语言·c#
qqxhb15 分钟前
零基础设计模式——行为型模式 - 观察者模式
java·观察者模式·设计模式·go
寒士obj42 分钟前
类加载的过程
java·开发语言
无名之逆1 小时前
大三自学笔记:探索Hyperlane框架的心路历程
java·开发语言·前端·spring boot·后端·rust·编程
Chuck1sn1 小时前
我把 Cursor AI 整合到 Ruoyi 中,从此让 Java 脚手架脱离人工!
java·vue.js·后端
水木石画室1 小时前
Spring Boot 常用注解面试题深度解析
java·spring boot·后端
hweiyu001 小时前
tomcat指定使用的jdk版本
java·开发语言·tomcat
百锦再1 小时前
.NET 类库开发详细指南c
java·log4j·.net·net·dot
梦境虽美,却不长1 小时前
C语言 学习 宏命令(预处理) 2025年6月9日14:41:39
c语言·开发语言·学习