代理模式的基本概念以及代理的实现方式

参考文档:

 

菜鸟教程

一、代理模式?

通俗的讲代理模式:经常会听到中介、代驾、代练等词,比如卖房子,房主需要张贴信息、带人看房,房主将自己的功能赋予的中介,就可以帮他完成这些事情。其实房主他最终的目的就是签合同收钱,那这样的话,什么张贴信息、宣传、带人看房,中介来就行了,房主只等着签合同收钱就行了。

代理模式的定义:一个类代表另一个类的功能,并且为其它对象提供一种代理以控制对这个对象的访问。

代理主要作用:

  • 保护目标对象;
  • 增强目标对像。

二、代理实现方式:静态代理和动态代理

静态代理:是把需要代理的对象功能逻辑写死了,比如被代理的对象需要再被代理其它功能,代理类就需要再添加逻辑,扩展性差,而且无法公用。

动态代理:只需要告诉代理类需要代理的对象,以后被代理的对象再添加新的方法时,也可以代理,这样代理类不需要再修改,容易维护,也可以公用。

案例中使用到依赖

<dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
</dependencies>

三、使用java.lang.reflect.InvocationHandler实现动态代理

  • product
package cn.com.dl.bean;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * Created by yanshao on 2020-11-12.
 */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Product implements Serializable {
    private static final long serialVersionUID = -1207552453025776210L;
    private String productId;
    private String productName;
}
  • ProductService
package cn.com.dl.service;

import cn.com.dl.bean.Product;

/**
 * Created by yanshao on 2020-11-12.
 */
public interface ProductService {
    /**
     * 打印产品名称
     * @param product
     */
    void printProductName(Product product);
}
  • ProductServiceImpl
package cn.com.dl.service.impl;

import cn.com.dl.bean.Product;
import cn.com.dl.service.ProductService;

/**
 * Created by yanshao on 2020-11-12.
 */
public class ProductServiceImpl implements ProductService {
    public void printProductName(Product product) {
        System.out.println("产品名称>>>" + product.getProductName());
    }
}
  • ProductProxyHandler 

   通过实现InvocationHandler接口,重新invoke来实现具体的逻辑,比如在调用method.invoke(productService,args)之前,我们可以打印参数列表日志、记录请求流水等;在method.invoke(productService,args)之后打印接口的处理结果、更新请求流水记录等。通过jdk提供的动态代理实现方式,代理类必须实现InvocationHandler接口(缺点)。

package cn.com.dl.proxy;

import cn.com.dl.service.ProductService;

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

/**
 * Created by yanshao on 2020-11-12.
 */
public class ProductProxyHandler implements InvocationHandler {

    private ProductService productService;

    public ProductProxyHandler(ProductService productService) {
        this.productService = productService;
    }

    /**
     * @param proxy  代理类对象com.sun.proxy.$Proxy*
     * @param method 被代理类需要执行的方法
     * @param args   被代理类需要执行的方法 的方法列表
     * @return
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("调用接口开始-----");
        System.out.println("代理类>>>" + proxy.getClass().getName());
        System.out.println("方法名称>>>>" + method.getName());
        System.out.println("入参>>>>" + Arrays.toString(args));
        Object object = method.invoke(productService,args);
        System.out.println("调用接口结束-----");
        return object;
    }
}

四、使用cn.com.dl.proxy.ProductCglibProxyHandler实现动态代理

  • ProductCglibProxyHandler
package cn.com.dl.proxy;

import cn.com.dl.service.ProductService;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * Created by yanshao on 2020-11-12.
 */
public class ProductCglibProxyHandler implements MethodInterceptor {
    private ProductService productService;

    public ProductCglibProxyHandler(ProductService productService) {
        this.productService = productService;
    }

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("ProductCglibProxyHandler调用接口开始-----");
        System.out.println("ProductCglibProxyHandler代理类>>>" + o.getClass().getName());
        System.out.println("ProductCglibProxyHandler方法名称>>>>" + method.getName());
        System.out.println("ProductCglibProxyHandler>>>methodProxy方法名称>>>>" + methodProxy.getSuperName());
        System.out.println("ProductCglibProxyHandler入参>>>>" + Arrays.toString(objects));
        Object object = method.invoke(productService,objects);
        System.out.println("ProductCglibProxyHandler调用接口结束-----");
        return object;
    }

    /**
     * 上面那种方式,需要实现MethodInterceptor接口,通过下面这种方式,我们可以不实现MethodInterceptor
     * 也可以让其它想要被代理的对象使用这个方法
     * @param obj
     * @param <T>
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T getCglibProxy(final T obj){
        Object proxy = Enhancer.create(obj.getClass(), new MethodInterceptor() {
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("getCglibProxy调用接口开始-----");
                System.out.println("getCglibProxy代理类>>>" + o.getClass().getName());
                System.out.println("getCglibProxy方法名称>>>>" + method.getName());
                System.out.println("getCglibProxy>>>methodProxy方法名称>>>>" + methodProxy.getSuperName());
                System.out.println("getCglibProxy入参>>>>" + Arrays.toString(objects));
                Object object = method.invoke(obj,objects);
                System.out.println("getCglibProxy调用接口结束-----");
                return object;
            }
        });
        return (T)proxy;
    }
}
  • ProductServiceImplTest
package cn.com.dl.service.impl;

import cn.com.dl.bean.Product;
import cn.com.dl.proxy.ProductCglibProxyHandler;
import cn.com.dl.proxy.ProductProxyHandler;
import cn.com.dl.service.ProductService;
import org.junit.Test;
import org.springframework.cglib.proxy.Enhancer;

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

public class ProductServiceImplTest {

    @Test
    public void printProductName() {

        ProductService productService = new ProductServiceImpl();
        InvocationHandler handler = new ProductProxyHandler(productService);

        ProductService proxy = (ProductService) Proxy.newProxyInstance(
                productService.getClass().getClassLoader(),
                productService.getClass().getInterfaces(),
                handler
                );

        Product product = Product.builder()
                .productId("101")
                .productName("手机")
                .build();

        proxy.printProductName(product);
    }

    @Test
    public void printProductName1() {

        ProductService productService = new ProductServiceImpl();

        Product product = Product.builder()
                .productId("102")
                .productName("电脑")
                .build();

        ProductCglibProxyHandler proxyHandler = new ProductCglibProxyHandler(productService);
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(productService.getClass());
        enhancer.setCallback(proxyHandler);
        //动态代理类
        ProductService cglibProxy = (ProductService)enhancer.create();
        cglibProxy.printProductName(product);
    }

    @Test
    public void printProductName2() {
        Product product = Product.builder()
                .productId("103")
                .productName("键盘")
                .build();
        ProductService productService = ProductCglibProxyHandler.getCglibProxy(new ProductServiceImpl());
        productService.printProductName(product);
    }

}

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

燕少༒江湖

给我一份鼓励!谢谢!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值