设计模式之代理模式(静态代理、动态代理实现)

前言

 

代理模式是软件设计中常用的设计模式,顾名思义,代理模式是对具体类的一种代理实现的思路,将具体的实现类和客户端调用的类隔离开,通过创建代理类来实现具体被代理对象的功能方法。主要的实现方式有简单的静态代理、动态代理,spring的aop就是典型的动态代理实现,本篇文章将针对代理的常见实现方式进行详细的讲解和编码实现。对每个编码demo进行可执行的演示。

一、静态代理

  • 类结构和设计场景

静态代理的实现,由抽象接口、被代理对象、代理对象三部分实现,被代理对象和代理对象分别实现了抽象接口的实现方法。代理对象实现构造方法,入参传入具体的被代理对象。客户端调用的时候通过创建代理对象,并传入具体的被代理对象来获取具体对象的功能方法实现。

  • 编码实现

抽象接口Movable

package com.czing.designpatterns.proxy.staticproxy;

/**
 * @Description
 * 被代理的对象,可移动的事物
 * @Author wangchengzhi
 * @Date 2023/5/21 8:18
 */
public interface Movable {
    void move();
}

被代理对象CarMove

package com.czing.designpatterns.proxy.staticproxy;

/**
 * @Description
 * 具体被代理的对象
 * @Author wangchengzhi
 * @Date 2023/5/21 8:20
 */
public class CarMove implements Movable {
    @Override
    public void move() {
        System.out.println("汽车移动wuwuwu~~~~");
    }
}

代理对象CarMoveLogProxy

package com.czing.designpatterns.proxy.staticproxy;

/**
 * @Description
 * 静态代理就是  代理和被代理对象继承相同的接口
 * 然后客户端调用的时候  调用代理的方法,构造方法传入的是具体的被代理对象
 * @Author wangchengzhi
 * @Date 2023/5/21 8:27
 */
public class CarMoveLogProxy implements Movable {
    Movable carMove;

    public CarMoveLogProxy(Movable carMove) {
        this.carMove = carMove;
    }
    @Override
    public void move() {
        System.out.println("汽车启动~~~~");
        carMove.move();
        System.out.println("汽车停止~~~~");
    }
}

测试验证方法:

package com.czing.designpatterns.proxy.staticproxy;

/**
 * @Description TODO
 * @Author wangchengzhi
 * @Date 2023/5/21 8:29
 */
public class Main {

    public static void main(String[] args) {
        CarMoveLogProxy logProxy = new CarMoveLogProxy(new CarMove());
        logProxy.move();
    }
}

二、动态代理

  • 类结构和设计场景

动态代理的实现,由抽象接口、被代理对象、动态代理类InvocationHandler三部分实现,被代理对抽象接口的实现方法。代理对象实现了构造方法,入参传入具体的被代理对象,且实现了InvocationHandler的invoke方法,客户端调用的时候通过创建代理对象,并传入具体的被代理对象来获取具体对象的功能方法实现。

  • 编码实现

设置保存动态代理类生成的class到本地的参数

//JDk的动态代理类生成的class文件保存到本地(注意JDK的版本不同)
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
或
System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles","true");

抽象接口Movable

package com.czing.designpatterns.proxy.dynamicproxy;

/**
 * @Description
 * 被代理的对象,可移动的事物
 * @Author wangchengzhi
 * @Date 2023/5/21 8:18
 */
public interface Movable {
    void move();
}

被代理对象CarMove和PlanMove

package com.czing.designpatterns.proxy.dynamicproxy;

/**
 * @Description
 * 具体被代理的对象
 * @Author wangchengzhi
 * @Date 2023/5/21 8:20
 */
public class CarMove implements Movable {
    @Override
    public void move() {
        System.out.println("汽车移动wuwuwu~~~~");
    }


}

package com.czing.designpatterns.proxy.dynamicproxy;

/**
 * @Description
 * 具体被代理的对象
 * @Author wangchengzhi
 * @Date 2023/5/21 8:20
 */
public class PlanMove implements Movable {
    @Override
    public void move() {
        System.out.println("飞机起飞wuwuwu~~~~");
    }


}

动态代理类MoveLogHander

package com.czing.designpatterns.proxy.dynamicproxy;

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

/**
 * @Description
 * 动态代理类
 * @Author wangchengzhi
 * @Date 2023/5/21 12:35
 */
public class MoveLogHander implements InvocationHandler {
    Movable move;

    public MoveLogHander(Movable move) {
        this.move = move;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("method " + method.getName() + " start..");
        //调用方法传入的参数args
        Object o = method.invoke(move, args);
        System.out.println("method " + method.getName() + " end!");
        return o;
    }
}

测试验证

package com.czing.designpatterns.proxy.dynamicproxy;


import java.lang.reflect.Proxy;

/**
 * @Description
 * 创建动态的代理类使用JDK的方式
 * Proxy.newProxyInstance创建对应的三个实体参数
 * 1、获取代理类的具体类加载信息
 * 2、被代理的对象
 * 3、动态代理类传入的具体被代理对象,invoke方法执行的就是该对象的invok方法
 * @Author wangchengzhi
 * @Date 2023/5/21 8:29
 */
public class Main {

    public static void main(String[] args) {
        //JDk的动态代理类生成的class文件保存到本地
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
        //动态创建汽车的代理类
        Movable m = (Movable)Proxy.newProxyInstance(MoveLogHander.class.getClassLoader(),
                new Class[]{Movable.class},
                new MoveLogHander(new CarMove()));
        m.move();
        //动态创建飞机的代理类
        Movable m1 = (Movable)Proxy.newProxyInstance(MoveLogHander.class.getClassLoader(),
                new Class[]{Movable.class},
                new MoveLogHander(new PlanMove()));
        m1.move();


    }
}

三、cglib实现动态代理

  • 类结构和设计场景

cglib的实现方式没有具体的代理类,只需要一个具体的代理对象和实现了MethodInterceptor的动态代理生成类,调用的时候Enhancer设置具体的参数信息类实现动态代理类的创建

  • 编码实现

pom文件增加cglib的依赖

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

被代理对象CarMove

package com.czing.designpatterns.proxy.cglib;

/**
 * @Description
 * 具体对象
 * @Author wangchengzhi
 * @Date 2023/5/21 8:20
 */
public class CarMove{
    public void move() {
        System.out.println("汽车移动wuwuwu~~~~");
    }


}

代理创建类LogMethodInterceptor

package com.czing.designpatterns.proxy.cglib;

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @Description TODO
 * @Author wangchengzhi
 * @Date 2023/5/21 13:33
 */
public class LogMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println(o.getClass().getSuperclass().getName());
        System.out.println("before");
        Object result = null;
        result = methodProxy.invokeSuper(o, objects);
        System.out.println("after");
        return result;
    }
}

 测试验证

package com.czing.designpatterns.proxy.cglib;


import org.springframework.cglib.proxy.Enhancer;


/**
 * @Description
 * 创建需要代理的具体对象,直接用cglib实现,不再需要代理类
 * @Author wangchengzhi
 * @Date 2023/5/21 8:29
 */
public class Main {

    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(CarMove.class);
        enhancer.setCallback(new LogMethodInterceptor());
        CarMove car = (CarMove)enhancer.create();
        car.move();
    }
}

四、aop注解实现动态代理

  • 类结构和设计场景

spring的aop可以通过注解的方式实现动态代理类生成,具体的代理对象,动态代理类切面的方式在具体代理对象的点或者面通过切入的方式实现具体的逻辑功能,需要引入aspect依赖和加载文件

  • 编码实现

app_auto.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
    <aop:aspectj-autoproxy/>
    <bean id="carMove" class="com.czing.designpatterns.proxy.aop.CarMove"/>
    <bean id="logProxy" class="com.czing.designpatterns.proxy.aop.LogProxy"/>
</beans>

pom依赖

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
</dependency>

被代理对象 CarMove

package com.czing.designpatterns.proxy.aop;

import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

/**
 * @Description
 * 具体对象
 * @Author wangchengzhi
 * @Date 2023/5/21 8:20
 */
@Component
public class CarMove{
    @Bean
    public void move() {
        System.out.println("汽车移动wuwuwu~~~~");
    }


}

aop切面实现动态代理类LogProxy

package com.czing.designpatterns.proxy.aop;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @Description TODO
 * @Author wangchengzhi
 * @Date 2023/5/21 13:33
 */
@Aspect
public class LogProxy {
    @Before("execution (void com.czing.designpatterns.proxy.aop.CarMove.move())")
    public void before() {
        System.out.println("method start.." + System.currentTimeMillis());
    }

    @After("execution (void com.czing.designpatterns.proxy.aop.CarMove.move())")
    public void after() {
        System.out.println("method stop.." + System.currentTimeMillis());
    }
}

 测试验证

package com.czing.designpatterns.proxy.aop;


import org.springframework.cglib.proxy.Enhancer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


/**
 * @Description
 * aop切面编程的思想实现动态代理
 * @Author wangchengzhi
 * @Date 2023/5/21 8:29
 */
public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("app_auto.xml");
        CarMove carMove = (CarMove)context.getBean("carMove");
        carMove.move();
    }
}
 

 结语

本篇尽量详尽的分享了代理模式的几种具体编码实现和理解思路,aop是spring很关键的一种设计思想,希望这次的demo编写能够对你的理解有所帮助,其他的切面实现后期会有专门文章分享,欢迎分享交流,但愿本文对您的学习有所帮助。


                
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值