1. 程式人生 > >java元件中的熱插拔(osgi)

java元件中的熱插拔(osgi)

大部分的開發這都是直接使用IDE,很少用人願意去探究Eclipse內部的情況,而Eclipse本身就是有一大堆的Plug-in組成,同時提供一個OSGi的環境供眾多的Plug-in使用。Eclipse與OSGI聯姻的行為是從Eclipse 基金在Eclipse 3.0 釋出的時候開始的,此後,Eclipse 逐步遷移到OSGi 框架中,並自己實現了一個OSGi 開源框架,取名為Equinox,該框架隨著每次Eclipse 的釋出也會相應的更新。Eclipse 之所以這麼做,其一是因為Eclipse 的外掛體系與OSGi 的設計思想不謀而合,其二也是因為OSGi 更為規範,其對外掛體系的定義也更為完整一些。事實證明Eclipse 在採用OSGi 架構後,無論從效能、可擴充套件性這兩個方面來講還是從二次開發的角度來定義,都取得巨大的成功。

從此以後,開發人員不僅能夠從網路中獲得俯拾皆是的Eclipse Plug-in,並在開發中發揮作用,同時也有很多的團體和個人也參與到了Plug-in的開發過程中。Eclipse Plug-in的最大特點就是熱插拔,當然這個特點的源泉便是OSGi。估計很多人都接觸過路由器,大部分的路由器都支援模組的熱插拔,這就意味著可以在路由器執行的狀況下給它動態的增加新的功能或者解除安裝不需要的功能,硬體界的這種熱插拔技術一直就是軟體界所追求的,而OSGI則使得熱插拔技術在軟體界成為現實。基於OSGI的系統,可通過安裝新的Bundle、更新或停止現有的Bundle來實現系統功能的插拔。

在這份文件中,我將圍繞著OSGi的熱插拔技術展開話題。與此同時會介紹OSGi同介面多Bundle服務的使用以及Servlet在OSGi中的使用。同樣,為了能夠給大家一個感性的認識,我決定還是提供一個小的工程例項來說明我要闡述的問題。這個工程將由一個介面定義Bundle、兩個介面實現Bundle以及一個客戶端呼叫Bundle。


1.實現介面定義Bundle

a. 編寫程式碼
 Activator.java

Java程式碼 複製程式碼
  1. package org.danlley.osgi.ds.common;   
  2. import org.osgi.framework.BundleActivator;   
  3. import org.osgi.framework.BundleContext;   
  4. publicclass Activator implements BundleActivator {   
  5. publicvoid start(BundleContext context) throws Exception {   
  6.     }   
  7. publicvoid stop(BundleContext context) throws Exception {   
  8.     }   
  9. }  
package org.danlley.osgi.ds.common;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

public class Activator implements BundleActivator {

	public void start(BundleContext context) throws Exception {
	}

	public void stop(BundleContext context) throws Exception {
	}

}

 Item.java

Java程式碼 複製程式碼
  1. package org.danlley.osgi.ds.services;   
  2. publicclass Item {   
  3.     String name;   
  4.     String id;   
  5. public Item(String name, String id) {   
  6. super();   
  7. this.name = name;   
  8. this.id = id;   
  9.     }   
  10. public Item() {   
  11. super();   
  12.     }   
  13. public String getName() {   
  14. return name;   
  15.     }   
  16. publicvoid setName(String name) {   
  17. this.name = name;   
  18.     }   
  19. public String getId() {   
  20. return id;   
  21.     }   
  22. publicvoid setId(String id) {   
  23. this.id = id;   
  24.     }   
  25. }  
package org.danlley.osgi.ds.services;

public class Item {
	String name;
	String id;

	public Item(String name, String id) {
		super();
		this.name = name;
		this.id = id;
	}

	public Item() {
		super();
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}
}

 MySampleListContributor.java 

Java程式碼 複製程式碼
  1. package org.danlley.osgi.ds.services;   
  2. import java.util.List;   
  3. publicinterface MySampleListContributor {   
  4. public List<Item> getItems();   
  5. }  
package org.danlley.osgi.ds.services;

import java.util.List;

public interface MySampleListContributor {
	public List<Item> getItems();
}

b. 修改配置檔案,釋出包路徑
 
 修改MANIFEST.MF配置檔案的內容,新增內容:Export-Package: org.danlley.osgi.ds.services,為後面的兩個Bundle實現提供介面,修改後MANIFEST.MF配置檔案的內容如下:
  -------------------------------------------------------
  Manifest-Version: 1.0
  Bundle-ManifestVersion: 2
  Bundle-Name: Osgi_ds_interface Plug-in
  Bundle-SymbolicName: osgi_ds_interface
  Bundle-Version: 1.0.0
  Bundle-ClassPath: target/classes/
  Bundle-Activator: org.danlley.osgi.ds.common.Activator
  Bundle-Vendor: some vendor
  Import-Package: org.osgi.framework;version="1.3.0"
  Export-Package: org.danlley.osgi.ds.services
  -------------------------------------------------------
 修改後build.properties配置檔案的內容
  ----------------------------------------
  source.target/classes/ = src/main/java/
  output.target/classes/ = target/classes/
  bin.includes = META-INF/,/
          target/classes/
  ----------------------------------------

2.定義Bundle介面實現

 a. 實現Bunble:osgi_ds_implements_a
  1). 定義類:MySampleListContributor

Java程式碼 複製程式碼
  1. package org.danlley.osgi.ds.impl;   
  2. import java.util.ArrayList;   
  3. import java.util.List;   
  4. import org.danlley.osgi.ds.services.Item;   
  5. import org.danlley.osgi.ds.services.MySampleListContributor;   
  6. publicclass ContributeA implements MySampleListContributor{   
  7. public List<Item> getItems(){   
  8.         List<Item> list=new ArrayList<Item>();   
  9.         list.add(new Item("ContributeA","1"));   
  10.         list.add(new Item("ContributeA","2"));   
  11.         list.add(new Item("ContributeA","3"));   
  12.         list.add(new Item("ContributeA","4"));   
  13. return list;   
  14.     }   
  15. }  
package org.danlley.osgi.ds.impl;

import java.util.ArrayList;
import java.util.List;
import org.danlley.osgi.ds.services.Item;
import org.danlley.osgi.ds.services.MySampleListContributor;

public class ContributeA implements MySampleListContributor{
	public List<Item> getItems(){
		List<Item> list=new ArrayList<Item>();
		list.add(new Item("ContributeA","1"));
		list.add(new Item("ContributeA","2"));
		list.add(new Item("ContributeA","3"));
		list.add(new Item("ContributeA","4"));
		return list;
	}
}

  2). 定義一個新目錄OSGI-INF用來存放介面實現的相關配置
  3). 在OSGI-INF目錄下定義檔案component.xml
   內容如下:

Xml程式碼 複製程式碼
  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <componentname="services">
  3. <implementation
  4. class="org.danlley.osgi.ds.impl.ContributeA"/>
  5. <service>
  6. <provide
  7. interface="org.danlley.osgi.ds.services.MySampleListContributor"/>
  8. </service>
  9. </component>

   說明:關於OSGi介面與實現的繫結事實上是有兩種實現的方式,一種便是利用這裡的配置檔案的宣告來實現其繫結的任務,另外還有一種方式是在程式中直接繫結。我們可以使用OSGi為我們提供的一個工具類org.osgi.framework.BundleContext為我們提供的方法registerService(String className,Object _instance, Dictionary arg)來完成這項工作,具體程式碼示例如下:

Java程式碼 複製程式碼
  1. private ServiceRegistration sr = null;   
  2. publicvoid start(BundleContext context) throws Exception {   
  3.     Hashtable props = new Hashtable();   
  4.     props.put("description""This an long value");   
  5.     sr = context.registerService(SomeClass.class.getName(),SomeClassImpl, props);   
  6. }  
private ServiceRegistration sr = null;
public void start(BundleContext context) throws Exception {
	Hashtable props = new Hashtable();
	props.put("description", "This an long value");
	sr = context.registerService(SomeClass.class.getName(),SomeClassImpl, props);
}

  4). 宣告OSGI-INF/component.xml

   -----------------------------------------------------
   Manifest-Version: 1.0
   Bundle-ManifestVersion: 2
   Bundle-Name: Osgi_ds_implements_a Plug-in
   Bundle-SymbolicName: osgi_ds_implements_a
   Bundle-Version: 1.0.0
   Bundle-ClassPath: target/classes/
   Bundle-Activator: org.danlley.osgi.ds.common.Activator
   Import-Package: org.osgi.framework;version="1.3.0"
   Require-Bundle: osgi_ds_interface
   Service-Component: OSGI-INF/component.xml
   -----------------------------------------------------

 b. 實現Bundle:osgi_ds_implement_b
  1). 定義類:MySampleListContributor

Java程式碼 複製程式碼
  1. package org.danlley.osgi.ds.impl;   
  2. import java.util.ArrayList;   
  3. import java.util.List;   
  4. import org.danlley.osgi.ds.services.Item;   
  5. import org.danlley.osgi.ds.services.MySampleListContributor;   
  6. publicclass ContributeB implements MySampleListContributor{   
  7. public List<Item> getItems(){   
  8.         List<Item> list=new ArrayList<Item>();   
  9.         list.add(new Item("ContributeB","[1]"));   
  10.         list.add(new Item("ContributeB","[2]"));   
  11. return list;   
  12.     }   
  13. }  
package org.danlley.osgi.ds.impl;

import java.util.ArrayList;
import java.util.List;

import org.danlley.osgi.ds.services.Item;
import org.danlley.osgi.ds.services.MySampleListContributor;

public class ContributeB implements MySampleListContributor{
	public List<Item> getItems(){
		List<Item> list=new ArrayList<Item>();
		list.add(new Item("ContributeB","[1]"));
		list.add(new Item("ContributeB","[2]"));
		return list;
	}
}

  2). 定義一個新目錄OSGI-INF用來存放介面實現的相關配置
  3). 在OSGI-INF目錄下定義檔案component.xml
   內容如下:

Java程式碼 複製程式碼
  1. <?xml version="1.0" encoding="UTF-8"?>   
  2. <component name="services">   
  3.     <implementation   
  4. class="org.danlley.osgi.ds.impl.ContributeB" />   
  5.     <service>   
  6.         <provide   
  7. interface="org.danlley.osgi.ds.services.MySampleListContributor" />   
  8.     </service>   
  9. </component>  
<?xml version="1.0" encoding="UTF-8"?>
<component name="services">
	<implementation
		class="org.danlley.osgi.ds.impl.ContributeB" />
	<service>
		<provide
			interface="org.danlley.osgi.ds.services.MySampleListContributor" />
	</service>
</component>

  4). 宣告OSGI-INF/component.xml

   -----------------------------------------------------
   Manifest-Version: 1.0
   Bundle-ManifestVersion: 2
   Bundle-Name: Osgi_ds_implement_b Plug-in
   Bundle-SymbolicName: osgi_ds_implement_b
   Bundle-Version: 1.0.0
   Bundle-ClassPath: target/classes/
   Bundle-Activator: org.danlley.osgi.ds.common.Activator
   Bundle-Vendor: some vendor
   Import-Package: org.osgi.framework;version="1.3.0"
   Require-Bundle: osgi_ds_interface
   Service-Component: OSGI-INF/component.xml
   -----------------------------------------------------

3. 定義客戶端Bundle:osgi_ds_client
 說明:在osgi_ds_client中,我們需要處理兩件事情
  i.  分別從兩個實現介面的Bundle中獲取資料
  ii. 註冊一個Servlet用來在瀏覽器中展現獲取的資料
 為此,我們需要設計一個工具類MenuHelper來獲取資料,並由ClientServlet來進行資料展現。
 a. 編寫程式碼
  MenuHelper.java

Java程式碼 複製程式碼
  1. package org.danlley.osgi.ds.client;   
  2. import java.util.ArrayList;   
  3. import java.util.List;   
  4. import org.danlley.osgi.ds.services.MySampleListContributor;   
  5. import org.osgi.service.component.ComponentContext;   
  6. publicclass MenuHelper {   
  7. static MenuHelper instance;   
  8.     List<MySampleListContributor> menuContributors = new ArrayList<MySampleListContributor>();   
  9. protectedvoid activate(ComponentContext context) {   
  10.         System.out.println("Calling activate");   
  11.         Object obj = null;   
  12. try {   
  13.             obj = context.locateService("menuHelper");   
  14.         } catch (Exception e) {   
  15.             e.printStackTrace();   
  16.         }   
  17.         System.out.println(obj);   
  18.         instance = this;   
  19.     }   
  20. protectedvoid deactivate(ComponentContext context) throws Exception {   
  21.         System.out.println("Calling deactivate");   
  22.     }   
  23. publicstatic MenuHelper getInstance() {   
  24. return instance;   
  25.     }   
  26. public List<MySampleListContributor> getMenuContributors() {   
  27. return menuContributors;   
  28.     }   
  29. publicvoid addMenuContributor(MySampleListContributor menuContributor) {   
  30.         System.out.println("Calling addMenuContributor");   
  31.         menuContributors.add(menuContributor);   
  32.     }   
  33. publicvoid removeMenuContributor(MySampleListContributor menuContributor) {   
  34.         System.out.println("Calling removeMenuContributor");   
  35.         menuContributors.remove(menuContributor);   
  36.     }   
  37. }  
package org.danlley.osgi.ds.client;

import java.util.ArrayList;
import java.util.List;
import org.danlley.osgi.ds.services.MySampleListContributor;
import org.osgi.service.component.ComponentContext;

public class MenuHelper {

	static MenuHelper instance;

	List<MySampleListContributor> menuContributors = new ArrayList<MySampleListContributor>();

	protected void activate(ComponentContext context) {
		System.out.println("Calling activate");
		Object obj = null;
		try {
			obj = context.locateService("menuHelper");
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println(obj);
		instance = this;
	}

	protected void deactivate(ComponentContext context) throws Exception {
		System.out.println("Calling deactivate");
	}

	public static MenuHelper getInstance() {
		return instance;
	}

	public List<MySampleListContributor> getMenuContributors() {
		return menuContributors;
	}

	public void addMenuContributor(MySampleListContributor menuContributor) {
		System.out.println("Calling addMenuContributor");
		menuContributors.add(menuContributor);
	}

	public void removeMenuContributor(MySampleListContributor menuContributor) {
		System.out.println("Calling removeMenuContributor");
		menuContributors.remove(menuContributor);
	}
}

  ClientServlet.java

Java程式碼 複製程式碼
  1. package org.danlley.osgi.ds.client.servlet;   
  2. import java.io.IOException;   
  3. import javax.servlet.http.HttpServlet;   
  4. import javax.servlet.http.HttpServletRequest;   
  5. import javax.servlet.http.HttpServletResponse;   
  6. import org.danlley.osgi.ds.client.MenuHelper;   
  7. import org.danlley.osgi.ds.services.Item;   
  8. import org.danlley.osgi.ds.services.MySampleListContributor;   
  9. publicclass ClientServlet extends HttpServlet {   
  10. /**  
  11.      * serialVersionUID  
  12.      */
  13. privatestaticfinallong serialVersionUID = -2631550134006854279L;   
  14. publicvoid doPost(HttpServletRequest servlet, HttpServletResponse response) throws IOException {   
  15.         doGet(servlet, response);   
  16.     }   
  17. publicvoid doGet(HttpServletRequest servlet, HttpServletResponse response) throws IOException {   
  18.         response.setContentType("text/html");   
  19.         response.getWriter().write("Hello  
  20. ");   
  21.         response.getWriter().write("<ul>");   
  22. for (MySampleListContributor mycontribute : MenuHelper.getInstance().getMenuContributors()) {   
  23. for (Item mItem : mycontribute.getItems()) {   
  24.                 response.getWriter().write(   
  25. "<li><a href=/"" + mItem.getId() + "/">" + mItem.getName() + "[" +    
  26.                     mItem.getId() + "]" + "</a></li>");   
  27.             }   
  28.         }   
  29.         response.getWriter().write("</ul>");   
  30.     }   
  31. }  
package org.danlley.osgi.ds.client.servlet;

import java.io.IOException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.danlley.osgi.ds.client.MenuHelper;
import org.danlley.osgi.ds.services.Item;
import org.danlley.osgi.ds.services.MySampleListContributor;

public class ClientServlet extends HttpServlet {
	/**
	 * serialVersionUID
	 */
	private static final long serialVersionUID = -2631550134006854279L;

	public void doPost(HttpServletRequest servlet, HttpServletResponse response) throws IOException {
		doGet(servlet, response);
	}

	public void doGet(HttpServletRequest servlet, HttpServletResponse response) throws IOException {
		response.setContentType("text/html");
		response.getWriter().write("Hello<br/>");
		response.getWriter().write("<ul>");
		for (MySampleListContributor mycontribute : MenuHelper.getInstance().getMenuContributors()) {
			for (Item mItem : mycontribute.getItems()) {
				response.getWriter().write(
					"<li><a href=/"" + mItem.getId() + "/">" + mItem.getName() + "[" + 
					mItem.getId() + "]" + "</a></li>");
			}
		}
		response.getWriter().write("</ul>");
	}

}

 b.註冊Servlet
  在工程根目錄定義檔案plugin.xml,同時也可以採用在Eclipse提供的視覺化介面進行操作。

Xml程式碼 複製程式碼
  1. <plugin>
  2. <extensionpoint="org.eclipse.equinox.http.registry.resources">
  3. <resource
  4. alias="/web"
  5. base-name="/page"/>
  6. </extension>
  7. <extensionpoint="org.eclipse.equinox.http.registry.servlets">
  8. <servlet
  9. alias="/exampleServlet"
  10. class="org.danlley.osgi.ds.client.servlet.ClientServlet"/>
  11. </extension>
  12. </plugin>

 c. 定義檔案目錄OSGI-INF
 d. 在OSGI-INF中增加檔案component.xml

Xml程式碼 複製程式碼
  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <componentname="menuHelper">
  3. <implementation
  4. class="org.danlley.osgi.ds.client.MenuHelper"/>
  5. <referencename="menuHelper"
  6. interface="org.danlley.osgi.ds.services.MySampleListContributor"
  7. cardinality="0..n"
  8. policy="dynamic"
  9. bind="addMenuContributor"
  10. unbind="removeMenuContributor"
  11. />
  12. </component>

  這樣,在系統初始化過程中,我們定義在MenuHelper中的activate方法首先會被執行,然後,locateService()查詢系統中是否有可用的"menuHelper",接著查詢MySampleListContributor例項,並由addMenuContributor方法完成合並工作。另外,當我們停掉客戶端呼叫Bundle時,deactivate方法會在整個Bundle被Stop之前被呼叫來執行一些清理工作。
 e. 修改配置檔案

  ------------------------------------------------------
  Manifest-Version: 1.0
  Bundle-ManifestVersion: 2
  Bundle-Name: Osgi_ds_client Plug-in
  Bundle-SymbolicName: osgi_ds_client;singleton:=true
  Bundle-Version: 1.0.0
  Bundle-ClassPath: target/classes/
  Bundle-Activator: org.danlleyo.osgi.ds.common.Activator
  Import-Package: org.osgi.framework;version="1.3.0"
  Service-Component: OSGI-INF/component.xml
  Require-Bundle: osgi_ds_interface,
   org.eclipse.osgi,
   org.eclipse.osgi.services,
   org.eclipse.equinox.http.registry,
   org.eclipse.equinox.common,
   org.eclipse.equinox.launcher,
   org.eclipse.equinox.http.servlet,
   org.eclipse.equinox.ds,
   org.eclipse.equinox.http.helper,
   org.eclipse.equinox.http.jetty,
   org.eclipse.core.jobs,
   org.apache.commons.logging,
   javax.servlet,
   org.mortbay.jetty,
   osgi_ds_implement_b,
   osgi_ds_implements_a
  ------------------------------------------------------

4. 系統執行
 a. 啟動服務:
  執行結果如下,說明服務成功啟動。
  ---------------------------------------------------------------
  osgi> Jul 23, 2008 2:08:58 PM org.mortbay.http.HttpServer doStart
  INFO: Version Jetty/5.1.x
  Jul 23, 2008 2:08:58 PM org.mortbay.util.Container start
  INFO: Started [email protected]
  Jul 23, 2008 2:08:58 PM org.mortbay.util.Container start
  INFO: Started HttpContext[/,/]
  Jul 23, 2008 2:08:58 PM org.mortbay.http.SocketListener start
  INFO: Started SocketListener on 0.0.0.0:80
  Jul 23, 2008 2:08:58 PM org.mortbay.util.Container start
  INFO: Started [email protected]
  Calling addMenuContributor
  Calling addMenuContributor
  Calling activate
  [email protected]
  ---------------------------------------------------------------
 b. 訪問服務
  訪問地址:http://localhost/exampleServlet 如果出現6條資料(4條ContributeA的資料和2條ContributeB的資料),則說明系統執行正常。
 c. 熱插拔Bundle
  檢視當前系統中所有執行Bundle的執行狀態及ID,結果如下:
  ------------------------------------------------------------------------------
  ss

  Framework is launched.

  id State       Bundle
  0 ACTIVE      org.eclipse.osgi_3.3.2.R33x_v20080105
  1879 ACTIVE      org.eclipse.osgi.services_3.1.200.v20070605
  2304 ACTIVE      javax.servlet_2.4.0.v200706111738
  3059 ACTIVE      org.eclipse.equinox.launcher_1.0.1.R33x_v20080118
  3060 ACTIVE      org.apache.commons.logging_1.0.4
  3065 ACTIVE      org.eclipse.equinox.http.registry_1.0.1.R33x_v20071231
  3066 ACTIVE      org.eclipse.equinox.registry_3.3.1.R33x_v20070802
  3067 ACTIVE      org.eclipse.equinox.common_3.3.0.v20070426
  3074 ACTIVE      org.apache.commons.logging_1.0.4.v200706111724
  3087 ACTIVE      org.eclipse.equinox.http.jetty_1.0.1.R33x_v20070816
  3095 ACTIVE      osgi_ds_interface_1.0.0
  3096 ACTIVE      org.eclipse.equinox.ds_1.0.0.qualifier
  3102 ACTIVE      org.eclipse.equinox.http.helper_1.0.0.qualifier
  3103 ACTIVE      osgi_ds_implement_b_1.0.0
  3104 ACTIVE      osgi_ds_implements_a_1.0.0
  3106 ACTIVE      org.eclipse.core.jobs_3.3.1.R33x_v20070709
  3109 ACTIVE      org.mortbay.jetty_5.1.11.v200706111724
  3112 ACTIVE      org.eclipse.equinox.http.servlet_1.0.1.R33x_v20070816
  3125 ACTIVE      osgi_ds_client_1.0.0
  ------------------------------------------------------------------------------

  執行stop 3104,執行結果如下:
   -----------------------------
   osgi> stop 3104
   Calling removeMenuContributor
   -----------------------------
  此時如果重新整理頁面,頁面上會僅剩兩天資料。說明osgi_ds_implements_a已被成功解除安裝。
  繼續執行stop 3103,執行結果如下:
   ------------------------------
   osgi> stop 3103
   Calling removeMenuContributor
   ------------------------------
  此時,重新整理頁面剛才展示的資料就會全部消失。
  繼續執行stop 3125,執行結果如下:
   --------------------
   osgi> stop 3125
   Calling deactivate
   ---------------------
  可見客戶端Bundle在停止之前,確實會執行deactivate方法來做一些清理工作。

 QQ群:9896150 【Java終結者】


 結束!

相關推薦

java元件osgi)

大部分的開發這都是直接使用IDE,很少用人願意去探究Eclipse內部的情況,而Eclipse本身就是有一大堆的Plug-in組成,同時提供一個OSGi的環境供眾多的Plug-in使用。Eclipse與OSGI聯姻的行為是從Eclipse 基金在Eclipse 3.0 釋出的時候開始的,此後,Eclipse

Linux Hot Plug)處理機制系列

將可移動裝置連入系統時,系統的後臺中會依次發生如下事件: 核心檢測到新硬體插入,然後分別通知hotplug和udev。前者用來裝入相應的核心模組(如usb-storage),而後者用來在/dev中建立相應的裝置節點(如/dev/sda1) udev建立了相應的裝置節點之後,

C# Winform下一個的MIS/MRP/ERP框架通用控制元件

一直對商業控制元件不感冒, 結合日常工作, 我寫了幾個常用控制元件. 一、下拉框控制元件(仿Access下拉框:F4下拉,自動輸入,支援單/多列顯示),可在Datagridview中使用。 1、常規: 2、Datagridview:  二、帶按鈕的文字框(可在Datagridview中使用): 1、常

在 ESXi 6.x和5.x虛擬機禁用添加/功能

客戶端 警告選項 虛機 所有 man nic win manage 下一步 現象:網卡和 SCSI 控制器顯示為可移除設備。與該虛擬硬件對應的“安全移除硬件”選項顯示在 Windows 系統任務欄中。如果正在使用 VMware View,您會註意到具有持久磁盤的 View

C# Winform下一個的MIS/MRP/ERP框架多語言方案)

文件加載 全局 查詢 分享 技術 變量 支持 對象 style 個別時候,我們需要一種多語種切換方案。   我的想方案是這樣的: 1、使用文本文本存儲多語言元素,應用程序啟動時加載到內存表中; 2、應用程序啟動時從配置文件加載語種定義; 3、所有窗體繼承自一個Base

C# Winform下一個的MIS/MRP/ERP框架11啟航)

aer tab chan byname 可能 清理 contex cati break   初學時,有了想法卻完全不知道該從何下指,此序列將拋磚引玉,與大家共同學習進步。   一個程序的初始,必然是啟動。   我的要求:   1、應用程序保持單例;   2、從配置文件加載一

C# Winform下一個的MIS/MRP/ERP框架15窗體基類場景1)

分享 需求 權限 檢測 表名 check 系統 ref 代碼 最基礎的窗體基類其實是通過應用場景反推的結構。 以下是場景一:   單表應用,普通的數據,比如單位/顏色/特殊字典等使用者少的,無需過多控制的可以使用一個數據表格來管理。   和Excel表格差不多,批量修改,統

C# Winform下一個的MIS/MRP/ERP框架16窗體基類場景2)

基礎資料 簡單 bubuko 圖片 主鍵 筆記 沒有 窗體 熱插拔 如果沒有特別需求,和場景1一樣只變更表名,主鍵字段,檢測字段等名稱,不需要寫其它代碼了。 * 清單列表+單筆編輯/保存,適用於大多數基礎資料管理以及簡單的單據資料錄入(當然,排版是要改一改的): *

C# Winform下一個的MIS/MRP/ERP框架14自動更新)

對於軟體來說,啟用自動更新是非常必要的。 根據軟體的應用場景,我們可以設計不同的更新模型。 目前,IMES框架執行在.Net framework 4.0下面,使用的Win系統版本在Win7,域內管控,平時業務調整也不是很頻繁。 所以,我的更新很粗放,就是刪除舊檔案,拷貝新檔案: 1、更新檔案放置在檔案

HDMI/DVI 顯示器與檢測原理HPD)

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

C# Winform下一個的MIS/MRP/ERP框架13窗體基類)

作為一個ERP資料處理框架,大部分的開發場景都差不多。 理想中,對於通用資料處理,我的步驟如下: 1、為窗體指定資料來源(資料表/查詢等); 2、拖入編輯控制元件,指定繫結欄位; 3、結束。 為此,我設計了幾個基類窗體,給它們分成幾個場景(如無資料/單表資料/主從表/多表關聯等),在不同的業務模型下

MyEclipse阿裏JAVA代碼規範P3C)的安裝及使用

sep 是否 。。 下載 手冊 本地 混合 upd 調整 JAVA代碼規範插件(P3C)是阿裏巴巴2017年10月14日在杭州雲棲大會上首發的,使之前的阿裏巴巴JAVA開發手冊正式以插件形式公開走向業界。插件的相關信息及安裝包都可以在GitHub(https://githu

Linux USB 驅動開發四)—— 那點事

Linux USB 驅動開發(四)—— 熱插拔那點事         學習USB熱插拔之前,先學習一些USB的硬體知識: 一、USB基礎概念 1、硬體知識(USB插座和插頭)        在最初的標

關於windows檢測的個人理解使用Qt開發)

在Qt中每一個視窗類(widget)都有一個處理windows訊息的函式,當windows出現熱插拔事件的時候,會向每個視窗傳送相應的WM_訊息,在Qt下,最終將調到natevieEvent函式;下面以QWidget為例: virtual bool QWidget::nat

C# Winform下一個的MIS/MRP/ERP框架簡介)

  Programmer普弱哥們都喜歡玩自己的框架,我也不例外。   理想中,這個框架要易於理解、易於擴充套件、易於維護;最重要的,易於CODING。   系統是1主體框架+N模組的多個EXE/DLL組成的,在主體框架開啟的時候,編譯完模組EXE可以馬上響應需求,不用退系統,不用重登入。   大概的目標:來一

C# Winform下一個的MIS/MRP/ERP框架12資料處理基類)

/// <summary> /// 資料庫連線基類 /// </summary> public class DBContext { /// <summary> /// 預設的加密方法Key,用於使用者

LinuxNetlink實現監控——核心與使用者空間通訊

1、什麼是NetLink?  它 是一種特殊的 socket,它是 Linux 所特有的,由於傳送的訊息是暫存在socket接收快取中,並不被接收者立即處理,所以netlink是一種非同步通訊機制。 系統呼叫和 ioctl 則是同步通訊機制。Netlink是面向資料包的服務

第二篇 基於.net搭建式web框架沙箱的構建)

/// <summary>沙箱管道 /// </summary> public class SandBoxChannel : MarshalByRefObject { /// <summary>沙箱內載入的程式集

第三篇 基於.net搭建式web框架重造Controller)

public class HuberController { public dynamic ViewBag = new DynamicViewBag(); public ViewDataDictionary ViewData = new ViewDataD

基於.net搭建式web框架實現原理)

第一節:我們為什麼需要一個熱插拔式的web框架? 模組之間獨立開發 假設我們要做一個後臺管理系統,其中包括“使用者活躍度”、“產品管理”、"賬單管理"等模組。每個模組中有自己的業務特性,這些模組都與具體業務高度耦合,很難由一個團隊開發完所有模組。這樣看來,由資料事業部的同事來開發“使用者活躍度”模