---
top: false
cover: false
toc: true
mathjax: true
date: 2018-10-27 02:01:03
password:
summary:
tags: "设计模式"
categories: "java"
title: 设计模式-代理模式Java代理
什么是代理模式
代理模式:为其他对象提供一种代理以控制对这个对象的访问,属于结构型模式。
目的
- 保护目标对象
- 增强目标对象
使用场景
- 要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。
- 针对历史代码中的内容需要进行改造,在不侵入历史代码时,对方法进行拓展,完成新功能的拓展。
Java的代理实现
场景描述
在原始的业务中,通过service调用dao层的方法写入到数据库中,目前为了进行业务拓展需要针对订单ID进行数据源的动态切换,在实现dao层时,需要根据主键进行分库的操作,不同的订单ID要分配到不同的数据库中。
代码实现
OrderServiceImpl
代码调用dao层代码OrderDao
定义dao层接口,OrderDaoImpl
实现接口进行数据写入
//service 代码
public class OrderServiceImpl {
private OrderDao orderDao;
public OrderServiceImpl(OrderDao orderDao) {
this.orderDao = orderDao;
}
public int createOrder(String orderId) {
return orderDao.insertOrder(orderId);
}
}
//dao接口
public interface OrderDao {
/**
* 创建的订单
*
* @param orderId 订单ID
* @return 插入的数据条数
*/
int insertOrder(String orderId);
}
//dao实现
public class OrderDaoImpl implements OrderDao {
public int insertOrder(String orderId) {
System.out.println("插入订单" + orderId);
return 1;
}
}
静态代理
仅能指定需要代理的对象,且无法进行其他功能的拓展,当被代理对象的定义进行修改后,代理类需要同步修改,不符合开闭原则。
public class OrderDaoStaticProxy implements OrderDao {
private OrderDaoImpl orderDaoImpl;
public OrderDaoStaticProxy(OrderDaoImpl orderDaoImpl) {
this.orderDaoImpl = orderDaoImpl;
}
@Override
public int insertOrder(String orderId) {
changeDataSource(orderId);
//原始逻辑
Object obj = orderDaoImpl.insertOrder(orderId);
//数据源恢复默认
restoreDataSource();
return (int) obj;
}
/**
* 根据订单ID修改数据源信息
*
* @param orderId
*/
private void changeDataSource(String orderId) {
System.out.println("当前数据源切换到 db_" + (Integer.parseInt(orderId) % 4 + 1));
}
/**
* 恢复默认数据源
*/
private void restoreDataSource() {
System.out.println("恢复数据源db_0");
}
}
//测试代码
public class TestStaticProxy {
public static void main(String[] args) {
OrderDao orderDao = new OrderDaoStaticProxy(new OrderDaoImpl());
orderDao.insertOrder("7");
}
}
静态代理定义后只能代理指定的对象
OrderDao
,当OrderDao
接口中定义的内容更新后,需要同步更新代理类中的调用。
动态代理
要求:被代理类必须实现接口
- 定义代理类,并且实现
InvocationHandler
接口 - 实现
invoke
方法
//代理类
public class OrderDaoDynamicProxy implements InvocationHandler {
private OrderDaoImpl orderDaoImpl;
public Object getInstance(OrderDaoImpl orderDaoImpl) {
//注入
this.orderDaoImpl = orderDaoImpl;
Class<? extends OrderDao> clazz = orderDaoImpl.getClass();
return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
}
/**
* 实现invoke方法
*
* @param proxy 代理对象
* @param method 方法
* @param args 参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//数据源切换
String orderId = (String) args[0];
changeDataSource(orderId);
//原始逻辑
Object obj = method.invoke(this.orderDaoImpl, args);
//数据源恢复默认
restoreDataSource();
return obj;
}
/**
* 根据订单ID修改数据源信息
*
* @param orderId
*/
private void changeDataSource(String orderId) {
System.out.println("当前数据源切换到 db_" + (Integer.parseInt(orderId) % 4 + 1));
}
/**
* 恢复默认数据源
*/
private void restoreDataSource() {
System.out.println("恢复数据源db_0");
}
}
//测试代码
public class TestDynamicProxy {
public static void main(String[] args) {
OrderDao orderDao = (OrderDao) new OrderDaoDynamicProxy().getInstance(new OrderDaoImpl());
orderDao.insertOrder("7");
}
}
源码分析
- 调用newProxyInstance方法
- 调用
getProxyClass0
做接口个数的检查,如果定义过直接返回,不存在则继续 - 调用
ProxyClassFactory
类的apply
方法 - 首先做接口列表的一系列检查,比如是否为接口、接口可见性
ProxyGenerator.generateProxyClass
方法开始生成代理类generateClassFile
方法创建代理类的二进制文件- 根据接口列表分别重写代理的方法,并将类内容写入到之前定义的以(
$Proxy
+数字)的类中
源码如下:
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
...
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);
...
}
/**
* Generate a proxy class. Must call the checkProxyAccess method
* to perform permission checks before calling this.
*/
private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces) {
...
if (interfaces.length > 65535) { //JDK 限制接口数量,进行检查
throw new IllegalArgumentException("interface limit exceeded");
}
//如果继承于相同接口的对应的loader已经在cache中存在了,那么直接返回,否则通过ProxyClassFactory进行代理类的创建
return proxyClassCache.get(loader, interfaces);
...
}
//根据ProxyClassFactory工厂构建class
private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
//根据给到的classload和接口列表产出class类
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// prefix for all proxy class names,类的前缀都是'$Proxy'
private static final String proxyClassNamePrefix = "$Proxy";
// next number to use for generation of unique proxy class names,通过生成的唯一自增数字为类编号,'$Proxy0'、'$Proxy1'、'$Proxy2'
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
//将接口列表装入Set去重
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
//遍历所有接口进行处理
for (Class<?> intf : interfaces) {
/*
* Verify that the class loader resolves the name of this
* interface to the same Class object.
*/
Class<?> interfaceClass = null;
try {
//反射调用接口,获取接口对象
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
//接口校验可见性权限
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
/*
* Verify that the Class object actually represents an
* interface.
*/
//接口校验
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
/*
* Verify that this interface is not a duplicate.
*/
//校验接口是否唯一
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
/*
* Record the package of a non-public proxy interface so that the
* proxy class will be defined in the same package. Verify that
* all non-public proxy interfaces are in the same package.
*/
//处理要写入的包路径
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
// if no non-public proxy interfaces, use com.sun.proxy package
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
/*
* Choose a name for the proxy class to generate.
*/
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* Generate the specified proxy class.
*/
//生成代理类
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
/*
* A ClassFormatError here means that (barring bugs in the
* proxy class generation code) there was some other
* invalid aspect of the arguments supplied to the proxy
* class creation (such as virtual machine limitations
* exceeded).
*/
throw new IllegalArgumentException(e.toString());
}
}
}
//生成class文件的方法
private byte[] generateClassFile() {
this.addProxyMethod(hashCodeMethod, Object.class);
this.addProxyMethod(equalsMethod, Object.class);
this.addProxyMethod(toStringMethod, Object.class);
Class[] var1 = this.interfaces;
int var2 = var1.length;
int var3;
Class var4;
//遍历接口,获取接口对应的方法
for(var3 = 0; var3 < var2; ++var3) {
var4 = var1[var3];
Method[] var5 = var4.getMethods();
int var6 = var5.length;
for(int var7 = 0; var7 < var6; ++var7) {
Method var8 = var5[var7];
//添加需要代理的方法
this.addProxyMethod(var8, var4);
}
}
//处理方法的返回值
Iterator var11 = this.proxyMethods.values().iterator();
List var12;
while(var11.hasNext()) {
var12 = (List)var11.next();
checkReturnTypes(var12);
}
//处理方法定义的属性
Iterator var15;
try {
this.methods.add(this.generateConstructor());
var11 = this.proxyMethods.values().iterator();
while(var11.hasNext()) {
var12 = (List)var11.next();
var15 = var12.iterator();
while(var15.hasNext()) {
ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();
this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));
this.methods.add(var16.generateMethod());
}
}
this.methods.add(this.generateStaticInitializer());
} catch (IOException var10) {
throw new InternalError("unexpected I/O Exception", var10);
}
if (this.methods.size() > 65535) {
throw new IllegalArgumentException("method limit exceeded");
} else if (this.fields.size() > 65535) {
throw new IllegalArgumentException("field limit exceeded");
} else {
this.cp.getClass(dotToSlash(this.className));
this.cp.getClass("java/lang/reflect/Proxy");
var1 = this.interfaces;
var2 = var1.length;
for(var3 = 0; var3 < var2; ++var3) {
var4 = var1[var3];
this.cp.getClass(dotToSlash(var4.getName()));
}
//类内容写出
this.cp.setReadOnly();
ByteArrayOutputStream var13 = new ByteArrayOutputStream();
DataOutputStream var14 = new DataOutputStream(var13);
try {
var14.writeInt(-889275714);
var14.writeShort(0);
var14.writeShort(49);
this.cp.write(var14);
var14.writeShort(this.accessFlags);
var14.writeShort(this.cp.getClass(dotToSlash(this.className)));
var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
var14.writeShort(this.interfaces.length);
Class[] var17 = this.interfaces;
int var18 = var17.length;
for(int var19 = 0; var19 < var18; ++var19) {
Class var22 = var17[var19];
var14.writeShort(this.cp.getClass(dotToSlash(var22.getName())));
}
var14.writeShort(this.fields.size());
var15 = this.fields.iterator();
while(var15.hasNext()) {
ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();
var20.write(var14);
}
var14.writeShort(this.methods.size());
var15 = this.methods.iterator();
while(var15.hasNext()) {
ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();
var21.write(var14);
}
var14.writeShort(0);
return var13.toByteArray();
} catch (IOException var9) {
throw new InternalError("unexpected I/O Exception", var9);
}
}
}
cglib代理
代码实现
public class CglibOrderDaoDynamicProxy implements MethodInterceptor {
private OrderDaoImpl orderDaoImpl;
public Object getInstance(OrderDaoImpl orderDaoImpl) {
//注入
this.orderDaoImpl = orderDaoImpl;
Enhancer enhancer = new Enhancer();
enhancer.setCallback(this);
enhancer.setSuperclass(orderDaoImpl.getClass());
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
changeDataSource((String) objects[0]);
Object o1 = methodProxy.invoke(orderDaoImpl, objects);
restoreDataSource();
return o1;
}
/**
* 根据订单ID修改数据源信息
*
* @param orderId
*/
private void changeDataSource(String orderId) {
System.out.println("当前数据源切换到 db_" + (Integer.parseInt(orderId) % 4 + 1));
}
/**
* 恢复默认数据源
*/
private void restoreDataSource() {
System.out.println("恢复数据源db_0");
}
}
//测试代码
public class TestCGLIBDynamicProxy {
public static void main(String[] args) {
OrderDao orderDao = (OrderDao) new CglibOrderDaoDynamicProxy().getInstance(new OrderDaoImpl());
orderDao.insertOrder("7");
}
}
实现原理
为了完整的理解cglib 如何工作,可以将产出的对象写到本地中
public class TestCGLIBDynamicProxy {
public static void main(String[] args) {
//写入到本地文件中
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"/Users/qizi/work/gupao/pattern");
OrderDao orderDao = (OrderDao) new CglibOrderDaoDynamicProxy().getInstance(new OrderDaoImpl());
orderDao.insertOrder("7");
}
}
其中OrderDaoImpl|EnhancerByCGLIB|8a2e97f4
为主要生成的代理的类,其他的两个为辅助类,net
包下为缓存相关的类。
OrderDaoImpl|EnhancerByCGLIB|8a2e97f4
类代码如下:
可以看到OrderDaoImpl|EnhancerByCGLIB|8a2e97f4
是继承了需要代理的类对象的
public final int insertOrder(String var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
//会调用定义的intercept方法
Object var2 = var10000.intercept(this, CGLIB|insertOrder|0|Method, new Object[]{var1}, CGLIB$insertOrder|0|Proxy);
return var2 == null ? 0 : ((Number)var2).intValue();
} else {
return super.insertOrder(var1);
}
}
同时针对需要代理的方式,会进行重写,并且定义为final
,表示已经代理过的方法无法再次被代理。