Java设计模式之代理模式

代理模式

代理模式是常用的结构型设计模式之一,当无法直接访问某个对象或访问某个对象存在困难 时可以通过一个代理对象来间接访问。

角色作用备注
抽象角色声明真实对象和代理对象的共同接口。
代理角色代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能够代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
抽象角色代理角色所代表的真实对象,是我们最终要引用的对象。

一、静态代理

静态代理:代码编译时就确定了被代理的类是哪一个;
公司一般都会有法律顾问 这个是在打官司之前就存在的类似于我们的静态代理。

1.1 声明一个接口类

package com.xuanwu.demo.service;

/**
 * 
 * 静态代理:接口类
 *    定义业务接口OrderService,其中含有抽象方法payOrder()
 */
public interface OrderService {

    String payOrder();
}

1.2 声明一个接口类OrderServiceImpl

定义目标类OrderServiceImpl,该类实现了业务接口。在对接口方法的实现上,只实现主订单支付即可。这个方法称为目标方法。

package com.xuanwu.demo.service.impl;

import com.xuanwu.demo.service.OrderService;
import lombok.extern.slf4j.Slf4j;

/**
 * 静态代理:目标类
 * 定义目标类OrderServiceImpl,该类实现了业务接口。在对接口方法的实现上,只实现主订单支付即可。这个方法称为目标方法。
 */
@Slf4j
public class OrderServiceImpl implements OrderService {
    /**
     * 目标方法
     * @return
     */
    @Override
    public String payOrder() {
        log.info(">>>>执行订单支付业务<<<<");
        return "订单支付结果";
    }
}

1.3 定义静态代理类

package com.xuanwu.demo.proxy;

import com.xuanwu.demo.service.OrderService;
import lombok.extern.slf4j.Slf4j;

/**
 * 静态代理----代理类
 * 定义代理类OrderProxy。这个类要实现OrderService接口。并且该代理类要将接口对象作为一个成员变量,还要定义一个带参的构造器,这个参数为接口对象。目的是,将目标对象引入代理类,以便代理类调用目标类的目标方法。
 */
@Slf4j
public class OrderProxy implements OrderService {
    private OrderService target;

    /**
     * 静态代理----代理类无参构造器
     */
    public OrderProxy(){

    }
    /**
     * 静态代理----代理类带一个参数构造器
     * @param target
     */
    public OrderProxy(OrderService target) {
        this.target = target;
    }

    /**
     * 静态代理----订单支付业务接口
     * @return
     */
    @Override
    public String payOrder() {
        //静态代理----此处是对目标类的增强
        log.info(">>>订单支付前信息校验<<<");
        String res= target.payOrder();
        log.info(">>>订单支付后消息推送<<<");
        return res;
    }
}

1.4 定义测试类

/**
 * 静态代理测试类
 */
public class StaticProxyTest {
    public static void main(String[] args) {
        //创建目标对象
        OrderService target=new OrderServiceImpl();

        //创建代理对象,并使用目标对象初始化
        OrderProxy proxy=new OrderProxy(target);
        //此时执行的内容就是对目标对象增强过得内容
        proxy.payOrder();

    }
}

1.5 运行结果

运行结果

二、动态态代理

动态代理类似于普通当事人与聘请的律师间的关系。律师是在“官司”发生后,才由当事人聘请的。即代理关系是在“官司”发生后才确立的

2.1 jdk动态代理

JDK动态代理是基于接口的代理,JDK动态代理的本质是两级代理,即代理类代理了InvocationHandler,而InvocationHandler又代理了实例类,只要给InvocationHandler声明了实例类所实现的接口,InvocationHandler就可自动实现,不用我们再手动添加。

2.1.1 jdk动态代理:接口类
package com.xuanwu.service;

/**
 * 
 * 动态代理:接口类
 *    定义业务接口OrderService,其中含有方法payOrder()
 */
public interface OrderService {

    String payOrder();
}

2.1.2 jdk动态代理:接口类实现类
package com.xuanwu.service.impl;

import com.xuanwu.service.OrderService;
import lombok.extern.slf4j.Slf4j;

/**
 * 动态代理:目标类
 * 定义目标类OrderServiceImpl,该类实现了业务接口。在对接口方法的实现上,只实现主订单支付即可。这个方法称为目标方法。
 */
@Slf4j
public class OrderServiceImpl implements OrderService {
    /**
     * 目标方法
     * @return
     */
    @Override
    public String payOrder() {
        log.info(">>>>执行订单支付业务<<<<");
        return "订单支付结果";
    }
}
2.1.3 jdk动态代理:定义主业务增强逻辑类
package com.xuanwu.jdk.demo;

import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
**
 * 定义主业务增强逻辑类OrderServiceInvocationHandler,该类需实现接口InvocationHandler。
 * 在该类中定义一个Object类型的成员变量,还要定义一个带参的构造器,这个参数为Object对象。目的是,将目标对象引入该类,以便通过反射调用目标方法。
 * 当然,也可以将这个属性定义为IAccount接口类型,但,最好不要这样做,最好将其定义为Object。
 * 因为,这样这个主业务增强逻辑可以适用于本项目中的任何类型的目标类,而不仅仅拘泥于某一个类
 *
 */
@Slf4j
public class OrderServiceInvocationHandler  implements InvocationHandler {
    // 目标对象
    private Object target;

    public OrderServiceInvocationHandler(Object target) {
        this.target = target;
    }

    /**
     *
     * @param proxy 代表生成的代理对象
     * @param method 代表目标方法
     * @param args 代表目标方法的参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //----此处是对目标类的增强
        log.info(">>>订单支付前信息校验<<<");

        //无论主业务方法有无参数,有无返回值,这种写法都可以兼顾到
        Object obj = method.invoke(target, args);

        log.info(">>>订单支付后消息推送<<<");

        return obj;
    }
}
2.1.4 测试类
package com.xuanwu.jdk.demo;

import com.xuanwu.service.OrderService;
import com.xuanwu.service.impl.OrderServiceImpl;
import java.lang.reflect.Proxy;


public class TestJdkProxy {
    public static void main(String[] args) {
        //创建目标对象
        OrderService target=new OrderServiceImpl();

        //创建代理对象,并使用目标对象初始化
        OrderService  service=(OrderService) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),//目标类的类加载器
                target.getClass().getInterfaces(), //目标类所实现的接口
                new OrderServiceInvocationHandler(target)) ; //增强业务逻辑


        service.payOrder();

    }
}

运行结果:

10:06:49.852 [main] INFO com.xuanwu.jdk.demo.OrderServiceInvocationHandler - >>>订单支付前信息校验<<<
10:06:49.854 [main] INFO com.xuanwu.service.impl.OrderServiceImpl - >>>>执行订单支付业务<<<<
10:06:49.855 [main] INFO com.xuanwu.jdk.demo.OrderServiceInvocationHandler - >>>订单支付后消息推送<<<

Process finished with exit code 0

2.2 cglib动态代理

Cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理

2.2.1 动态代理目标类
package com.xuanwu.service.impl;

import lombok.extern.slf4j.Slf4j;

/**
 * 动态代理之CGlib动态代理目标类
 */
@Slf4j
public class OrderServiceImplCglib {

    /**
     * 动态代理之CGlib动态代理----目标方法
     */
    public String payOrder() {
        log.info(">>>>执行订单支付业务<<<<");
        return "订单支付结果";
    }

    /**
     * 动态代理之CGlib动态代理----非目标方法
     */
    public String queryOrder() {

        log.info(">>>>执行订单查询业务<<<<");
        return "执行订单查询结果";
    }
}

2.2.2 CGlib的动态代理的工厂类
package com.xuanwu.cglib.demo;


import com.xuanwu.service.impl.OrderServiceImplCglib;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

/**
 * CGlib的动态代理的工厂类
 *
 *
 */
public class OrderServiceCglibProxyFactory implements MethodInterceptor {
    // 1.申明目标类的成员变量,并创建以目标对象为参数的构造器,用于接收目标对象

    private OrderServiceImplCglib target;

    // 2. 使用构造方法 实例化目标对象
    public OrderServiceCglibProxyFactory() {

        this.target = new OrderServiceImplCglib();
    }

    public OrderServiceImplCglib createProxy() {
        // 创建增强器对象
        Enhancer enhancer = new Enhancer();
        // 初始化增强器:指定目标类即父类
        enhancer.setSuperclass(OrderServiceImplCglib.class);
        // 初始化增强器:设置回调接口对象
        enhancer.setCallback(this);
        //使用增强类创建代理对象
        return (OrderServiceImplCglib) enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

        //这里只对payOrder进行增强
        if("payOrder".equals(method.getName())){
            System.out.println("开始时间:"+System.currentTimeMillis());
            Object result =method.invoke(target, args);
            System.out.println("结束时间:"+System.currentTimeMillis());
            return result;
        }
        // 其他方法不增强
        return method.invoke(target, args);
    }
}

2.2.4 测试类
package com.xuanwu.cglib.demo;

import com.xuanwu.service.impl.OrderServiceImplCglib;

/***
 *cglib代理实现类
 */
public class TestCglibProxy {
    public static void main(String[] args) {
        //创建代理对象,并使用目标对象初始化
        OrderServiceImplCglib service=new OrderServiceCglibProxyFactory().createProxy();
        service.payOrder();
        service.queryOrder();
    }
}

运行结果

开始时间:1592361433218
10:37:13.220 [main] INFO com.xuanwu.service.impl.OrderServiceImplCglib - >>>>执行订单支付业务<<<<
结束时间:1592361433222
10:37:13.222 [main] INFO com.xuanwu.service.impl.OrderServiceImplCglib - >>>>执行订单查询业务<<<<

Process finished with exit code 0

三、代理总结

静态代理总结:

优点:可以做到在不修改目标对象的功能前提下,对目标功能扩展
缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值