参考文档:
一、代理模式?
通俗的讲代理模式:经常会听到中介、代驾、代练等词,比如卖房子,房主需要张贴信息、带人看房,房主将自己的功能赋予的中介,就可以帮他完成这些事情。其实房主他最终的目的就是签合同收钱,那这样的话,什么张贴信息、宣传、带人看房,中介来就行了,房主只等着签合同收钱就行了。
代理模式的定义:一个类代表另一个类的功能,并且为其它对象提供一种代理以控制对这个对象的访问。
代理主要作用:
- 保护目标对象;
- 增强目标对像。
二、代理实现方式:静态代理和动态代理
静态代理:是把需要代理的对象功能逻辑写死了,比如被代理的对象需要再被代理其它功能,代理类就需要再添加逻辑,扩展性差,而且无法公用。
动态代理:只需要告诉代理类需要代理的对象,以后被代理的对象再添加新的方法时,也可以代理,这样代理类不需要再修改,容易维护,也可以公用。
案例中使用到依赖
<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);
}
}