设计模式-代理模式-静态代理和动态代理在Java中的使用示例

生活中,最使人疲惫的往往不是道路的遥远,而是心中的郁闷;最使人痛苦的往往不是生活的不幸,而是希望的破灭;最使人颓废的往往不是前途的坎坷,而是自信的丧失;最使人绝望的往往不是挫折的打击,而是心灵的死亡。所以我们要有自己的梦想,让梦想的星光指引着我们走出落漠,走出惆怅,带着我们走进自己的理想。

导读:本篇文章讲解 设计模式-代理模式-静态代理和动态代理在Java中的使用示例,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

场景

代理模式(Proxy Pattern)

租房中介、代理律师、售票黄牛、中介、婚介、经纪人、快递等,都是代理模式的实际体现。

代理模式是指为其他对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象

之间起到中介作用,代理模式属于结构型设计模式。

使用代理模式两个目的:一是保护目标对象,二是增强目标对象。

静态代理

比如,父母为自己的孩子相亲,这个相亲的过程实现如下

顶层接口Person代码实现

package com.ruoyi.demo.designPattern.staticProxy;

/**
 * 人有很多行为,比如下面的谈恋爱、找对象
 */
public interface Person {
    public void findLove();
}

儿子要找对象,实现Son类

package com.ruoyi.demo.designPattern.staticProxy;

public class Son implements Person{
    @Override
    public void findLove() {
        System.out.println("儿子要求:白富美");
    }
}

父亲要帮儿子相亲,实现Father类

package com.ruoyi.demo.designPattern.staticProxy;

public class Father {
    private Son son;
    public Father(Son son){
        this.son = son;
    }
    //获取目标对象的引用
    public void  findLove(){
        System.out.println("父亲帮忙安排相亲");
        this.son.findLove();
        System.out.println("双方同意,确定关系");
    }
}

注意这里:

父亲通过构造方法获取儿子的引用,并且在findLove中进行了增强,给儿子安排了相亲,然后再

促使儿子去谈恋爱,调用findLove方法。

测试代码

package com.ruoyi.demo.designPattern.staticProxy;

public class fatherTest {
    public static void main(String[] args) {
        Father father = new Father(new Son());
        father.findLove();
    }
}

注:

博客:
霸道流氓气质的博客_CSDN博客-C#,架构之路,SpringBoot领域博主
关注公众号
霸道的程序猿
获取编程相关电子书、教程推送与免费下载。

静态代理业务场景举例

看一个实际的业务场景。

在分布式业务中,需要分库分表,分库分表之后使用Java操作时可能需要配置多个数据源。

通过设置数据源路由来动态切换数据源。

创建Order订单类

package com.ruoyi.demo.designPattern.staticProxy;

public class Order {
    private Object orderInfo;
    private Long createTime;
    private String id;

    public Object getOrderInfo() {
        return orderInfo;
    }

    public void setOrderInfo(Object orderInfo) {
        this.orderInfo = orderInfo;
    }

    public Long getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Long createTime) {
        this.createTime = createTime;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}

创建Order持久层操作类

package com.ruoyi.demo.designPattern.staticProxy;

public class OrderDao {
    public int insert(Order order){
        System.out.println("OrderDao创建order成功!");
        return 1;
    }
}

创建IOrderService接口

package com.ruoyi.demo.designPattern.staticProxy;

public interface IOrderService {
    int createOrder(Order order);
}

创建OrderService实现类

package com.ruoyi.demo.designPattern.staticProxy;

public class OrderService implements IOrderService{
    private OrderDao orderDao;
    public OrderService(){
        //如果使用Spring应该是自动注入的,这里为方便,直接在构造方法中初始化
        orderDao = new OrderDao();
    }
    @Override
    public int createOrder(Order order) {
        System.out.println("OrderService 调用orderDao创建订单");
        return orderDao.insert(order);
    }
}

然后进行静态代理,主要完成的功能是:根据订单创建时间自动按年进行分库。

先创建数据源路由对象,使用ThreadLocal的单例实现DynamicDataSourceEntry

package com.ruoyi.demo.designPattern.staticProxy;

//动态切换数据源
public class DynamicDataSourceEntry {
    //默认数据源
    public final static String DEFAULT_SOURCE = null;

    private final static ThreadLocal<String> local = new ThreadLocal<>();

    private DynamicDataSourceEntry(){}

    //清空数据源
    public static void clear(){
        local.remove();
    }

    //获取当前正在使用的数据源名字
    public static String get(){
        return local.get();
    }

    //还原当前切换的数据源
    public static void restore(){
        local.set(DEFAULT_SOURCE);
    }

    //设置已知名字的数据源
    public static void set(String source){
        local.set(source);
    }

    //根据年份动态设置数据源
    public static void set(int year){
        local.set("DB_"+year);
    }
}

创建切换数据源的代理类OrderServiceStaticProxy

package com.ruoyi.demo.designPattern.staticProxy;

import java.text.SimpleDateFormat;
import java.util.Date;

public class OrderServiceStaticProxy implements IOrderService{

    private SimpleDateFormat yearFormat = new SimpleDateFormat("yyyy");

    private IOrderService orderService;

    public OrderServiceStaticProxy(IOrderService orderService){
        this.orderService = orderService;
    }

    @Override
    public int createOrder(Order order) {
        before();
        Long time = order.getCreateTime();
        Integer dbRouter = Integer.valueOf(yearFormat.format(new Date(time)));
        System.out.println("静态代理类自动分配到【DB_"+dbRouter+"】数据源处理数据");
        DynamicDataSourceEntry.set(dbRouter);
        orderService.createOrder(order);
        after();
        return 0;
    }

    private void before(){
        System.out.println("Proxy before method");
    }

    private void after(){
        System.out.println("Proxy after method");
    }
}

来看测试代码

package com.ruoyi.demo.designPattern.staticProxy;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class StaticProxyTest {
    public static void main(String[] args) {
        try {
            Order order = new Order();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
            Date date = sdf.parse("2022/10/29");
            order.setCreateTime(date.getTime());
            IOrderService orderService = new OrderServiceStaticProxy(new OrderService());
            orderService.createOrder(order);
        }catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

运行结果

设计模式-代理模式-静态代理和动态代理在Java中的使用示例

 

动态代理-JDK实现方式

动态代理和静态代理思路基本一致,只不过动态代理功能更加强大,随着业务的扩展适应性更强。

还以上面找对象为例,那么动态代理能适用复杂的业务场景。

不仅包括父亲给儿子找对象,还包括媒婆、婚介所等,所以需要一个更加通用的解决方案。

创建媒婆类

package com.ruoyi.demo.designPattern.jdkDynamicProxy;

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

public class JDKMeipo implements InvocationHandler {

    //被代理的对象,把引用保存下来
    private Object target;
    public  Object getInstance(Object target) throws Exception{
        this.target = target;
        Class<?> clazz = target.getClass();
        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object obj = method.invoke(this.target,args);
        after();
        return obj;
    }

    private void before(){
        System.out.println("我是媒婆,已经确定你的需求,开始给你找对象");
    }

    private void after(){
        System.out.println("合适的话,就在一起吧");
    }
}

创建单身客户类

package com.ruoyi.demo.designPattern.jdkDynamicProxy;

import com.ruoyi.demo.designPattern.staticProxy.Person;

public class Customer implements Person {

    @Override
    public void findLove() {
        System.out.println("高富帅单身优质对象");
    }
}

测试代码

package com.ruoyi.demo.designPattern.jdkDynamicProxy;

import com.ruoyi.demo.designPattern.staticProxy.Person;

public class jdkDynamicProxy {
    public static void main(String[] args) {
        try {
            Person obj = (Person) new JDKMeipo().getInstance(new Customer());
            obj.findLove();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

为加深印象,用JDK动态代理修改上面数据源动态路由的业务

创建动态代理的类

package com.ruoyi.demo.designPattern.jdkDynamicProxy;

import com.ruoyi.demo.designPattern.staticProxy.DynamicDataSourceEntry;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.text.SimpleDateFormat;
import java.util.Date;

public class OrderServiceDynamicProxy implements InvocationHandler {

    private SimpleDateFormat yearFormat = new SimpleDateFormat("yyyy");
    private Object target;
    public Object getInstance(Object target){
        this.target = target;
        Class<?> clazz = target.getClass();
        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before(args[0]);
        Object object = method.invoke(target,args);
        after();
        return object;
    }

    private void before(Object target){
        System.out.println("Proxy before method");
        try {
            Long time = (Long) target.getClass().getMethod("getCreateTime").invoke(target);
            Integer dbRouter = Integer.valueOf(yearFormat.format(new Date(time)));
            System.out.println("动态代理类自动分配到【DB_"+dbRouter+"】数据源处理数据");
            DynamicDataSourceEntry.set(dbRouter);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void after(){
        System.out.println("Proxy after method");
    }
}

测试代码如下

package com.ruoyi.demo.designPattern.jdkDynamicProxy;

import com.ruoyi.demo.designPattern.staticProxy.IOrderService;
import com.ruoyi.demo.designPattern.staticProxy.Order;
import com.ruoyi.demo.designPattern.staticProxy.OrderService;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DyDataDyProTest {
    public static void main(String[] args) {
        Order order = new Order();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
        Date date;
        {
            try {
                date = sdf.parse("2022/10/31");
                order.setCreateTime(date.getTime());
                IOrderService orderService = (IOrderService) new OrderServiceDynamicProxy().getInstance(new OrderService());
                orderService.createOrder(order);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
    }
}

动态代理-CGLib方式

还是 以上面媒婆为例

package com.ruoyi.demo.designPattern.cglibDynamicProxy;


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

import java.lang.reflect.Method;

public class CglibMeipo implements MethodInterceptor {

    public Object getInstance(Class<?> clazz) throws Exception{
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //业务增强
        before();
        Object obj = methodProxy.invokeSuper(o,objects);
        after();
        return obj;
    }

    private void before(){
        System.out.println("我是媒婆:要按照你的要求给你找对象");
    }

    private void after(){
        System.out.println("如果觉得合适你们就谈恋爱吧");
    }
}

创建单身客户类

package com.ruoyi.demo.designPattern.cglibDynamicProxy;

public class Customer {
    public void findLove(){
        System.out.println("白富美");
    }
}

测试代码

package com.ruoyi.demo.designPattern.cglibDynamicProxy;

public class CGlibProxyTest {
    public static void main(String[] args) {
        try {
            Customer obj = (Customer) new CglibMeipo().getInstance(Customer.class);
            obj.findLove();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/135880.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!