- 浏览: 493753 次
- 性别:
- 来自: 长沙
-
文章分类
最新评论
-
Source_野驴:
...
jsp静态化和伪静态化 -
zidanzzg:
很好的知识,找到了利用异或交换数值的理论支持,谢谢分享
XOR的性质和运算 -
ueseu:
引用(2) DomainDomain域名也是Cookie的一部 ...
Cookie的组成 -
ueseu:
引用Secure取true或者false值。如果为true,那 ...
Cookie的组成 -
liqi___123:
理解得很透彻,谢谢!!
ROLAP、MOLAP和HOLAP联机分析处理区别
转自:http://www.oschina.net/question/12_7698
把大型系统移植到OSGi架构上常常意味着解决复杂的类加载问题。这篇文章专门研究了面向这个领域最难问题的几个框架:有关动态代码生成的框架。这些框架 也都是些超酷的框架:AOP包装器,ORM映射器以及服务代理生成器,这些仅仅是一些例子。
我们将按照复杂性增加的顺序考察一些类加载的典型问题,开发一小段代码来解决这些问题中最有趣的一个。即使你不打算马上写一个代码生成框架,这篇文 章也会让你对静态定义依赖的模块运行时(如OSGi系统)的低级操作有比较深入的了解。
这篇文章还包括一个可以工作的演示项目,该项目不仅包含这里演示的代码,还有两个基于ASM的代码生成器可供实践。
类加载地点转换
把一个框架移植到OSGi系统通常需要把框架按照extender模 式重构。这个模式允许框架把所有的类加载工作委托给OSGi框架,与此同时保留对应用代码的生命周期的控制。转换的目标是使用应用bundle的类加载来 代替传统的繁复的类加载策略。例如我们希望这样替换代码:
ClassLoader appLoader = Thread.currentThread().getContextClassLoader(); Class appClass = appLoader.loadClass("com.acme.devices.SinisterEngine"); ... ClassLoader appLoader = ... Class appClass = appLoader.loadClass("com.acme.devices.SinisterEngine");
替换为:
Bundle appBundle = ... Class appClass = appBundle.loadClass("com.acme.devices.SinisterEngine");
尽管我们必须做大量的工作以便OSGi为我们加载应用代码,我们至少有一种优美而正确的方式来完成我们的工作,而且会比以前工作得更好!现在用户可 以通过向OSGi容器安装/卸载bundle而增加/删除应用。用户还可以把他们的应用分解为多个bundle,在应用之间共享库并利用模块化的其他能 力。
由于上下文类加载器是目前框架加载应用代码的标准方式,我们在此对其多说两句。当前OSGi没有定义设置上下文类加载器的策略。当一个框架依赖于上 下文类加载器时,开发者需要预先知道这点,在每次调用进入那个框架时手工设置上下文类加载器。由于这样做易于出错而其不方便,所以在OSGi下几乎不使用 上下文类加载器。在定义OSGi容器如何自动管理上下文类加载器方面,目前有些人正 在进行尝试。但在一个官方的标准出现之前,最好把类加载转移到一个具体的应用bundle。
适配器类加载器
有时候我们转换的代码有外部化的类加载策略。这意味着框架的类和方法接收明确的ClassLoader 参数,允许我们来决定他们从哪里加载应用代码。在这种情况下,把系统转换到OSGi就仅仅是让Bundle对象适配ClassLoader API的问题。这是一个经典的适配器模式的应用。
public class BundleClassLoader extends ClassLoader { private final Bundle delegate; public BundleClassLoader(Bundle delegate) { this.delegate = delegate; } @Override public Class<?> loadClass(String name) throws ClassNotFoundException { return delegate.loadClass(name); } }
现在我们可以把这个适配器传给转换的框架代码。随着新bundle的增减,我们还可以增加bundle跟踪代码来创建新的适配器 —— 例如,我们可以“在外部”把一个Java框架适配到OSGi,避免浏览该框架的代码库以及变换每个单独的类加载场所。下面是将一个框架转换到使用OSGi 类加载的示意性的例子:
... Bundle app = ... BundleClassLoader appLoader = new BundleClassLoader(app); DeviceSimulationFramework simfw = ... simfw.simulate("com.acme.devices.SinisterEngine", appLoader); ...
桥接类加载器
许多有趣的Java框架的客户端代码在运行时做了很多花哨的类处理工作。其目的通常是在应用的类空间中构造本不存在的类。让我们把这些生成的类称作 增强(enhancement)。通常,增强类实现了一些应用可见的接口或者继承自一个应用可见的类。有时,一些附加的接口及其实现也可以被混入。
增强类扩充了应用代码 - 应用可以直接调用生成的对象。例如,一个传递给应用代码的服务代理对象就是这种增强类对象,它使得应用代码不必去跟踪一个动态服务。简单的说,增加了一些 AOP特征的包装器被作为原始对象的替代品传递给应用代码。
增强类的生命始于字节数组byte[],由你喜爱的类工程库(ASM,BCEL,CGLIB)产生。一旦我们生成了我们的类,必须把这些原始的字节 转换为一个Class对象,换言之,我们必须让某个类加载器对我们的字节调用它的defineClass()
方法。我们有三个 独立的问题要解决:
- 类空间完整性 - 首先我们必须决定可以定义我们增强类的类空间。该类空间必须“看到”足够多的类以便让增强类能够被完全链接。
-
可见性 -
ClassLoader.defineClass()
是一个受保护的方法。我们必 须找到一个好方法来调用它。 - 类空间一致性 - 增强类从框架和应用bundle混入类,这种加载类的方式对于OSGi容器来说是“不可见的”。作为结果,增强类可能被暴露给相同类的不兼容的版本。
类空间完整性
增强类的背后支持代码对于生成它们的Java框架来说是未公开的 - 这意味着该框架应该会把该新类加入到其类空间。另一方面,增强类实现的接口或者扩展的类在应用的类空间是可见,这意味着我们应该在这里定义增强类。我们不 能同时在两个类空间定义一个类,所以我们有个麻烦。
因为没有类空间能够看到所有需要的类,我们别无选择,只能创建一个新的类空间。一个类空间等同于一个类加载器实例,所以我们的第一个工作就是在所有 的应用bundle之上维持一个专有的类加载器。这些叫做桥接类加载器,因为他们通过链接加载器合并了两个类空间:
public class BridgeClassLoader extends ClassLoader { private final ClassLoader secondary; public BridgeClassLoader(ClassLoader primary, ClassLoader secondary) { super(primary); } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { return secondary.loadClass(name); } }
现在我们可以使用前面开发的BundleClassLoader:
/* Application space */ Bundle app = ... ClassLoader appSpace = new BundleClassLoader(app); /* * Framework space * * We assume this code is executed inside the framework */ ClassLoader fwSpace = this.getClass().getClassLoader(); /* Bridge */ ClassLoader bridge = new BridgeClassLoader(appSpace, fwSpace);
这个加载器首先从应用空间为请求提供服务 - 如果失败,它将尝试框架空间。请注意我们仍然让OSGi为我们做很多重量工作。当我们委托给任何一个类空间时,我们实际上委托给了一个基于OSGi的类加 载器 - 本质上,primary和secondary加载器可以根据他们各自bundle的导入/导出(import/export)元数据将加载工作委托给其他 bundle加载器。
此刻我们也许会对自己满意。然而,真相是苦涩的,合并的框架和应用类空间也许并不够!这一切的关键是JVM链接类(也叫解析类)的特殊方式。对于 JVM链 接类的工作有很多解释:
简短的回答:JVM以一种细粒度(一次一个符号)的方式来做解析工作的。
冗长的回答:当JVM链接一个类时,它不需要被连接类的所有引用类的完整的描述。它只需要被链接类真正使用的个 别的方法、字段和类型的信息。我们直觉上认为对于JVM来说,其全部是一个类名称,加上一个超类,加上一套实现的接口,加上一套方法签名,加上一套字段签 名。所有这些符号是被独立且延迟解析的。例如,要链接一个方法调用,调用者的类空间只需要给类对象提供目标类和方法签名中用到的所有类型。目标类中的其他 许多定义是不需要的,调用者的类加载器永远不会收到加载它们(那些不需要的定义)的请求。
正式的答案:类空间SpaceA的类A必须被类空间SpaceB的相同类对象所代表,当且仅当:
- SpaceB存在一个类B,在它的符号表(也叫做常 量池)中引用着A。
- OSGi容器已经将SpaceA作为类A的提供者(provider)提供给SpaceB。该联系是建立在容器所有bundle的静态元 数据之上的。
例如:假设我们有一个bundle BndA导出一个类A。类A有3个方法,分布于3个接口中:
-
IX.methodX(String)
IY.methodY(String)
-
IZ.methodZ(String)
还假设我们有一个bundle BndB,其有一个类B。类B中有一个引用 A a = ……和一个方法调用a.methodY("Hello!")。为了能够解析类B,我们需要为BndB的类空间引入类A和类String。这就够了!我们不 需要导入IX或者IZ。我们甚至不需要导入IY,因为类B没有用IY - 它只用了A。在另一方面,bundle BndA导出时会解析类A,必须提供IX,IY,IZ,因为他们作为被实现的接口直接被引用。最终,BndA也不需要提供IX,IY,IZ的任何父接口, 因为他们也没有被直接引用。
现在假设我们希望给类空间BndB的类B呈现类空间BndA的类A的一个增强版本。该增强类需要继承类A并覆盖它的一些或全部方法。因此,该增强类 需要看到在所有覆盖的方法签名中使用的类。然而,BndB仅当调用了所有被覆盖的方法时才会导入所有这些类。BndB恰好调用了我们的增强覆盖的所有的A 的方法的可能性非常小。因此,BndB很可能在他的类空间中不会看到足够的类来定义增强类。实际上完整的类集合只有BndA能够提供。我们有麻烦了!
结果是我们必须桥接的不是框架和应用空间,而是框架空间和增强类的空间 - 所以,我们必须把策略从“每个应用空间一个桥”变为“每个增强类空间一个桥”。我们需要从应用空间到一些第三方bundle的类空间做过渡跳接,在那里, 应用导入其想让我们增强的类。但是我们如何做过渡跳接呢?很简单!如我们所知,每个类对象可以告诉我们它第一次被定义的类空间是什么。例如,我们要得到A 的类加载器,所需要做的就是调用A.class.getClassLoader()。在很多情况下我们没有一个类对象,只有类的名字,那么我们如何从一开 始就得到A.class?也很简单!我们可以让应用bundle给我们它所看到的名称“A”对应的类对象。然后我们就可以桥接那个类的空间与框架的空间。 这是很关键的一步,因为我们需要增强类和原始类在应用内是可以互换的。在类A可能的许多版本中,我们需要挑选被应用所使用的那个类的类空间。下面是框架如 何保持类加载器桥缓存的示意性例子:
... /* Ask the app to resolve the target class */ Bundle app = ... Class target = app.loadClass("com.acme.devices.SinisterEngine"); /* Get the defining classloader of the target */ ClassLoader targetSpace = target.getClassLoader(); /* Get the bridge for the class space of the target */ BridgeClassLoaderCache cache = ... ClassLoader bridge = cache.resolveBridge(targetSpace);
桥缓存看起来会是这样:
public class BridgeClassLoaderCache { private final ClassLoader primary; private final Map<ClassLoader, WeakReference<ClassLoader>> cache; public BridgeClassLoaderCache(ClassLoader primary) { this.primary = primary; this.cache = new WeakHashMap<ClassLoader, WeakReference<ClassLoader>>(); } public synchronized ClassLoader resolveBridge(ClassLoader secondary) { ClassLoader bridge = null; WeakReference<ClassLoader> ref = cache.get(secondary); if (ref != null) { bridge = ref.get(); } if (bridge == null) { bridge = new BridgeClassLoader(primary, secondary); cache.put(secondary, new WeakReference<ClassLoader>(bridge)); } return bridge; } }
为了防止保留类加载器带来的内存泄露,我们必须使用弱键和弱值。目标是不在内存中保持一个已卸载的bundle的类空间。我们必须使用弱值,因为每 个映射项目的值(BridgeClassLoader)都强引用着键(ClassLoader),于是以此方式否定它的“弱点”。这是WeakHashMap javadoc规定的标准建议。通过使用一个弱缓存我们避免了跟踪所有的bundle,而且不必对他们的生命周期做出反应。
可见性
好的,我们终于有了自己的外来的桥接类空间。现在我们如何在其中定义我们的增强类?如前所述问题,defineClass()是 BridgeClassLoader的一个受保护的方法。我们可以用一个公有方法来覆盖它,但这是粗野的做法。如果做覆盖,我们还需要自己编码来检查所请 求的增强类是否已经被定义。更好的办法是遵循类加载器设计的意图。该设计告诉我们应该覆盖findClass(),当findClass()认为它可以由 任意二进制源提供所请求类时会调用defineClass()方法。在findClass()中我们只依赖所请求的类的名称来做决定。所以我们的 BridgeClassLoade必须自己拿主意:
这是一个对“A$Enhanced”类的请求,所以我必须调用一个叫做"A"的类的增强类生成器!然后我在生成的字节数组上调用 defineClass()方法。然后我返回一个新的类对象。
这段话中有两个值得注意的地方。
- 我们为增强类的名称引入了一个文本协议 - 我们可以给我们的类加载器传入数据的单独一项 - 所请求的类的名称的字符串。同时我们需要传入数据中的两项 - 原始类的名称和一个标志,将其(原始类)标志为增强类的主语。我们将这两项打包为一个字符串,形式为[目标类的名称]"$Enhanced"。现在 findClass()可以寻找增强类的标志$Enhanced,如果存在,则提取出目标类的名称。这样我们引入了我们增强类的命名约定。无论何时,当我 们在堆栈中看到一个类名以$Enhanced结尾,我们知道这是一个动态生成的类。为了减少与正常类名称冲突的风险,我们将增强类标志做得尽可能特殊(例 如:$__service_proxy__)
- 增强是按需生成的 - 我们永远不会把一个增强类生成两次。我们继承的loadClass()方法首先会调用findLoadedClass(),如果失败会调用 parent.loadClass(),只有失败的时候它才会调用 findClass()。由于我们为名称用了一个严格的协议,保证findLoadedClass()在第二次请求相同类的增强类时候不会失败。这与桥接 类加载器缓存相结合,我们得到了一个非常有效的方案,我们不会桥接同样的bundle空间两次,或者生产冗余的增强类。
这里我们必须强调通过反射调用defineClass()的选项。cglib使用这种方法。当我们希望用户给我们传递一个可用的类加 载器时这是一种可行的方案。通过使用反射我们避免了在类加载器之上创建另一个类加载器的需要,只要调用它的defineClass()方法即可。
类空间一致性
到了最后,我们所做的是使用OSGi的模块层合并两个不同的、未关联的类空间。我们还引入了在这些空间中一种搜索顺序,其与邪恶的Java类路径搜 索顺序相似。实际上,我们破坏了OSGi容器的类空间一致性。这里是糟糕的事情发生的一个场景:
- 框架使用包
com.acme.devices
,需要的是1.0版本。 - 应用使用包
com.acme.devices
,需要的是2.0版本。 - 类A直接饮用
com.acme.devices.SinisterDevice
。 - 类
A$Enhanced
在他自己的实现中使用了com.acme.devices.SinisterDevice
。 - 因为我们搜索应用空间,首先
A$Enhanced
会被链接到com.acme.devices.SinisterDevice 2.0
版,而他的内部代码是基于com.acme.devices.SinisterDevice 1.0
编 译的。
结果应用将会看到诡异的LinkageErrors
或者ClassCastExceptions
。 不用说,这是个问题。
唉,自动处理这个问题的方式还不存在。我们必须简单的确保增强类的内部代码直接引用的是“非常私有的”类实现,不会被其他类使用。我们甚至可以为任 何我们可能希望使用的外部API定义私有的适配器,然后在增强类代码中引用这些适配器。一旦我们有了一个良好定义的实现子空间,我们可以用这个知识来限制 类泄露。现在我们仅仅向框架空间委托特殊的私有实现类的请求。这还会限定搜索顺序问题,使得应用优先搜索还是框架优先搜索对结果没有影响。让所有的事情都 可控的一个好策略是有一个专有的包来包含所有增强类实现代码。那么桥接加载器就可以检查以那个包开头的类的名称并将它们委托给框架加载器做加载。最终,我 们有时候可以对特定的单实例(singleton)包放宽这个隔离策略,例如org.osgi.framework
- 我们可以安全的直接基于org.osgi.framework
编译我们的增强类代码,因为在运行时所有在OSGi容器中的代码 都会看到相同的org.osgi.framework
- 这是由OSGi核心保证的。
把事情放到一起
所有关于这个类加载的传说可以被浓缩为下面的100行代码:
public class Enhancer { private final ClassLoader privateSpace; private final Namer namer; private final Generator generator; private final Map<ClassLoader , WeakReference<ClassLoader>> cache; public Enhancer(ClassLoader privateSpace, Namer namer, Generator generator) { this.privateSpace = privateSpace; this.namer = namer; this.generator = generator; this.cache = new WeakHashMap<ClassLoader , WeakReference<ClassLoader>>(); } @SuppressWarnings("unchecked") public <T> Class<T> enhance(Class<T> target) throws ClassNotFoundException { ClassLoader context = resolveBridge(target.getClassLoader()); String name = namer.map(target.getName()); return (Class<T>) context.loadClass(name); } private synchronized ClassLoader resolveBridge(ClassLoader targetSpace) { ClassLoader bridge = null; WeakReference<ClassLoader> ref = cache.get(targetSpace); if (ref != null) { bridge = ref.get(); } if (bridge == null) { bridge = makeBridge(targetSpace); cache.put(appSpace, new WeakReference<ClassLoader>(bridge)); } return bridge; } private ClassLoader makeBridge(ClassLoader targetSpace) { /* Use the target space as a parent to be searched first */ return new ClassLoader(targetSpace) { @Override protected Class<?> findClass(String name) throws ClassNotFoundException { /* Is this used privately by the enhancements? */ if (generator.isInternal(name)) { return privateSpace.loadClass(name); } /* Is this a request for enhancement? */ String unpacked = namer.unmap(name); if (unpacked != null) { byte[] raw = generator.generate(unpacked, name, this); return defineClass(name, raw, 0, raw.length); } /* Ask someone else */ throw new ClassNotFoundException(name); } }; } } public interface Namer { /** Map a target class name to an enhancement class name. */ String map(String targetClassName); /** Try to extract a target class name or return null. */ String unmap(String className); } public interface Generator { /** Test if this is a private implementation class. */ boolean isInternal(String className); /** Generate enhancement bytes */ byte[] generate(String inputClassName, String outputClassName, ClassLoader context); }
Enhancer仅仅 针对桥接模式。代码生成逻辑被具体化到一个可插拔的Generator中。该Generator接收一个上下文类加载器,从中可以得到类,使用反射来驱动 代码生成。增强类名称的文本协议也可以通过Name接口插拔。这里是一个最终的示意性代码,展示这么一个增强类框架是如何使用的:
... /* Setup the Enhancer on top of the framework class space */ ClassLoader privateSpace = getClass().getClassLoader(); Namer namer = ...; Generator generator = ...; Enhancer enhancer = new Enhancer(privateSpace, namer, generator); ... /* Enhance some class the app sees */ Bundle app = ... Class target = app.loadClass("com.acme.devices.SinisterEngine"); Class<SinisterDevice> enhanced = enhancer.enhance(target); ...
这里展示的Enhance框架不仅是伪代码。实际上,在撰写这篇文章期间,这个框架被真正构建出来并用两个在同一OSGi容器中同时运行的样例代码 生成器进行了测试。结果是类加载正常,现在代码在Google Code上,所有人都可以拿下来研究。
对于类生成过程本身感兴趣的人可以研究这两个基于ASM的生成器样例。那些在service dynamics上阅读文章的人也许注意到proxy generator使用ServiceHolder代码作为一个私有实现。
结论
这里展现的类加载特技在许多OSGi之外的基础框架中使用。例如桥接类加载器被用在Guice,Peaberry中,Spring Dynamic Modules则用桥接类加载器来使他们的AOP包装器和服务代理得以工作。当我们听说Spring的伙计们在将Tomcat适配到OSGi方面做了大量 工作时,我们可以推断他们还得做类加载位置转换或者更大量的重构来外化Tomcat的servlet加载。
感谢
这篇文章中的许多例子都是摘自Stuart McCulloch为Google Guice和Peaberry所写的出色代码。工业强度的类桥接的例子请看BytecodeGen.java from Google Guice和ImportProxyClassLoader.java from Peaberry。在那里你会看到如何处理其他方面的问题,例如安全,系统类加载器,更好的延迟缓存和并发。谢谢Stuart!
作者还要感谢Peter Kriens的Classy Solutions to Tricky Proxies。希望在本文中的对JVM链接的解释对于Peter的工作有用。谢谢你Peter!
关于作者
Todor Boev作为ProSyst一 名雇员已经在OSGi方面工作了8年。他热衷于将OSGi发展为JVM的一个通用编程环境。目前他既在专职研究这一领域,又是Peaberry项目 的一名贡献者。他在rinswind.blogspot.com维 护着一个博客。
发表评论
-
java String.getBytes()编码问题 (讲到实处了)
2012-12-12 11:26 823转载自: String.getBytes()的问 ... -
JSP中文验证码
2012-05-14 17:18 1262以上两篇文章的内容介绍了有关JSP中产生数字验证码跟中文验证 ... -
One-Jar之旅
2011-09-16 10:06 1792One-Jar之旅 1 ... -
Javamail中的常见中文乱码问题与解决办法
2011-09-09 09:48 1722在使用javamail api开发邮件服务系统时,我们常常会碰 ... -
理解Java ClassLoader机制
2011-07-28 11:24 1415再次阅读这篇文章时,有了更深的体会,特转载之。 理解Ja ... -
JAVA泛型简介
2011-07-22 13:41 1252另篇:http://www.java3z.com/cwbweb ... -
BCEL和Javassist的介绍
2011-07-18 10:49 1661BCEL 介绍: Byte Code E ... -
开源的java编译器jikes
2011-06-19 08:50 2275今天才知道java编译器还有个jikes这样的开源产品。 ... -
java的沙盒机制
2011-01-28 18:03 2067JAVA 的安全模型不同于传统的安全方法,传统的安全方法中 ... -
filter的调用顺序
2011-01-06 11:54 1318在一个大型项目中往往有多个servlet过滤器,但是这些ser ... -
JAVA操作COOKIE
2010-12-28 11:32 13001.设置Cookie Cookie cookie = ... -
监视器和锁
2010-12-17 16:54 1805http://topic.csdn.net/t/20050 ... -
关于volatile变量的理解
2010-12-12 13:21 1026前些日子在看些多线 ... -
关于Java 构造函数和继续特性的回顾
2010-12-06 09:21 1235java构造函数 java类库的设计者们通过提供 ... -
Java可变参数方法重载的错误3例
2010-12-05 23:28 1152JDK1.5引进了方法的可变参数,受到许多开发人员的青睐。 ... -
JDK1.5新特性
2010-12-05 23:19 749"JDK1.5"的一个重要主题就是 ... -
序列化中serialVersionUID的使用
2010-12-04 08:39 1420先来看一个例子: 定义一个bean: Java代码 ... -
Java 语言的 XPath API
2010-12-02 15:31 989如果要告诉别人买一加仑牛奶,您会怎么说?“请去买一加仑牛 ... -
java -verbose命令
2010-09-23 15:00 9439java -verbose[:class|gc|jni ... -
db2的jdbc驱动
2010-09-20 18:34 1316type1:jdbc-odbc桥 ...
相关推荐
3. **类加载器特技:OSGi代码生成**:"类加载器特技:OSGi代码生成.doc"可能探讨了OSGi如何利用其独特的类加载机制来实现动态代码生成和修改。由于每个bundle都有自己的类加载器,开发者可以创建在运行时动态生成或...
Tripple Farm:Match 3 Combination Game Complete Project 合成小镇三消Unity合成消除游戏项目游戏插件模版C# 支持Unity2020.3.4或更高 您知道像三合镇这样的著名益智游戏,并且您想制作一个自己的游戏。就是这样。这个包正好适合您。 这是一个完整的项目,您可以在零分钟内将其上传到 appstore 或 googleplay 商店。 基本规则: 3个或以上相同的道具可以匹配升级为新的道具。动物如果被困住,也可以合并。 羽毛: -移动(android/ios)就绪。 - 包含所有源代码。 -超过 12 座建筑/军团需要升级。 -三种特殊物品可以提供帮助。 - 三个不同的主题(场景和动物) -unity iap 支持 -Unity UI -广告位已准备好 -包含详细文档
内容概要:本文档是一份针对Java初学者的基础测试题,分为不定项选择题、简答题和编程题三大部分。选择题涵盖标识符、数组初始化、面向对象概念、运算符优先级、循环结构、对象行为、变量命名规则、基本
内容概要:本文详细介绍了如何利用MATLAB进行机器人运动学、动力学以及轨迹规划的建模与仿真。首先,通过具体的代码实例展示了正运动学和逆运动学的实现方法,包括使用DH参数建立机械臂模型、计算末端位姿以及求解关节角度。接着,讨论了雅克比矩阵的应用及其在速度控制中的重要性,并解释了如何检测和处理奇异位形。然后,深入探讨了动力学建模的方法,如使用拉格朗日方程和符号工具箱自动生成动力学方程。此外,还介绍了多种轨迹规划技术,包括抛物线插值和五次多项式插值,确保路径平滑性和可控性。最后,提供了常见仿真问题的解决方案,强调了在实际工程项目中需要注意的关键点。 适合人群:对机器人控制感兴趣的初学者、希望深入了解机器人运动学和动力学的学生及研究人员、从事机器人开发的技术人员。 使用场景及目标:① 学习如何使用MATLAB进行机器人运动学、动力学建模;② 掌握不同类型的轨迹规划方法及其应用场景;③ 解决仿真过程中遇到的各种问题,提高仿真的稳定性和准确性。 其他说明:文中提供的代码片段可以直接用于实验和教学,帮助读者更好地理解和掌握相关概念和技术。同时,针对实际应用中的挑战提出了实用的建议,有助于提升项目的成功率。
包括:源程序工程文件、Proteus仿真工程文件、配套技术手册等 1、采用51/52单片机作为主控芯片; 2、发送机:18B20测温、开关模拟灯光,发送数据; 3、接收机:接受数据、12864液晶显示;
内容概要:本文探讨了在微电网优化中如何处理风光能源的不确定性,特别是通过引入机会约束和概率序列的方法。首先介绍了风光能源的随机性和波动性带来的挑战,然后详细解释了机会约束的概念,即在一定概率水平下放松约束条件,从而提高模型灵活性。接着讨论了概率序列的应用,它通过对历史数据分析生成多个可能的风光发电场景及其概率,以此为基础构建优化模型的目标函数和约束条件。文中提供了具体的Matlab代码示例,演示了如何利用CPLEX求解器解决此类优化问题,并强调了参数选择、模型构建、约束添加以及求解过程中应注意的技术细节。此外,还提到了一些实用技巧,如通过调整MIP gap提升求解效率,使用K-means聚类减少场景数量以降低计算复杂度等。 适合人群:从事电力系统研究、微电网设计与运营的专业人士,尤其是那些对风光不确定性建模感兴趣的研究者和技术人员。 使用场景及目标:适用于需要评估和优化含有大量间歇性可再生能源接入的微电网系统,旨在提高系统的经济性和稳定性,确保在面对风光出力波动时仍能维持正常运作。 其他说明:文中提到的方法不仅有助于学术研究,也可应用于实际工程项目中,帮助工程师们制定更为稳健的微电网调度计划。同时,文中提供的代码片段可供读者参考并应用于类似的问题情境中。
linux之用户管理教程.md
内容概要:本文详细介绍了如何利用组态王和西门子S7-200 PLC构建六层或八层电梯控制系统。首先进行合理的IO地址分配,明确输入输出信号的功能及其对应的物理地址。接着深入解析了PLC源代码的关键部分,涵盖初始化、呼叫处理、电梯运行逻辑和平层处理等方面。此外,提供了组态王源代码用于实现动画仿真,展示了电梯轿厢的画面创建及动画连接方法。最后附上了详细的电气原理图和布局图,帮助理解和实施整个系统架构。 适合人群:从事工业自动化控制领域的工程师和技术人员,尤其是对PLC编程和人机界面开发感兴趣的从业者。 使用场景及目标:适用于教学培训、工程项目实践以及研究开发等场合。旨在为相关人员提供一个完整的电梯控制系统设计方案,便于他们掌握PLC编程技巧、熟悉组态软件的应用,并能够独立完成类似项目的开发。 其他说明:文中不仅包含了理论知识讲解,还分享了许多实际操作经验,如解决编码器丢脉冲的问题、优化平层停车精度的方法等。同时强调了安全性和可靠性方面的考虑,例如设置了多重保护机制以确保系统稳定运行。
在工业生产和设备运行过程中,滚动轴承故障、变压器油气故障等领域的数据分类与故障诊断至关重要。准确的数据分类与故障诊断能够及时发现设备潜在问题,避免故障恶化导致的生产事故与经济损失。LSTM能够捕获时序信息,马尔可夫场(MTF)能够一维信号转换为二维特征图,并结合CNN学习空间特征,MTF-1D-2D-CNN-LSTM-Attention模型通过将一维时序信号和二维图像融合,融合不同模态优势,并引入多头自注意力机制提高泛化能力,为数据分类与故障诊断提供了新的思路。实验结果表明,该模型在分类准确率、鲁棒性和泛化能力方面具有显著优势。多模态融合算法凭借其创新点和实验验证的有效性,在滚动轴承故障、变压器油气故障等领域展现出广阔的应用前景,有望推动相关领域故障诊断技术的进一步发展。 关键词:多模态融合;故障诊断;马尔可夫场;卷积神经网络;长短期记忆神经网络 适用平台:Matlab2023版本及以上。实验硬件设备配置如下:选用高性能计算机,搭载i7处理器,以确保数据处理和模型训练的高效性;配备16GB的内存,满足大规模数据加载和模型运算过程中的内存需求;使用高性能显卡,提供强大的并行计算能力,加速深度学习模型的训练过程。实验参数的选择依据多方面因素确定。
内容概要:本文档提供了一个面试模拟的指导框架,旨在为用户提供一个真实的面试体验。文档中的面试官名为Elian,被设定为性格温和冷静且思路清晰的形象,其主要职责是根据用户提供的简历信息和应聘岗位要求,进行一对一的模拟面试。面试官将逐一提出问题,确保每次只提一个问题,并等待候选人的回答结束后再继续下一个问题。面试官需要深入了解应聘岗位的具体要求,包括但不限于业务理解、行业知识、具体技能、专业背景以及项目经历等方面,从而全面评估候选人是否符合岗位需求。此外,文档强调了面试官应在用户主动发起提问后才开始回答,若用户未提供简历,面试官应首先邀请用户提供简历或描述应聘岗位; 适用人群:即将参加面试的求职者,特别是希望提前熟悉面试流程、提升面试技巧的人士; 使用场景及目标:①帮助求职者熟悉面试流程,提高应对实际面试的信心;②通过模拟面试,让求职者能够更好地展示自己的优势,发现自身不足之处并加以改进; 其他说明:此文档为文本格式,用户可以根据文档内容与面试官Elian进行互动,以达到最佳的模拟效果。在整个模拟过程中,用户应尽量真实地回答每一个问题,以便获得最贴近实际情况的反馈。
招聘技巧HR必看如何进行网络招聘和电话邀约.ppt
内容概要:本文详细介绍了利用三菱PLC(特别是FX系列)和组态王软件构建3x3书架式堆垛式立体库的方法。首先阐述了IO分配的原则,明确了输入输出信号的功能,如仓位检测、堆垛机运动控制等。接着深入解析了梯形图编程的具体实现,包括基本的左右移动控制、复杂的自动寻址逻辑,以及确保安全性的限位保护措施。还展示了接线图和原理图的作用,强调了正确的电气连接方式。最后讲解了组态王的画面设计技巧,通过图形化界面实现对立体库的操作和监控。 适用人群:从事自动化仓储系统设计、安装、调试的技术人员,尤其是熟悉三菱PLC和组态王的工程师。 使用场景及目标:适用于需要提高仓库空间利用率的小型仓储环境,旨在帮助技术人员掌握从硬件选型、电路设计到软件编程的全流程技能,最终实现高效稳定的自动化仓储管理。 其他说明:文中提供了多个实用的编程技巧和注意事项,如避免常见错误、优化性能参数等,有助于减少实际应用中的故障率并提升系统的可靠性。
内容概要:本文详细探讨了利用COMSOL进行电弧放电现象的模拟,重点在于采用磁流体方程(MHD)来耦合电磁、热流体和电路等多个物理场。文中介绍了关键的数学模型如磁流体动力学方程、热传导方程以及电路方程,并讨论了求解过程中遇到的技术难题,包括参数敏感性、求解器选择、网格划分等问题。此外,作者分享了许多实践经验,比如如何处理不同物理场之间的相互作用,怎样避免数值不稳定性和提高计算效率。 适用人群:适用于从事电弧放电研究的专业人士,尤其是那些希望通过数值模拟深入了解电弧行为并应用于实际工程项目的人群。 使用场景及目标:①帮助研究人员更好地理解和预测电弧放电过程中的各种物理现象;②为工程师提供优化电气设备设计的方法论支持;③指导使用者正确配置COMSOL软件的相关参数以确保高效稳定的仿真结果。 其他说明:尽管存在较高的计算复杂度和技术挑战,成功的电弧放电仿真能够显著提升对这一重要物理过程的认识水平,并促进相关领域的技术创新和发展。
内容概要:本文详细介绍了如何利用粒子群优化算法(PSO)改进极限学习机(KELM),以提升其在多维输入单维输出数据处理任务中的性能。首先简述了KELM的工作原理及其快速训练的特点,接着深入探讨了PSO算法的机制,包括粒子的速度和位置更新规则。然后展示了如何将PSO应用于优化KELM的关键参数,如输入权值和隐含层偏置,并提供了具体的Python代码实现。通过对模拟数据和实际数据集的实验对比,证明了PSO优化后的KELM在预测精度上有显著提升,尤其是在处理复杂数据时表现出色。 适合人群:对机器学习尤其是深度学习有一定了解的研究人员和技术爱好者,以及从事数据分析工作的专业人士。 使用场景及目标:适用于需要高效处理多维输入单维输出数据的任务,如时间序列预测、回归分析等。主要目标是通过优化模型参数,提高预测准确性并减少人工调参的时间成本。 其他说明:文中不仅给出了详细的理论解释,还附上了完整的代码示例,便于读者理解和实践。此外,还讨论了一些实用技巧,如参数选择、数据预处理等,有助于解决实际应用中的常见问题。
内容概要:本文介绍了利用粒子群算法(PSO)解决微网优化调度问题的方法。主要内容涵盖微网系统的组成(风力、光伏、储能、燃气轮机、柴油机)、需求响应机制、储能SOC约束处理及粒子群算法的具体实现。文中详细描述了目标函数的设计,包括发电成本、启停成本、需求响应惩罚项和SOC连续性惩罚项的计算方法。同时,阐述了粒子群算法的核心迭代逻辑及其参数调整策略,如惯性权重的线性递减策略。此外,还讨论了代码调试过程中遇到的问题及解决方案,并展示了仿真结果,证明了模型的有效性和优越性。 适合人群:从事电力系统优化、智能算法应用的研究人员和技术人员,特别是对微网调度感兴趣的读者。 使用场景及目标:适用于研究和开发微网优化调度系统,旨在提高供电稳定性的同时降低成本。具体应用场景包括但不限于分布式能源管理、工业园区能源调度等。目标是通过合理的调度策略,使微网系统在满足需求响应的前提下,实现经济效益最大化。 其他说明:本文提供的Matlab程序具有良好的模块化设计,便于扩展和维护。建议读者在理解和掌握基本原理的基础上,结合实际情况进行改进和创新。
KUKA机器人相关资料
基于多智能体的高层建筑分阶段火灾疏散仿 真及策略研究.pdf
Iterative Time Series Imputation by Maintaining Dependency Consistency (ACM TKDD 2024)
内容概要:本文详细探讨了带同步整流桥的交错PFC(功率因数校正)电路的设计与仿真实现。交错PFC通过多路PFC电路交错工作,降低了输入电流纹波,提高了功率密度。同步整流桥采用MOSFET代替传统二极管,减少了整流损耗,提升了效率。文中提供了关键代码片段,包括PWM控制、同步整流桥控制逻辑、电流环控制等,并介绍了如何在MATLAB/Simulink中搭建仿真模型,验证设计方案的有效性。此外,还讨论了仿真过程中遇到的问题及其解决方案,如死区时间处理、电流采样精度、负载突变应对等。 适合人群:从事电力电子设计的研究人员和技术工程师,尤其是对PFC技术和同步整流感兴趣的从业者。 使用场景及目标:适用于研究和开发高效的电源管理系统,旨在提高电能利用率,减少谐波污染,优化电源性能。目标是通过仿真实验验证设计方案的可行性,最终应用于实际硬件开发。 其他说明:文章强调了仿真与实际调试的区别,提醒读者在实际应用中需要注意的细节,如电流采样精度、死区时间和负载突变等问题。同时,提供了具体的代码实现和仿真技巧,帮助读者更好地理解和掌握这一复杂的技术。
内容概要:本文详细探讨了MATLAB环境下冷热电气多能互补微能源网的鲁棒优化调度模型。首先介绍了多能耦合元件(如风电、光伏、P2G、燃气轮机等)的运行特性模型,展示了如何通过MATLAB代码模拟这些元件的实际运行情况。接着阐述了电、热、冷、气四者的稳态能流模型及其相互关系,特别是热电联产过程中能流的转换和流动。然后重点讨论了考虑经济成本和碳排放最优的优化调度模型,利用MATLAB优化工具箱求解多目标优化问题,确保各能源设备在合理范围内运行并保持能流平衡。最后分享了一些实际应用中的经验和技巧,如处理风光出力预测误差、非线性约束、多能流耦合等。 适合人群:从事能源系统研究、优化调度、MATLAB编程的专业人士和技术爱好者。 使用场景及目标:适用于希望深入了解综合能源系统优化调度的研究人员和工程师。目标是掌握如何在MATLAB中构建和求解复杂的多能互补优化调度模型,提高能源利用效率,降低碳排放。 其他说明:文中提供了大量MATLAB代码片段,帮助读者更好地理解和实践所介绍的内容。此外,还提及了一些有趣的发现和挑战,如多能流耦合的复杂性、鲁棒优化的应用等。