首页 文章 精选 留言 我的

精选列表

搜索[高并发],共10000篇文章
优秀的个人博客,低调大师

美国通与阿里展示“云到端”整体方案

今日,Qualcomm 宣布已经完成在 Qualcomm MDM9206 全球多模 LTE IoT 调制解调器上运行阿里云 Link物联网套件。此项进展有助于展示通过在 MDM9206 中预集成阿里云 Link 物联网套件,模组厂商和物联网开发者可以利用 LTE IoT 连接以及运行在 LTE 系统级芯片上的客户端软件,实现解决方案的快速开发和部署。双方对接的实现展示了云和端之间颇具成本效益的高度集成,能够更好地应对大量现有和新兴 LTE IoT 用例,包括智能交通(如共享单车)、智慧城市、以及诸如智能电网、智能表计(如电表、煤气表、水表)、资产追踪在内的多种工业物联网应用。 MDM9206 LTE IoT 调制解调器专为支持全球多模而设计,支持 eMTC(Cat M1)、NB-IoT(Cat NB-1)以及 2G/E-GPRS,并且与传统 LTE 连接相比,它能够推动下一代物联网产品与服务实现对成本效益、低功耗、长达数年的续航时间和更广覆盖的发展要求。MDM9206 LTE IoT 调制解调器集成主频高达 1.3GHz 的 ARM Cortex A7 CPU,具有强劲的应用处理能力,并支持各种外设接口。上述所有功能都通过一套全面、灵活又简便的 Qualcomm Application Programming Interfaces(应用程序接口)提供,从而为阿里云 Link 物联网套件提供一个开放的开发环境。该 API 还可支持运行在 A7处理器上的应用访问关键外部设备、GNSS(全球导航卫星系统)/定位和调制解调器功能。 阿里巴巴集团副总裁、阿里云 IoT 事业部总经理库伟表示:“我们和 Qualcomm 拥有共同愿景,致力于为全球提供领先、可靠的物联网产品,实现万物互联的美好世界。基于阿里云 Link 物联网套件和 Qualcomm 的 LTE IoT 调制解调器的‘云到端’整体方案,可以更好地加速应对中国广泛的商业与工业应用的发展要求,比如智能单车、智能生活、智能能源等。” Qualcomm 产品市场和销售副总裁孙刚表示: “我们非常高兴厂商和物联网开发者能够利用 LTE IoT 连接的能力实现与阿里云的接入,并创造全新的解决方案。Qualcomm 致力于进一步演进蜂窝连接技术、还有 4G 和 5G 技术,为中国和全球其他地区创新者的需求提供支持。” 据悉,迄今为止,已有近 60 款设计正采用 Qualcomm 的 MDM9206 LTE IoT 全球多模调制解调器,支持 LTE Cat M1 和 NB1。 本文出处:畅享网 本文来自云栖社区合作伙伴畅享网,了解相关信息可以关注vsharing.com网站。

优秀的个人博客,低调大师

仿拉手网底部菜单实现FragmentActivity+Fragment+RadioGroup

先把欢迎页和引导页的代码上传了http://download.csdn.net/detail/u013134391/7183787不要积分的。 底部菜单条实如今4.0曾经都是用tabhost。如今基本都被fargmentActivity加RadioGroup替代。以下实现底部菜单相同是用后者实现。 先声明一组四个的RadioButton的RadioGroup的单选button组,然后呢对照拉手网我们就发现样子太不一样了,我们的另一个单选button的样式,这个我们写RadioButton的android:button="@null"属性去除样式。 另外拉手网的是上面图片以下是名称的样式,并且他的名城和图片在不通状态下颜色不同,这个就须要我们写几个button选择器selector,我们通过selector的不通状态来设置不通的图片。名称也是一样。再设置RadioButton设置他的android:drawableTop=""属性,这样图片就会在字的上面了。这样我们的底部菜单条的布局就写完了。 在我们点击底部的单选button的时候怎么切换,在我们刚刚写的底部菜单的布局上加入一个FramentLayout,占领除了底部菜单条的全部地方。 然后在主界面里,监听RadioGroup的切换,监听checkedChanged,以下我们准备4个Fragmenet的切换界面。这里的Fragment由于要向下兼容,所以我们使用的是扩展包里的Fragment,Fragment重写onCreateView方法,载入布局文件。 我们须要写一个adapter来帮我们管理这四个界面的切换,这里的adapter我们就写的是FragmentStatePagerAdapter,这里构造方法须要传入參数FragmentManager,全部我们的MainActivity须要继承的是FragmentActivity,这样才干this.getSupportFragmentManager()获取一个FragmentManager,这里须要必要实现getcount,由于我们就4个界面就直接写4。getItem这里我们用来初始化界面,推断当前是那个界面0就是主页了,其它以此类推。然后在RadioGroup监听的地方使用FrameLayout替换进行界面的替换//详细代码例如以下 //将frameLayout替换成第index个Fragment Fragment fragment = (Fragment) fragmentAdapter.instantiateItem( frameLayout, index); //将第index个界面替换成fragment fragmentAdapter.setPrimaryItem(frameLayout, index, fragment); //提交 fragmentAdapter.finishUpdate(frameLayout); http://download.csdn.net/detail/u013134391/7190025 代码无积分下载 本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5246764.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

PostgreSQL 数据库HAProxy和PgBouncer配置可用架构

一.OS Packages CentOS 7.2 X64 pcre-devel openssl-devel zlib-devel 二.编译安装haproxy 1.编译安装 haproxy-1.7.1.tar.gz # make TARGET=linux2628 USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 PREFIX=/usr/local/haproxy ...... ...... ...... oto_http.o src/raw_sock.o src/backend.o src/tcp_rules.o src/lb_chash.o src/lb_fwlc.o src/lb_fwrr.o src/lb_map.o src/lb_fas.o src/stream_interface.o src/stats.o src/proto_tcp.o src/applet.o src/session.o src/stream.o src/hdr_idx.o src/ev_select.o src/signal.o src/acl.o src/sample.o src/memory.o src/freq_ctr.o src/auth.o src/proto_udp.o src/compression.o src/payload.o src/hash.o src/pattern.o src/map.o src/namespace.o src/mailers.o src/dns.o src/vars.o src/filters.o src/flt_http_comp.o src/flt_trace.o src/flt_spoe.o src/cli.o src/ev_poll.o src/ev_epoll.o src/ssl_sock.o src/shctx.o ebtree/ebtree.o ebtree/eb32tree.o ebtree/eb64tree.o ebtree/ebmbtree.o ebtree/ebsttree.o ebtree/ebimtree.o ebtree/ebistree.o -lcrypt -lz -ldl -lssl -lcrypto -ldl -L/usr/lib -lpcreposix -lpcre gcc -Iinclude -Iebtree -Wall -O2 -g -fno-strict-aliasing -Wdeclaration-after-statement -DCONFIG_HAP_LINUX_SPLICE -DTPROXY -DCONFIG_HAP_LINUX_TPROXY -DCONFIG_HAP_CRYPT -DUSE_ZLIB -DENABLE_POLL -DENABLE_EPOLL -DUSE_CPU_AFFINITY -DASSUME_SPLICE_WORKS -DUSE_ACCEPT4 -DNETFILTER -DUSE_GETSOCKNAME -DUSE_OPENSSL -DUSE_SYSCALL_FUTEX -DUSE_PCRE -I/usr/include -DCONFIG_HAPROXY_VERSION=\"1.7.1\" -DCONFIG_HAPROXY_DATE=\"2016/12/13\" \ -DSBINDIR='"/usr/local/haproxy/sbin"' \ -c -o src/haproxy-systemd-wrapper.o src/haproxy-systemd-wrapper.c gcc -g -o haproxy-systemd-wrapper src/haproxy-systemd-wrapper.o -lcrypt -lz -ldl -lssl -lcrypto -ldl -L/usr/lib -lpcreposix -lpcre # # make install PREFIX=/usr/local/haproxy install -d "/usr/local/haproxy/sbin" install haproxy "/usr/local/haproxy/sbin" install -d "/usr/local/haproxy/share/man"/man1 install -m 644 doc/haproxy.1 "/usr/local/haproxy/share/man"/man1 install -d "/usr/local/haproxy/doc/haproxy" for x in configuration management architecture cookie-options lua WURFL-device-detection proxy-protocol linux-syn-cookies network-namespaces DeviceAtlas-device-detection 51Degrees-device-detection netscaler-client-ip-insertion-protocol close-options SPOE intro; do \ install -m 644 doc/$x.txt "/usr/local/haproxy/doc/haproxy" ; \ done # 2.配置文件 # pwd /usr/local/haproxy # mkdir etc # vi ha_proxy.conf global log 127.0.0.1 local0 info maxconn 40960 user haproxy group haproxy daemon nbproc 1 chroot /usr/local/haproxy pidfile /usr/local/haproxy/haproxy.pid defaults log global mode tcp option tcplog option dontlognull option redispatch retries 3 maxconn 2000 timeout connect 5s timeout client 360s timeout server 360s frontend postgres-front bind 192.168.199.201:5432 default_backend postgresql backend postgresql mode tcp option pgsql-check user haproxy balance roundrobin server postgresql_01 192.168.199.201:5430 weight 1 check inter 5s rise 2 fall 3 server postgresql_02 192.168.199.201:5431 weight 1 check inter 5s rise 2 fall 3 listen admin-stats mode http option httplog bind 0.0.0.0:8888 stats enable stats refresh 30s stats uri /dbs stats realm welcome login\ Haproxy stats auth admin:admin stats admin if TRUE # # 3.配置PATH变量 # vi /etc/profile unset -f pathmunge export PATH=/usr/local/haproxy/sbin:$PATH 三、安装pgbouncer 1.安装libevent libevent-2.0.22-stable.tar.gz # ./configure # make # make install ln -s /usr/local/lib/libevent-2.0.so.5 /usr/lib64/libevent-2.0.so.5 2.安装pgbouncer # ./configure --prefix=/opt/pgbouncer/1.17.2 ...... ...... Results c-ares = no evdns = yes udns = no tls = yes # make # make install # cd /opt/pgbouncer/1.17.2/ # mkdir etc log # 配置文件 # cd /opt/pgbouncer/1.17.2/share/doc/pgbouncer # cp pgbouncer.ini userlist.txt /opt/pgbouncer/1.17.2/etc/ # cd /opt/pgbouncer/1.17.2/etc/ vi pgbouncer.ini [root@localhost etc]# more pgbouncer.ini ;; database name = connect string ;; ;; connect string params: ;; dbname= host= port= user= password= ;; client_encoding= datestyle= timezone= ;; pool_size= connect_query= [databases] ;; * indicate testdb, haproxy * = port=6432 dbname=testdb user=postgres password=111111 ; foodb over unix socket ;foodb = ; redirect bardb to bazdb on localhost ;bardb = host=localhost dbname=bazdb ; access to dest database will go with single user ;forcedb = host=127.0.0.1 port=300 user=baz password=foo client_encoding=UNICODE datestyle=ISO connect_query='SELECT 1' ; use custom pool sizes ;nondefaultdb = pool_size=50 reserve_pool_size=10 ; fallback connect string ;* = host=testserver ;; Configuration section [pgbouncer] ;;; ;;; Administrative settings ;;; logfile = /opt/pgbouncer/1.17.2/log/pgbouncer.log pidfile = /opt/pgbouncer/1.17.2/bin/pgbouncer.pid ;;; ;;; Where to wait for clients ;;; ; ip address or * which means all ip-s listen_addr = * listen_port = 5430 ; unix socket is also used for -R. ; On debian it should be /var/run/postgresql ;unix_socket_dir = /tmp ;unix_socket_mode = 0777 ;unix_socket_group = ;;; ;;; TLS settings for accepring clients ;;; ;; disable, allow, require, verify-ca, verify-full ;client_tls_sslmode = disable ;; Path to file that contains trusted CA certs ;client_tls_ca_file = <system default> ;; Private key and cert to present to clients. ;; Required for accepting TLS connections from clients. ;client_tls_key_file = ;client_tls_cert_file = ;; fast, normal, secure, legacy, <ciphersuite string> ;client_tls_ciphers = fast ;; all, secure, tlsv1.0, tlsv1.1, tlsv1.2 ;client_tls_protocols = all ;; none, auto, legacy ;client_tls_dheparams = auto ;; none, auto, <curve name> ;client_tls_ecdhcurve = auto ;;; ;;; TLS settings for connecting to backend databases ;;; ;; disable, allow, require, verify-ca, verify-full ;server_tls_sslmode = disable ;; Path to that contains trusted CA certs ;server_tls_ca_file = <system default> ;; Private key and cert to present to backend. ;; Needed only if backend server require client cert. ;server_tls_key_file = ;server_tls_cert_file = ;; all, secure, tlsv1.0, tlsv1.1, tlsv1.2 ;server_tls_protocols = all ;; fast, normal, secure, legacy, <ciphersuite string> ;server_tls_ciphers = fast ;;; ;;; Authentication settings ;;; ; any, trust, plain, crypt, md5 auth_type = md5 ;auth_file = /8.0/main/global/pg_auth auth_file = /opt/pgbouncer/1.17.2/etc/userlist.txt ;; Path to HBA-style auth config ;auth_hba_file = ;; Query to use to fetch password from database. Result ;; must have 2 columns - username and password hash. ;auth_query = SELECT usename, passwd FROM pg_shadow WHERE usename=$1 ;;; ;;; Users allowed into database 'pgbouncer' ;;; ; comma-separated list of users, who are allowed to change settings ;admin_users = user2, someadmin, otheradmin admin_users = pgbadmin ; comma-separated list of users who are just allowed to use SHOW command ;stats_users = stats, root ;;; ;;; Pooler personality questions ;;; ; When server connection is released back to pool: ; session - after client disconnects ; transaction - after transaction finishes ; statement - after statement finishes pool_mode = transaction ; ; Query for cleaning connection immediately after releasing from client. ; No need to put ROLLBACK here, pgbouncer does not reuse connections ; where transaction is left open. ; ; Query for 8.3+: ; DISCARD ALL; ; ; Older versions: ; RESET ALL; SET SESSION AUTHORIZATION DEFAULT ; ; Empty if transaction pooling is in use. ; server_reset_query = ; Whether server_reset_query should run in all pooling modes. ; If it is off, server_reset_query is used only for session-pooling. ;server_reset_query_always = 0 ; ; Comma-separated list of parameters to ignore when given ; in startup packet. Newer JDBC versions require the ; extra_float_digits here. ; ;ignore_startup_parameters = extra_float_digits ; ; When taking idle server into use, this query is ran first. ; SELECT 1 ; server_check_query = select 1 ; If server was used more recently that this many seconds ago, ; skip the check query. Value 0 may or may not run in immediately. server_check_delay = 10 ;; Use <appname - host> as application_name on server. ;application_name_add_host = 0 ;;; ;;; Connection limits ;;; ; total number of clients that can connect max_client_conn = 10240 ; default pool size. 20 is good number when transaction pooling ; is in use, in session pooling it needs to be the number of ; max clients you want to handle at any moment default_pool_size = 100 ;; Minimum number of server connections to keep in pool. min_pool_size = 80 ; how many additional connection to allow in case of trouble ;reserve_pool_size = 5 ; if a clients needs to wait more than this many seconds, use reserve pool ;reserve_pool_timeout = 3 ; how many total connections to a single database to allow from all pools ;max_db_connections = 50 ;max_user_connections = 50 ; If off, then server connections are reused in LIFO manner ;server_round_robin = 0 ;;; ;;; Logging ;;; ;; Syslog settings ;syslog = 0 ;syslog_facility = daemon ;syslog_ident = pgbouncer ; log if client connects or server connection is made ;log_connections = 1 ; log if and why connection was closed ;log_disconnections = 1 ; log error messages pooler sends to clients ;log_pooler_errors = 1 ;; Period for writing aggregated stats into log. ;stats_period = 60 ;; Logging verbosity. Same as -v switch on command line. ;verbose=0 ;;; ;;; Timeouts ;;; ;; Close server connection if its been connected longer. server_lifetime = 300 ;; Close server connection if its not been used in this time. ;; Allows to clean unnecessary connections from pool after peak. ;server_idle_timeout = 60 ;; Cancel connection attempt if server does not answer takes longer. server_connect_timeout = 10 ;; If server login failed (server_connect_timeout or auth failure) ;; then wait this many second. server_login_retry = 3 ;; Dangerous. Server connection is closed if query does not return ;; in this time. Should be used to survive network problems, ;; _not_ as statement_timeout. (default: 0) ;query_timeout = 0 ;; Dangerous. Client connection is closed if the query is not assigned ;; to a server in this time. Should be used to limit the number of queued ;; queries in case of a database or network failure. (default: 120) ;query_wait_timeout = 120 ;; Dangerous. Client connection is closed if no activity in this time. ;; Should be used to survive network problems. (default: 0) ;client_idle_timeout = 0 ;; Disconnect clients who have not managed to log in after connecting ;; in this many seconds. ;client_login_timeout = 60 ;; Clean automatically created database entries (via "*") if they ;; stay unused in this many seconds. ; autodb_idle_timeout = 3600 ;; How long SUSPEND/-R waits for buffer flush before closing connection. ;suspend_timeout = 10 ;; Close connections which are in "IDLE in transaction" state longer than ;; this many seconds. idle_transaction_timeout = 300 ;;; ;;; Low-level tuning options ;;; ;; buffer for streaming packets ;pkt_buf = 4096 ;; man 2 listen listen_backlog = 2048 ;; Max number pkt_buf to process in one event loop. ;sbuf_loopcnt = 5 ;; Maximum Postgres protocol packet size. ;max_packet_size = 2147483647 ;; networking options, for info: man 7 tcp ;; Linux: notify program about new connection only if there ;; is also data received. (Seconds to wait.) ;; On Linux the default is 45, on other OS'es 0. ;tcp_defer_accept = 0 ;; In-kernel buffer size (Linux default: 4096) ;tcp_socket_buffer = 0 ;; whether tcp keepalive should be turned on (0/1) ;tcp_keepalive = 1 ;; following options are Linux-specific. ;; they also require tcp_keepalive=1 ;; count of keepaliva packets ;tcp_keepcnt = 0 ;; how long the connection can be idle, ;; before sending keepalive packets ;tcp_keepidle = 0 ;; The time between individual keepalive probes. ;tcp_keepintvl = 0 ;; DNS lookup caching time ;dns_max_ttl = 15 ;; DNS zone SOA lookup period ;dns_zone_check_period = 0 ;; DNS negative result caching time ;dns_nxdomain_ttl = 15 ;;; ;;; Random stuff ;;; ;; Hackish security feature. Helps against SQL-injection - when PQexec is disabled, ;; multi-statement cannot be made. ;disable_pqexec=0 ;; Config file to use for next RELOAD/SIGHUP. ;; By default contains config file from command line. ;conffile ;; Win32 service name to register as. job_name is alias for service_name, ;; used by some Skytools scripts. ;service_name = pgbouncer ;job_name = pgbouncer ;; Read additional config from the /etc/pgbouncer/pgbouncer-other.ini file ;%include /etc/pgbouncer/pgbouncer-other.ini # # vi userlist.txt "pgbadmin" "pgbouncer123" "haproxy" "haproxy" # 3.修改数据库访问端口'6432' # netstat -ltnp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 844/sshd tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1572/master tcp 0 0 0.0.0.0:6432 0.0.0.0:* LISTEN 14974/postmaster # 设置PATH # vi /etc/profile export PATH=/opt/pgbouncer/1.17.2/bin:/usr/local/haproxy/sbin:$PATH 4.初始化数据库 建立数据库role haproxy postgres=# CREATE ROLE haproxy LOGIN ENCRYPTED PASSWORD 'md53b4da8c0b2ce93c288203e3d363895a6' SUPERUSER INHERIT CREATEDB CREATEROLE REPLICATION; 建立数据库 postgres=# \c postgres haproxy; postgres=# create database testdb; 建立表 testdb=# create table t1(id int, name varchar(20)); CREATE TABLE testdb=# 数据库访问控制 # vi pg_hba.conf host all all 192.168.199.0/24 trust 5.启动pgbouncer # chown postgres.postgres -R /opt/pgbouncer/ # su - postgres 1)pgbouncer01 $ pgbouncer -d /opt/pgbouncer/1.17.2/etc/pgbouncer.ini 2016-12-20 15:09:52.182 15013 LOG File descriptor limit: 1024 (H:4096), max_client_conn: 10240, max fds possible: 10350 $ 2) pgbouncer02 配置文件 ; ip address or * which means all ip-s listen_addr = * listen_port = 5431 ;;; ;;; Administrative settings ;;; logfile = /opt/pgbouncer/1.17.2/log/pgbouncer02.log pidfile = /opt/pgbouncer/1.17.2/bin/pgbouncer02.pid $ pgbouncer -d /opt/pgbouncer/1.17.2/etc/pgbouncer02.ini 2016-12-20 15:12:06.964 15020 LOG File descriptor limit: 1024 (H:4096), max_client_conn: 10240, max fds possible: 10350 $ 启动ha-proxy # haproxy -f /usr/local/haproxy/etc/ha_proxy.conf # netstat -lntp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:5430 0.0.0.0:* LISTEN 16497/pgbouncer tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 844/sshd tcp 0 0 0.0.0.0:5431 0.0.0.0:* LISTEN 16500/pgbouncer tcp 0 0 0.0.0.0:8888 0.0.0.0:* LISTEN 16510/haproxy tcp 0 0 192.168.199.201:5432 0.0.0.0:* LISTEN 16510/haproxy tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1572/master tcp 0 0 0.0.0.0:6432 0.0.0.0:* LISTEN 14974/postmaster tcp6 0 0 :::5430 :::* LISTEN 16497/pgbouncer tcp6 0 0 :::22 :::* LISTEN 844/sshd tcp6 0 0 :::5431 :::* LISTEN 16500/pgbouncer tcp6 0 0 ::1:25 :::* LISTEN 1572/master tcp6 0 0 :::6432 :::* LISTEN 14974/postmaster # 使用pgadmin客户端访问DB:testdb, user:haproxy, password:haproxy,IP:192.168.199.201, port:5432 测试连接 insert into t1 select generate_series(1,10000),'name'; $ more test.conf SELECT id FROM t1 WHERE id = 50; pgbench -h 192.168.199.201 -U haproxy -c 25 -j 25 -M prepared -n -s 500 -T 60 testdb -f ./test.conf 本文转自 pgmia 51CTO博客,原文链接:http://blog.51cto.com/heyiyi/1884440

优秀的个人博客,低调大师

.NET实现之(自己动手写内聚插件系统)

今天跟大家分享一下本人在“.NET简谈构件系统开发模式”一文中提到的软件架构设计思路的具体实现细节。 大家看了我这篇文章后,总问我为什么要起个这么怪异的名字“构件”而不用“插件”。其实这个名字在我脑子漂浮了很久,一直找不到合适的场合用它。 在一本书上是这样解释构件的:构件是可以更换的部件,并且这个部件是由一系列很小的部件组成,同样这些小的部件由更小的部件组成;我为什么要区分插件与构件主要原因是这两个名字所表达的思想不同。插件是可插、可卸的过程,没有强调无限极的递归实现子插件的意思,所以本人将其区分开来;当然也可以将这两种架构用同一名词描述,其实是大同小异了。下面我给大家带来怎么用这种设计思路来开发具体的系统。[王清培版权所有,转载请给出署名] 一:问题分析 在进行开发之前我们需要对整个系统有个分析,插件系统所强调的核心思想是能让所开发出来的系统应变日常需求,在功能升级的时候能很方便的进行更新。但这不是插件系统的最大的好处,我们用传统的三层、MVC开发也能实现这种好处,无非是将DLL文件放到目录下然后在重启就行了。 但是由于插件系统将功能点分的很细,大部分的功能在没有必要的情况下是不需要操作更新的。东西分的越小越好控制,但是开发的成本也随着控制粒度而变大。所以这个平衡点需要我们自己把握,不是所有的项目都适应这种架构。 插件系统是采用面向接口开发而不是面向类开发,在我们系统需求出来之后需要抽取功能点以进行插件抽象。这个时候就是考验一个项目的架构师的设计能力了。设计的不好导致后期开发无法进行下去,这类问题有很多种,比如:接口定义不明确、返回类型不明确、接口的公共部分是否抽象完全,也就是基类实现的是否合理等等;这些问题都很复杂,真正开发大型系统时,这些问题不能马虎,搞不好项目失败。从需求中抽出插件然后进行概要文档的编写、详要文档的编写。在一些大的方面设计文档可能很实用,但是我们程序员知道,一个设计文档不能通用,不是任何系统结构都能相同的设计文档,这就牵扯到了公司的文档编写方面了。如果设计文档无法应付这些复杂的系统结构,可以由架构师编写项目的架构设计文档,只有这样才能让开发人员一目了然,程序员才能发挥自主能动力能力,才能使项目完美收工。 我们刚才讲了,插件系统是采用面向接口设计、开发,也就是面向对象领域所提倡的开发思想。既然我们是以面向接口设计的,那么我们的插件是完全依赖于某些接口,就好比COM一样,你的接口不变,我就能找到你。最大的好处就是如果我的项目是需要第三方去实现的,那么我们的程序集文件DLL不需要签名,而不能由其他人跟换的插件使用签名,这样系统显的很有柔韧性。我喜欢大师们的开发思想,将自己的项目比作大型的机器人,任何部件是可装配、可更换的。不要将自己的项目开发的那么臃肿,那么脆弱。 插件系统对程序员的自身技术要求也是比较高的,这里面纵横交错,都是需要很深厚的技术功底的。都说这个语言好、那个语言好、只要精通什么都好。这个时候就考验你是否真的掌握了这门语言。语言本身是为了满足某些需求而存在的,JS是为了实现HTMLDOM的交互、CSS是为了修饰HTMLDOM、HTML是一种结构表示语言,这样语言的存在和使用都是有方向的,千万不要把语言和语言相比。由于插件自己的耦合几乎为零,这个时候我们都是通过接口进行调用,比如:我在一个接口里面操作了某些功能,同时这些同能要能及时的反馈到另一个插件中去。这样一个小小的功能,就需要我们运用很复杂的调用关系,任何一步处理的不到位,都会给后期的改动带来麻烦,甚至是灾难性的。 二:真实项目解析 我用了这种结构进行了系统开发,前期的构思是很头疼,但是后期的效果很不错的。 我在“.NET简谈构件系统开发模式”一文中已经进行了基本理论的分析,就不在讲了。直接用代码看吧; 1.主程序实现 在主程序要想使用某个插件的时候我们需要用统一的方法或者说是接口吧,能拿到我这个模块所对应的插件;请看代码: ///<summary> ///DataSourceOpen插件接口,上下文使用; ///</summary> BaseComebasecome; ///<summary> ///打开SqlServer数据源 ///</summary> privatevoidTools_Sqlmenu_Click(objectsender,EventArgse) { basecome=NewBaseCome(); (basecomeasDataSourceOpen).PassDataEvent+=newPassDataHandler(FrmDbServer_PassDataEvent); basecome.StartCome(); } privatevoidFrmDbServer_PassDataEvent(List<string>param,paramsstring[]par) { if(par.Length>0) if(!IsOpenSource(par[0])) BindTreeView(param,par); } 这是我的一个菜单的单击事件,这个菜单是主程序中的功能菜单,我需要在主程序中调用相对应的插件;上面的BaseCome是插件基类,实现了所有插件共同的一些特征,便于调用和实现;我在事件中使用了一个NewBaseCome()方法,这个方式是当前窗体中的公共方法,请看代码: ///<summary> ///统一获取构件基类 ///</summary> ///<returns>BaseCome对象</returns> privateBaseComeNewBaseCome() { return(PlugManager.PlugKernelManager.MainEventProcess("http://www.emed.cc/CodeBuilderStudio/Details/DataSourceOpen")asBaseCome); } 我通过这个公共方法获取到当前功能需要用的插件,PlugManager.PlugKernelManager.MainEventProcess()是插件管理器中的一个共有方法,这个方法会根据你传入的XML命名空间获取配置文件中的插件配置节点名称,你可能会问:“为什么要用这种结构的XML配置文件?”。其实我的个人习惯是使用有结构意义的XML文件,这是其一。其二是,我必须确定插件配置文件的唯一性,由于插件系统支持第三方实现,所以我更本不知道插件的名称是什么,所以我用XML命名空间进行规定。当我需要的时候,我直接通过XML命名空间就能获取到当前插件了。我们一起来看插件管理器的实现,请看代码: 2.插件管理器实现 ///<summary> ///主程序发生事件,需要启动相应构件 ///</summary> ///<paramname="xmlnamespace">构件所属的命名空间</param> ///<returns>本构件加载是否成功true:成功,false失败</returns> publicstaticobjectMainEventProcess(stringxmlnamespace) { try { PlugDomdom=domcollection[xmlnamespace]; if(dom==null) thrownewSystem.Exception( "在系统当前上下文构件集合中未能查找出"+xmlnamespace+"命名空间构件,请检查构件配置文件LoadConfig.xml是否进行了相应的设置;"); ComeLoadEvent(dom.Assembly);//构件初始化成功 returnReflectionDomObject(dom);//通过反射DLL文件,启动实现构件 } catch(Exceptionerr) { ComeCommonMethod.LogFunction.WritePrivateProfileString( "MainEventProcess",err.Source+"->"+err.TargetSite,err.Message,Environment.CurrentDirectory+"\\PlugManagerLog.ini"); returnnull; } } ///<summary> ///主程序发生事件,释放构件资源 ///</summary> ///<paramname="comeobject">构件对象</param> publicstaticvoidMainDisposeProcess(objectcomeobject) { try { (comeobjectasMain.Interface.ComeBaseModule.BaseCome).Dispose(); ComeExitEvent((comeobjectasMain.Interface.ComeBaseModule.BaseCome).ComeName); } catch(Exceptionerr) { ComeCommonMethod.LogFunction.WritePrivateProfileString( "MainDisposeProcess",err.Source+"->"+err.TargetSite,err.Message,Environment.CurrentDirectory+"\\PlugManagerLog.ini"); } } 由于管理器中的代码比较多,我只找了关键的代码。其实插件管理器的主要任务是起到一个衔接的作用,在主程序中通过插件管理器获取到插件对象。 插件管理器的大概实现的功能是这样的,系统启动时读取插件配文件,将配置文件进行对象化,也就是将XML节点进行抽取形成对象,这样便于我们使用。 在用户需要某个插件的时候,我们需要将插件以基类的形式给用户,这样可以消除插件管理器与接口之间的耦合。插件管理器只针对与插件基类。请看代码: ///<summary> ///内部方法,根据Assembly构件宿主程序集名称动态加载内部构件对象 ///</summary> ///<paramname="dom">构件文档对象模型PlugDom</param> privatestaticobjectReflectionDomObject(PlugDomdom) { try { Assemblyass=Assembly.LoadFile(Path.Combine(_comeloadpath,dom.Assembly)); Type[]entrytype=ass.GetTypes(); foreach(Typetypeinentrytype) { //所有构件基类,查找构件的入口点 if(type.BaseType.FullName=="Main.Interface.ComeBaseModule.BaseCome") { Main.Interface.ComeBaseModule.BaseComebasecome= System.Activator.CreateInstance(type,type.FullName,_comeloadpath,DateTime.Now) asMain.Interface.ComeBaseModule.BaseCome; //注册事件 NoteComeLifecycleProcess(basecome); returnbasecome; } } thrownewException("为能实现"+dom.XmlNameSpace+"标识构件,请检查构件配置文件"); } catch(Exceptionerr) { ComeCommonMethod.LogFunction.WritePrivateProfileString( "GetDomObjectByXmlns",err.Source+"->"+err.TargetSite,err.Message,Environment.CurrentDirectory+"\\PlugManagerLog.ini"); returnnull; } } ///<summary> ///记录所有构件共有的生命周期事件数据 ///</summary> privatestaticvoidNoteComeLifecycleProcess(Main.Interface.ComeBaseModule.BaseComebasecome) { basecome.ComeStartGoodsEvent+=newMain.Interface.ComeBaseModule.OnStartGoodsHandler(basecome_ComeStartGoodsEvent); basecome.ComeExitGoodsEvent+=newMain.Interface.ComeBaseModule.OnExitGoodsHandler(basecome_ComeExitGoodsEvent); basecome.ComeExceptionEvent+=newMain.Interface.ComeBaseModule.OnExceptionHandler(basecome_ComeExceptionEvent); } 这是插件管理器中比较重要的实现代码。包括反射、事件注册都在这里。Main.Interface.ComeBaseModule.BaseCome 就是插件基类,由于所有的插件需要进行整个生命周期管理,比如释放一些非托管资源、句柄之类的。所以我要进行统一的管理。在此进行事件注册,以方便监听。我们再看一下实现接口的插件代码: 3.插件实现 /* *author:南京.王清培 *codingtime:2011.5.28 *copyright:江苏华招网信息技术有限公司 *function:开发数据源构件实现,DataSourceOpen.Come项目; */ usingSystem; usingSystem.Collections.Generic; usingSystem.Text; usingMain.Interface.ComeBaseModule; namespaceDataSourceOpen.Come { ///<summary> ///继承构件基类,没有完全实现构件,继续向下传递实现; ///</summary> [Main.Interface.Attribute.WheTherNextTransfer(IfNextTransfer=true, ChildAssembly="CodeBuilderStudio.DataSourceOpen.Childe1", ChildInterface="DataSourceOpen.Interface.NextComeInterface")] publicclassControlContent:BaseCome,Main.Interface.DataSourceOpen { 这个插件继承了BaseCome对象,也就是插件基类。然后又实现了Main.Interface.dataSourceOpen接口,当主程序调用的时候就能拿到这个对象了。 总结:插件系统实现大概就讲完了,包扩接口、插件管理器等知识,希望能给各位需要进行插件开发的起到一个抛砖引玉的作用吧。 本文转自 王清培 51CTO博客,原文链接:http://blog.51cto.com/wangqingpei557/609175,如需转载请自行联系原作者

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册