- 浏览: 493735 次
- 性别:
- 来自: 长沙
-
文章分类
最新评论
-
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 822转载自: 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 1721在使用javamail api开发邮件服务系统时,我们常常会碰 ... -
理解Java ClassLoader机制
2011-07-28 11:24 1414再次阅读这篇文章时,有了更深的体会,特转载之。 理解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 1317在一个大型项目中往往有多个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 748"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都有自己的类加载器,开发者可以创建在运行时动态生成或...
KUKA机器人相关资料
内容概要:本文详细介绍了利用Matlab实现模拟退火算法来优化旅行商问题(TSP)。首先阐述了TSP的基本概念及其在路径规划、物流配送等领域的重要性和挑战。接着深入讲解了模拟退火算法的工作原理,包括高温状态下随机探索、逐步降温过程中选择较优解或以一定概率接受较差解的过程。随后展示了具体的Matlab代码实现步骤,涵盖城市坐标的定义、路径长度的计算方法、模拟退火主循环的设计等方面。并通过多个实例演示了不同参数配置下的优化效果,强调了参数调优的重要性。最后讨论了该算法的实际应用场景,如物流配送路线优化,并提供了实用技巧和注意事项。 适合人群:对路径规划、物流配送优化感兴趣的科研人员、工程师及高校学生。 使用场景及目标:适用于需要解决复杂路径规划问题的场合,特别是涉及多个节点间最优路径选择的情况。通过本算法可以有效地减少路径长度,提高配送效率,降低成本。 其他说明:文中不仅给出了完整的Matlab代码,还包括了一些优化建议和技术细节,帮助读者更好地理解和应用这一算法。此外,还提到了一些常见的陷阱和解决方案,有助于初学者避开常见错误。
内容概要:本文详细介绍了如何利用Simulink进行自动代码生成,在STM32平台上实现带57次谐波抑制功能的霍尔场定向控制(FOC)。首先,文章讲解了所需的软件环境准备,包括MATLAB/Simulink及其硬件支持包的安装。接着,阐述了构建永磁同步电机(PMSM)霍尔FOC控制模型的具体步骤,涵盖电机模型、坐标变换模块(如Clark和Park变换)、PI调节器、SVPWM模块以及用于抑制特定谐波的陷波器的设计。随后,描述了硬件目标配置、代码生成过程中的注意事项,以及生成后的C代码结构。此外,还讨论了霍尔传感器的位置估算、谐波补偿器的实现细节、ADC配置技巧、PWM死区时间和换相逻辑的优化。最后,分享了一些实用的工程集成经验,并推荐了几篇有助于深入了解相关技术和优化控制效果的研究论文。 适合人群:从事电机控制系统开发的技术人员,尤其是那些希望掌握基于Simulink的自动代码生成技术,以提高开发效率和控制精度的专业人士。 使用场景及目标:适用于需要精确控制永磁同步电机的应用场合,特别是在面对高次谐波干扰导致的电流波形失真问题时。通过采用文中提供的解决方案,可以显著改善系统的稳定性和性能,降低噪声水平,提升用户体验。 其他说明:文中不仅提供了详细的理论解释和技术指导,还包括了许多实践经验教训,如霍尔传感器处理、谐波抑制策略的选择、代码生成配置等方面的实际案例。这对于初学者来说是非常宝贵的参考资料。
内容概要:本文详细介绍了基于西门子S7-200 PLC和组态王的机械手搬运控制系统的实现方案。首先,文章展示了梯形图程序的关键逻辑,如急停连锁保护、水平移动互锁以及定时器的应用。接着,详细解释了IO分配的具体配置,包括数字输入、数字输出和模拟量接口的功能划分。此外,还讨论了接线图的设计注意事项,强调了电磁阀供电和继电器隔离的重要性。组态王的画面设计部分涵盖了三层画面结构(总览页、参数页、调试页)及其动画脚本的编写。最后,分享了调试过程中遇到的问题及解决方案,如传感器抖动、输出互锁设计等。 适合人群:从事自动化控制领域的工程师和技术人员,尤其是对PLC编程和组态软件有一定基础的读者。 使用场景及目标:适用于自动化生产线中机械手搬运控制系统的开发与调试。目标是帮助读者掌握从硬件接线到软件逻辑的完整实现过程,提高系统的稳定性和可靠性。 其他说明:文中提供了大量实践经验,包括常见的错误和解决方案,有助于读者在实际工作中少走弯路。
内容概要:本文详细介绍了基于西门子1200PLC的污水处理项目,涵盖了PLC程序结构、通信配置、HMI设计以及CAD原理图等多个方面。PLC程序采用梯形图和SCL语言相结合的方式,实现了复杂的控制逻辑,如水位控制、曝气量模糊控制等。通讯配置采用了Modbus TCP和Profinet双协议,确保了设备间高效稳定的通信。HMI设计则注重用户体验,提供了详细的报警记录和趋势图展示。此外,CAD图纸详尽标注了设备位号,便于后期维护。操作说明书中包含了应急操作流程和定期维护建议,确保系统的长期稳定运行。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是对PLC编程、HMI设计和通信配置感兴趣的从业者。 使用场景及目标:适用于污水处理厂及其他类似工业控制系统的设计、实施和维护。目标是帮助工程师掌握完整的项目开发流程,提高系统的可靠性和效率。 其他说明:文中提供的具体代码片段和设计思路对于理解和解决实际问题非常有价值,建议读者结合实际项目进行深入学习和实践。
内容概要:本文详细介绍了基于5电平三相模块化多电平变流器(MMC)的虚拟同步发电机(VSG)控制系统的构建与仿真。首先,文章描述了MMC的基本结构和参数设置,包括子模块电容电压均衡策略和载波移相策略。接着,深入探讨了VSG控制算法的设计,特别是有功-频率和无功-电压下垂控制的具体实现方法。文中还展示了通过MATLAB-Simulink进行仿真的具体步骤,包括设置理想的直流电源和可编程三相源来模拟电网扰动。仿真结果显示,VSG控制系统能够在面对频率和电压扰动时迅速恢复稳定,表现出良好的调频调压性能。 适合人群:从事电力电子、电力系统自动化及相关领域的研究人员和技术人员。 使用场景及目标:适用于研究和开发新型电力电子设备,特别是在新能源接入电网时提高系统的稳定性。目标是通过仿真验证VSG控制的有效性,为实际应用提供理论支持和技术指导。 其他说明:文章提供了详细的代码片段和仿真配置,帮助读者更好地理解和重现实验结果。此外,还提到了一些常见的调试技巧和注意事项,如选择合适的仿真步长和参数配对调整。
内容概要:本文详细介绍了在一个复杂的工业自动化项目中,如何利用西门子S7-1200 PLC为核心,结合基恩士视觉相机、ABB机器人以及G120变频器等多种设备,构建了一个高效的立体库码垛系统。文中不仅探讨了不同设备之间的通信协议(如Modbus TCP和Profinet),还展示了SCL和梯形图混合编程的具体应用场景和技术细节。例如,通过SCL进行视觉坐标解析、机器人通信心跳维护等功能的实现,而梯形图则用于处理简单的状态切换和安全回路。此外,作者分享了许多实际调试过程中遇到的问题及其解决方案,强调了良好的注释习惯对于提高代码可维护性的关键作用。 适用人群:从事工业自动化领域的工程师和技术人员,尤其是对PLC编程、机器人控制及多种通信协议感兴趣的从业者。 使用场景及目标:适用于需要整合多种工业设备并确保它们能够稳定协作的工作环境。主要目标是在保证系统高精度的同时降低故障率,从而提升生产效率。 其他说明:文中提到的一些具体技术和方法可以作为类似项目的参考指南,帮助开发者更好地理解和应对复杂的工业控制系统挑战。
KUKA机器人相关资料
java脱敏工具类
内容概要:本文详细介绍了基于自抗扰控制(ADRC)的表贴式永磁同步电机(SPMSM)双环控制系统的建模与实现方法。该系统采用速度环一阶ADRC控制和电流环PI控制相结合的方式,旨在提高电机在复杂工况下的稳定性和响应速度。文章首先解释了选择ADRC的原因及其优势,接着展示了ADRC和PI控制器的具体实现代码,并讨论了在Matlab/Simulink环境中搭建模型的方法和注意事项。通过对不同工况下的仿真测试,验证了该控制策略的有效性,特别是在负载突变情况下的优越表现。 适合人群:从事电机控制、自动化控制及相关领域的研究人员和技术人员,尤其是对自抗扰控制感兴趣的工程师。 使用场景及目标:适用于需要高精度、高响应速度的工业伺服系统和其他高性能电机应用场景。目标是提升电机在复杂环境下的稳定性和抗扰能力,减少转速波动和恢复时间。 其他说明:文中提供了详细的代码示例和调试技巧,帮助读者更好地理解和实施该控制策略。同时,强调了在实际应用中需要注意的问题,如参数调整、输出限幅等。
java设计模式之责任链的使用demo
内容概要:本文详细介绍了两相交错并联Buck/Boost变换器的硬件结构和三种控制方式(开环、电压单环、双环)的实现方法及仿真结果。文中首先描述了该变换器的硬件结构特点,即四个MOS管组成的H桥结构,两相电感交错180度工作,从而有效减少电流纹波。接着,针对每种控制方式,具体讲解了其配置步骤、关键参数设置以及仿真过程中需要注意的问题。例如,在开环模式下,通过固定PWM占空比来观察原始波形;电压单环则引入PI控制器进行电压反馈调节;双环控制进一步增加了电流内环,实现了更为精确的电流控制。此外,文章还探讨了单向结构的特点,并提供了仿真技巧和避坑指南。 适合人群:从事电力电子研究的技术人员、高校相关专业师生。 使用场景及目标:适用于希望深入了解两相交错并联Buck/Boost变换器的工作原理和技术细节的研究者,旨在帮助他们掌握不同控制方式的设计思路和仿真方法。 其他说明:文中不仅提供了详细的理论解释,还有丰富的实例代码片段,便于读者理解和实践。同时,作者分享了许多宝贵的实践经验,有助于避免常见的仿真错误。
第二场c++A组
数控磨床编程.ppt
内容概要:本文详细介绍了利用COMSOL软件进行N2和CO2混合气体在热-流-固三场耦合作用下增强煤层气抽采的数值模拟。首先,通过设定煤岩材料参数,如热导率、杨氏模量等,构建了煤岩物理模型。接着,引入达西定律和Maxwell-Stefan扩散方程,建立了混合气体运移方程,考虑了气体膨胀系数和吸附特性。在应力场求解方面,采用自适应步长和阻尼系数调整,确保模型稳定。同时,探讨了温度场与气体运移的耦合机制,特别是在低温条件下CO2注入对煤体裂隙扩展的影响。最后,通过粒子追踪和流线图展示了气体运移路径和抽采效率的变化。 适合人群:从事煤层气开采、数值模拟以及相关领域的科研人员和技术工程师。 使用场景及目标:适用于需要优化煤层气抽采工艺的研究机构和企业,旨在通过数值模拟提高抽采效率并减少环境影响。 其他说明:文中提供了详细的MATLAB和COMSOL代码片段,帮助读者理解和复现模型。此外,强调了模型参数选择和求解器配置的重要性,分享了作者的实际经验和常见问题解决方法。
基于Bode的引线补偿器设计 计算给定G、相位裕度、交叉频率和安全裕度要求的引线补偿器。 计算给定电厂G、PM和Wc要求的铅补偿器,并运行ControlSystemDesigner进行验证。
KUKA机器人相关文档
包括:源程序工程文件、Proteus仿真工程文件、配套技术手册等 1、采用51/52单片机作为主控芯片; 2、采用数码管显示计时秒数,单个操作均为20秒; 3、采用继电器控制进水、排水; 4、采用L298驱动电机; 5、具有强洗、标准洗、弱洗、甩干四种模式; 6、强洗流程:进水、三轮洗涤、排水、甩干、进水、漂洗、排水、甩干; 7、标准洗流程:进水、两轮洗涤、排水、甩干、进水、漂洗、排水、甩干; 8、弱洗流程:进水、一轮洗涤、排水、甩干、进水、漂洗、排水、甩干;
内容概要:本文详细介绍了如何利用MATLAB 2018b搭建微电网并网逆变器模型,采用电压电流双环控制配合SPWM调制技术,实现稳定的并网控制。文中涵盖了PI参数整定、下垂系数计算、SPWM载波生成、PLL改进等多个关键技术环节,并分享了调试经验和常见问题解决方案。通过具体的代码示例展示了各模块的具体实现方法,强调了电流环和电压环的设计要点以及下垂控制的应用。 适合人群:具有一定电力电子和控制系统基础知识的研究人员和技术人员,尤其是从事微电网研究和开发的专业人士。 使用场景及目标:适用于希望深入了解微电网并网控制机制及其具体实现方式的学习者和从业者。主要目标是掌握电压电流双环控制与SPWM调制相结合的方法,理解下垂控制的工作原理,并能够独立完成相关系统的建模与调试。 其他说明:文中提供的代码片段可以直接用于MATLAB/Simulink环境进行实验验证,同时附带了许多宝贵的实践经验,如参数选择、波形分析等,有助于提高实际项目的成功率。此外,还特别提到了一些容易被忽视但至关重要的细节,比如载波频率设置、死区时间和谐波抑制等问题。