dubbo的动态代理也是只能代理接口

源码入口在JavassistProxyFactory中

public class JavassistProxyFactory extends AbstractProxyFactory {
@Override
@SuppressWarnings("unchecked")
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
} @Override
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
// TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
return new AbstractProxyInvoker<T>(proxy, type, url) {
@Override
protected Object doInvoke(T proxy, String methodName,
Class<?>[] parameterTypes,
Object[] arguments) throws Throwable {
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
};
}
}

先写个demo

接口

public interface BasePerson {
void doSth() ;
String getSth() ;
}

接口实现类

public class Person implements BasePerson {
@Override
public void doSth() {
System.out.println("Person 正在 努力工作");
}
@Override
public String getSth() { System.out.println("person 正在 获取报酬"); return "good men";
}
}

写一个InvocationHandler

public class MyInvocationHandler implements InvocationHandler {

    Object targetObj;

    public MyInvocationHandler(Object obj) {
targetObj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理前置");
Object invoke = method.invoke(targetObj, args);
System.out.println("代理后置");
return invoke;
}
}

测试类

public class ProxyTest {

    public static void main(String[] args) {

        Person person = new Person();
Class<?>[] interfaces = Person.class.getInterfaces();
BasePerson proxyperson = (BasePerson) Proxy.getProxy(interfaces).newInstance(new MyInvocationHandler(person)); String sth = proxyperson.getSth();
System.out.println(sth);
}
}

控制台打印

代理前置
person 正在 获取报酬
代理后置
good men

源码分析

ClassHelper

// 优先获取当前线程的类加载器
public static ClassLoader getClassLoader(Class<?> cls) {
ClassLoader cl = null;
try {
cl = Thread.currentThread().getContextClassLoader();
} catch (Throwable ex) {
// Cannot access thread context ClassLoader - falling back to system class loader...
}
if (cl == null) {
//没有线程上下文的类加载器,使用接口的类加载器
cl = cls.getClassLoader();
}
return cl;
}

Proxy

public static Proxy getProxy(Class<?>... ics) {
//先获取类加载器
return getProxy(ClassHelper.getClassLoader(Proxy.class), ics);
}

Proxy 主要是这个方法

public static Proxy getProxy(ClassLoader cl, Class<?>... ics) {
if (ics.length > 65535)
throw new IllegalArgumentException("interface limit exceeded");
//记载被代理类接口
StringBuilder sb = new StringBuilder();
for (int i = 0; i < ics.length; i++) {
String itf = ics[i].getName();
if (!ics[i].isInterface())
throw new RuntimeException(itf + " is not a interface."); Class<?> tmp = null;
try {
tmp = Class.forName(itf, false, cl);
} catch (ClassNotFoundException e) {
}
//当前使用的类加载器加载不到(所以一般用接口自己的类加载器加载)
if (tmp != ics[i])
throw new IllegalArgumentException(ics[i] + " is not visible from class loader");
sb.append(itf).append(';');
} // 接口集的名字作为key
String key = sb.toString(); // 使用类加载器获取缓存
Map<String, Object> cache;
synchronized (ProxyCacheMap) {
cache = ProxyCacheMap.get(cl);
if (cache == null) {
cache = new HashMap<String, Object>();
ProxyCacheMap.put(cl, cache);
}
} Proxy proxy = null;
synchronized (cache) {
do {
// 从缓存中获取
Object value = cache.get(key);
if (value instanceof Reference<?>) {
proxy = (Proxy) ((Reference<?>) value).get();
if (proxy != null)
return proxy;
} if (value == PendingGenerationMarker) {
try {
cache.wait();
} catch (InterruptedException e) {
}
} else {
// 添加到缓存(value是一个标识)
cache.put(key, PendingGenerationMarker);
break;
}
}
while (true);
}
//自增id
long id = PROXY_CLASS_COUNTER.getAndIncrement(); //以下就是使用javassist拼装代理类
String pkg = null;
ClassGenerator ccp = null, ccm = null;
try {
ccp = ClassGenerator.newInstance(cl); Set<String> worked = new HashSet<String>();
List<Method> methods = new ArrayList<Method>(); for (int i = 0; i < ics.length; i++) {
if (!Modifier.isPublic(ics[i].getModifiers())) {
String npkg = ics[i].getPackage().getName();
if (pkg == null) {
pkg = npkg;
} else {
if (!pkg.equals(npkg))
throw new IllegalArgumentException("non-public interfaces from different packages");
}
}
ccp.addInterface(ics[i]); for (Method method : ics[i].getMethods()) {
String desc = ReflectUtils.getDesc(method);
if (worked.contains(desc))
continue;
worked.add(desc); int ix = methods.size();
Class<?> rt = method.getReturnType();
Class<?>[] pts = method.getParameterTypes(); StringBuilder code = new StringBuilder("Object[] args = new Object[").append(pts.length).append("];");
for (int j = 0; j < pts.length; j++)
code.append(" args[").append(j).append("] = ($w)$").append(j + 1).append(";");
code.append(" Object ret = handler.invoke(this, methods[" + ix + "], args);");
if (!Void.TYPE.equals(rt))
code.append(" return ").append(asArgument(rt, "ret")).append(";"); methods.add(method);
ccp.addMethod(method.getName(), method.getModifiers(), rt, pts, method.getExceptionTypes(), code.toString());
}
} if (pkg == null)
pkg = PACKAGE_NAME; // create ProxyInstance class.
String pcn = pkg + ".proxy" + id;
ccp.setClassName(pcn);
ccp.addField("public static java.lang.reflect.Method[] methods;");
ccp.addField("private " + InvocationHandler.class.getName() + " handler;");
ccp.addConstructor(Modifier.PUBLIC, new Class<?>[]{InvocationHandler.class}, new Class<?>[0], "handler=$1;");
ccp.addDefaultConstructor();
Class<?> clazz = ccp.toClass();
clazz.getField("methods").set(null, methods.toArray(new Method[0])); // create Proxy class.
String fcn = Proxy.class.getName() + id;
ccm = ClassGenerator.newInstance(cl);
ccm.setClassName(fcn);
ccm.addDefaultConstructor();
ccm.setSuperClass(Proxy.class);
ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn + "($1); }");
Class<?> pc = ccm.toClass();
proxy = (Proxy) pc.newInstance();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
} finally {
// release ClassGenerator
if (ccp != null)
ccp.release();
if (ccm != null)
ccm.release();
synchronized (cache) {
if (proxy == null)
cache.remove(key);
else
cache.put(key, new WeakReference<Proxy>(proxy));
cache.notifyAll();
}
}
return proxy;
}

得到编译的class文件


//如果接口是public修饰的 就在debug的时候使用这个能在E盘下生成class文件,e:/com/alibaba/dubbo/common/bytecode/proxy0/proxy0.class
ccm.getClassPool().get("com.alibaba.dubbo.common.bytecode.proxy0").debugWriteFile("e:\\")
//如果接口没有被public修饰 debug的时候可以用以下方式获取class文件
ccp.getClassPool().get("per.qiao.util.proxy0").debugWriteFile("e:\\")
ccm.getClassPool().get("per.qiao.util.proxy0").debugWriteFile("e:\\")

debug截图

编译后的文件proxy0.class

package com.alibaba.dubbo.common.bytecode;

import com.alibaba.dubbo.common.bytecode.ClassGenerator.DC;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import per.qiao.util.BasePerson; public class proxy0 implements DC, BasePerson {
public static Method[] methods;
private InvocationHandler handler; public String getSth() {
Object[] var1 = new Object[0];
Object var2 = this.handler.invoke(this, methods[0], var1);
return (String)var2;
} public void doSth() {
Object[] var1 = new Object[0];
this.handler.invoke(this, methods[1], var1);
} public proxy0() {
} public proxy0(InvocationHandler var1) {
this.handler = var1;
}
}

dubbo中使用动态代理的更多相关文章

  1. 使用Java中的动态代理实现数据库连接池

    2002 年 12 月 05 日 作者通过使用JAVA中的动态代理实现数据库连接池,使使用者可以以普通的jdbc连接的使用习惯来使用连接池. 数据库连接池在编写应用服务是经常需要用到的模块,太过频繁的 ...

  2. java中的动态代理机制

    java中的动态代理机制 在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface).另一个则是 Proxy(Class),这一个类和接口是实现 ...

  3. Spring AOP中的动态代理

    0  前言 1  动态代理 1.1 JDK动态代理 1.2 CGLIB动态代理 1.2.1 CGLIB的代理用法 1.2.2 CGLIB的过滤功能 2  Spring AOP中的动态代理机制 2.1  ...

  4. 转:Spring AOP中的动态代理

    原文链接:Spring AOP中的动态代理 0  前言 1  动态代理 1.1 JDK动态代理 1.2 CGLIB动态代理 1.2.1 CGLIB的代理用法 1.2.2 CGLIB的过滤功能 2  S ...

  5. java反射中的动态代理机制(有实例)

    在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的 ...

  6. 十分钟理解Java中的动态代理

    十分钟理解 Java 中的动态代理   一.概述 1. 什么是代理 我们大家都知道微商代理,简单地说就是代替厂家卖商品,厂家“委托”代理为其销售商品.关于微商代理,首先我们从他们那里买东西时通常不知道 ...

  7. 动态代理(一)——JDK中的动态代理

    在开始动态代理的描述之前,让我们认识下代理.代理:即代替担任执行职务.在面向对象世界中,即寻找另一个对象代理目标对象与调用者交互.Java中分为静态代理和动态代理.这里对于静态代理不做详述.它们之间的 ...

  8. 深度剖析java中JDK动态代理机制

    https://www.jb51.net/article/110342.htm 本篇文章主要介绍了深度剖析java中JDK动态代理机制 ,动态代理避免了开发人员编写各个繁锁的静态代理类,只需简单地指定 ...

  9. 一文读懂Java中的动态代理

    从代理模式说起 回顾前文: 设计模式系列之代理模式(Proxy Pattern) 要读懂动态代理,应从代理模式说起.而实现代理模式,常见有下面两种实现: (1) 代理类关联目标对象,实现目标对象实现的 ...

随机推荐

  1. .NET Core入门程序及命令行练习

    用命令行一步一步新建项目.添加Package.Restore.Build.Run 执行的实现方式,更让容易让我们了解.NET Core的运行机制. 准备工作 安装.NET Core 运行环境,下载地址 ...

  2. mysql ERROR 1862 (HY000): 密码超时错误解决 Your password has expired.To log in you must change it using a client that supports expired password

    工具链接可能报错,使用黑窗口链接后: 1. SET PASSWORD = PASSWORD("xinmima"); 2. flush privileges; 使用新密码链接即可.

  3. PHP正则表达式提取html超链接中的href地址

    $preg='/<a .*?href="(.*?)".*?>/is'; preg_match_all($preg,$str,$array2); ;$i<count ...

  4. P5589 【小猪佩奇玩游戏】

    这题还是比较妙妙套路的,复杂度为\(O(log^2N)\),可以卡掉\(\sqrt n\)的做法 首先我们可以把原数列分成很多个集合,集合之间肯定是两两独立的,考虑分别计算答案 我们定义\(f_i\) ...

  5. EasyEarth三维可视化解决方案——智慧河长

    EasyEarth—— 为河长装上“千里眼.顺风耳” 为各级河长办应急指挥.任务指派. 实绩考核提供快速直观的 高效.精准.智能化决策平台. 河长制背景 我国治水工作呈现出新老问题交织态势,河湖管理保 ...

  6. 刷题记录:[CISCN2019 总决赛 Day2 Web1]Easyweb

    目录 刷题记录:[CISCN2019 总决赛 Day2 Web1]Easyweb 一.涉及知识点 1.敏感文件泄露 2.绕过及sql注入 3.文件上传:短标签绕过php过滤 刷题记录:[CISCN20 ...

  7. 安装关系型数据库MySQL 安装大数据处理框架Hadoop

    作业要求来自:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/3161 1.Hadoop的介绍 Hadoop最早起源于Nutch.Nut ...

  8. 剑指offer:孩子们的游戏(圆圈中最后剩下的数)

    题目描述: 每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此.HF作为牛客的资深元老,自然也准备了一些小游戏.其中,有个游戏是这样的:首先,让小朋友们围成一个大圈.然后,他随机 ...

  9. Nim游戏博弈(收集完全版)

    Nim游戏证明参见: 刘汝佳训练指南P135-写的很酷! 知乎上SimonS关于Nim博弈的回答! Nim游戏的概述: 还记得这个游戏吗? 给出n列珍珠,两人轮流取珍珠,每次在某一列中取至少1颗珍珠, ...

  10. springcloud添加自定义的endpoint来实现平滑发布

    在我之前的文章  springcloud如何实现服务的平滑发布 里介绍了基于pause的发布方案. 平滑发布的核心思想就是:所有服务的调用者不再调用该服务了就表示安全的将服务kill掉. 另外actu ...