读书笔记-Java高级编程-魏勇

本书《Java高级编程》由魏勇撰写,详细介绍了Java的高级特性,包括javadoc、jar、JMX、SVN、Git等工具的使用,以及链式存储、队列、堆栈、树、二叉树等数据结构。同时,书中还涵盖了多层网络结构、Socket、WebSocket,以及MINA、状态转换等网络编程技术。此外,讨论了Java类加载器、加密算法、JAAS、JSSE、JCE等安全相关主题,并涉及RMI、CORBA和EJB在远程对象交互中的应用。最后,书中探讨了OSGi作为Java动态模块编程标准的概念和实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java高级编程 魏勇 清华大学出版社 

ISBN-9787302450948

仅供参考, 自建索引, 以备后查

 

一、javadoc、jar、JMX、SVN、Git

/** 

 * 此类注释出在执行命令后生成文档,而且只在public方法、属性上有效

 * @author Colin

 * @version 1.3.2 Colin 2020-11-19 <br/>

 *                  1.3.3 Colin 2021-01-19

 */

# javadoc [options] [packagenames] [sourcefiles] [@files]

  [options]

-sourcepath E:\workspace\socket-http test.java0.socket_http

    切换到 E:\workspace\socket-http 文件夹开始编译包 

-classpath E:\workspace\maven-repository\

    引用 E:\workspace\maven-repository\ 目录中的jar引用类

  [packagenames] 不支持递归子包,无通配符

  [@files] 读取文件内容进行编译

如 package-compile.txt 文件内容如下

com.baidu.advertisement

com.baidu.videoshare

则执行  # javadoc -d apidoc @package-compile.txt 后

会对文件中的包中的java文件进行编译


install4j   exe4j   TowerJ   jaxegen.exe   InstallAnywhere   JET   JOVE  JToExe

MANIFESAT.MF        一般放置于 META-INF/ 文件夹

Manifest-Version: 1.0

Main-Class: test.java0.socket_http.SocketHttpFileStarter

Created-By: 1.0.1 Colin

# cd /d E:\workspace\socket-http

# jar cvfm socket-http.jar MANIFEST.MF test.java0.socket_http


JMX (Java Management Extensions) 为应用程序、设备、系统植入管理功能的框架

虽然这么印刷的,还没太深入理解,倒是加入到了项目中,发现也挺有用

javax.management.MBeanServer  JMX代理层核心 (个人理解:类似于反射工具类)

javax.management.ObjectName 用于为类指定标识名,用于查找类实例对象


public static void main(String[] args) throws Exception {
	String dir = "E:/workspace/filesocket/src/main/webapp";
	HttpFileServerSocket hfss = HttpFileServerSocket.getInstance().setWebDir(dir);
	new Thread(hfss).start();

	ObjectName sn = new ObjectName("HttpFileServerSocket:name=DirSetter");
    /// MBeanServer mbs = MBeanServerFactory.createMBeanServer();
	MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); /// 推荐
    /// 为 hfss 实例注册  之后可以进行管理
	mbs.registerMBean(hfss, sn);
	
}

打到 JAVA_HOME\bin 目录下 jconsole 

# jconsole 运行 

选择对应的进程

对于我的这个程序来说,作用就是动态修改了某个属性  


Subversion:SVN服务提供程序

TortoiseSVN:SVN独立客户端

SVNService.exe:把SVN加入到Windows服务

TortoiseGit:Git客户端软件

 

二、顺序、链式存储、队列、堆栈、树、二叉树

队列 First In First Out   Vector   rear: 队列尾部   front: 队列头部

堆栈 Last In First Out   Stack

  如:进制转换可以把 余数 及最后 依次入栈,再全部出栈即可


Java中的链式是自身引用实现,C、C++中则使用指针实现

class ListNode { Object data; ListNode next; }

单向链表、单向循环链表、双向链表

interface ListIterator extends Iterator { } Java中的双向遍历接口


先根     中   左  右 

中根     左   中  右

后根     左   右  中

T=(D,R)   D:所有结点集合  R:节点关系集合

二叉树 Binary Tree  顺序存储(完全二叉树比较合适)或链式存储均可实现


Enumeration   传统数据结构使用此类遍历

public SequenceInputStream(Enumeration<? extends InputStream> e) { }

Properties extends Hashtable<Object, Object> { }

BitSet   <========

 

三、多层网络结构、Socket、WebSocket

OSI 网络七层结构 

应用层 表示层 会话层 传输层 网络层 数据链路层 物理层

TCP/IP Transport Control Protocol / Internet Protocol

  • 链路层:数据链路层或网络接口层,与操作系统的设备驱动程序和网络接口卡交互
  • 网络层:IP地址  InetAddress Inet4Address Inet6Address
  • 传输层:端口号,TCP/IP 数据传输控制 Socket ServerSocket DatagramPacket DatagramSocket MulticastSocket
  • 应用层:最上层协议 ftp http smtp pop3 telnet

URL Uniform Resource Locator

openStream()    getContent()    openConnection()

URLConnection

MIME  Multipurpose Internet Mail Extensions 多用途Internet邮件扩展

IP地址分类   <========


Socket 实现 Web 服务器   

可以参考 https://blog.csdn.net/u011225581/article/details/112516987

HTTP请求报文       请求行  请求头部  空行  请求数据 


Java中 浏览器 组件

JEditorPane  Lobo+FramePanel  JDIC+JDICPlus  SWT+Browser

J2ME cHTML Browser

Dooble

j2wap  WAP浏览器

Proteus  基于J2ME的手机浏览器

jCellBrowser  同上

MicroBrowser4ME  同上

MoDaBrowser


WebSocket  可以参考 https://blog.csdn.net/u011225581/article/details/112465492

HTTP请求头中  Upgrade: websocket   表示需要切换到 websocket 进行通信

websocket 聊天程序示例


SMTP Simple Mail Transfer Protocol 简单邮件传输协议

邮件发送示例

 

四、MINA、状态转换

MINA Multipurpose Infrastructure for Network Applications

    ApacheDirectory、AsyncWeb、ApacheQpid、QuickFIX/J、

    Openfire、SubEthaSTMP、red5

基于 JAVA NIO 采用非阻塞异步传输,事件驱动、支持TCP/IP等

NioSocketAcceptor      NioSocketConnector

IoSession                     IoHandlerAdapter IoHandler

sessionCreated()    sessionOpened()      sessionIdle()

exceptionCaught()  messageReceived()  messageSent()


ApacheMINA网络应用一般架构

  IO服务:执行实际IO操作,支持不同协议,如TCP/IP、UDP/IP、串口、管道

  IO过滤器:转换字节流到指定对象与数据结构;对输入输出的数据进行处理

  IO处理器:具体业务逻辑

MINA实现数学计算示例:Java调用JS引擎

MINA与Spring框架Ioc/DI整合使用

MINA在Android上应用,Service服务中加入连接获取 Session


MINA状态机 - 事件驱动控制流程

传统应用程序:遵循事先程序设定,很少有事件改变执行流程

事件驱动程序:根据接收事件执行相应流程,由用户事件改变控制流程

@Transitions({

    @Transition(on="", in="", next=""),

    @Transition(on="", in="", next="")

})

@Transition(on="触发事件名称", in="起始状态", next="结束状态", weight=10)

StateContext   StateContextLookup  StateControl 

mina: IoSessionStateContextLookup -> IoSession

          IoHandlerTransition   IoHandlerTransitions

StateMachineProxyBuilder  SingletonStateContextLookup

方法匹配规格,根据 @Transition 及方法的参数数量与类型

状态继承   @State Root   @State(Root) Playing

使用 StateContext 而非 IoSession 是因为不需要类型转换


Java5开始支持 静态导入 


Windows 安装 Openfire    XMPP/Jabber 协议

%Openfire%\resources\database  各类数据库表的脚本

%Openfire%\conf\openfire.xml  <database>存储配置的数据库连接信息

Spark 客户端 可与 MSN、ICQ 等 IM 服务器通信  Openfire需要安装 IM Gateway 插件

ClarosChat  基于 Ajax 的Web即时消息客户端

Jeti Java即时消息客户端

JWChat 基于Web的客户端

Ashcast SwingGUI客户端

NFC Chat 

JClaim


Eclipse 导入 openfire_src 二次开发


Openfire Socket 网络连接  ConnectionManager+ConnectionManagerImpl

  • 服务器与服务器之间的连接  端口 5269
  • 外部组件和服务器之间的连接  端口5275
  • 多元连接 5269
  • 客户端与服务器的连接  5222
  • 客户端TLS/SSL与服务器的连接 5223

Protocol Codec Factory  通过 Decoder  Encoder 扩展支持各种 Socket 网络协议

自定义需实现  interface ProtocolCodecFactory { }  参考 XMPPCodecFactory { }

Openfire 客户端实现 IoHandler 的类是 ClientConnectionHandler 继承处 ConnectionHandler

 

五、Java类加载器ClassLoader、加密算法、JAAS、JSSE、JCE、DES、MD5

类加载器:JVM类装载器Bootstrap、自定义装载器(extends ClassLoader)

    无用户装载器的情况下,使用 ClassLoader.getSystemClassLoader() 装载用户类

    Bootstrap ClassLoader:C++实现,所有类加载器的最终父加载器,装载关键Java类

    ExtClassLoader:位于Luncher.java文件,装载Java支行环境扩展包 (jre/lib/ext) 等,

         虽然被Bootstrap加载,但父加载器类被设置为null (C++/Java)

    AppClassLoader:位于Luncher.java文件,在ExtClassLoader之后同样被Boostrap加载,

         但是父类被设置为 ExtClassLoader。 父类和哪个加载器来加载,不一定一一对应

Parent Delegation 模型

    类似于树形结构,先由父级去加载,父级会先判断由父级加载,若不成功则自己加载

命名空间

    加载的类被放入JVM,相应有一个完全匹配类名对应,而 加载器 作为此名称的一部分,

    所以被不同加载器加载的同一个类是两个不同的类

运行时包

    和命名空间类似,防止用户自定义类冒充核心类库

    如:定义  java.lang.OOObject  被用户自定义类加载器加载,但是由于装载器不同,因此

           不能自由访问 java.lang 包中其它的可见成员

扩展ClassLoader方法

   extends ClassLoader { @Override public Class findClass(Stirng name) { } }


消息摘要:检验消息完整性, MD4、MD5,SHA-1    java.security.MessageDigest

/// MD5方式生成文件 file 摘要信息
md5 = MessageDigest.getInstance("MD5");
input = new DigestInputStream(
    new BufferedInputStream(
        new FileInputStream(file)), md5);
int len = 0;
byte[] buf = new byte[2048];
while ((len=input.read(buf))>0) {}
byte[] digest = input.getMessageDigest().digest();
input.close();
javax.xml.bind.DatatypeConverter.printHexBinary(digest);

JCE Java密码术扩展 Java Cryptography Extension

JSSE Java安全套接字扩展 Java Secure Sockets Extension

JAAS Java认证和授权服务 Java Authentication and Authorization Service

JGSS Java能用安全性服务 Java General Security Service

CertPath API Java证书路径API Certication Path API

SSL 安全套接字层 Secure Sockets Layer 

TLS 传输层安全性 Transport Layer Security 


应该使用 transient 关键字对密码等敏感字段进行标识


Java支持的消息摘要算法

MD2、MD5:128位算法

SHA-1:160位算法

SHA-256、SHA-383、SHA-512

plainText = "要生成摘要的数据";
/// plainText == bytes[] 同样适用
byte[] bytes = new byte[12];
new Random().nextBytes(bytes);
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(bytes); /// 前后加干扰
md.update(plainText.getBytes());
md.update(bytes); /// 前后加干扰
return DatatypeConverter.printHexBinary(md.digest());

消息认证码:密钥和数据一起用来生成消息摘要

Java支持  HMAC/SHA-1   HMAC/MD5

/// 生成密钥
SecretKey md5key = KeyGenerator.getInstance("HmacMD5").generateKey();
/// Mac 类用于生成消息认证码
Mac mac = Mac.getInstance("HmacMD5");
    mac.init(md5key);
    mac.update(plainText);
/// 消息认证码
byte[] bytes = mac.doFinal();

Base64编码     0-25  'A'-'Z'    26-51 'a'-'z'    52-61  '0'-'9'  62'+'  63'/'

    Java 中 byte 用两个字节 0xFF 表示,即最多由 8 位 二进制 组成

    Base64最多64个字符,用 6 位 二进制 2^6 足以表示

    转换:byte[] 转换二进制位,每 6 位进行分隔,有余数则加入 零值字节(0000 0000)

    一字节是8位二进制,补完之后的总字节 % 24 == 0 即可    因为 24%8==24%6

ASCII 中  ’A‘ = 65 = 0100 0001  ===>  则补位变为 0100 0001 0000 0000 0000 0000

切分为两段,每段 6 位二进制,即 010000(16) 010000(16) 000000(=) 000000(=)

即 ASCII 中 'A' 对就的 Base64 编码为 QQ==


私钥密码术    密码块  填充  序列密码  密码方式

/// 生成DES密钥Key
KeyGenerator kg = KeyGenerator.getInstance("DES");
kg.init(56);
Key key = kg.generatorKey();
/// 获取加密对象实例
/// DES加密 ECB方式 PKCS5填充
Cipher cipher = Cipher.getIntance("DES/ECB/PKCS5Padding");

/// 加密明文
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encrypts = cipher.doFinal(plainText); /// 

/// 解密
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] normals = cipher.doFinal(encrypts);

私钥可以加密单一位或位块,通常是64位大小,若有余数,则需要进行填充

如填充全0或全1    PKCS5为私钥常用填充方式  PKCS1为公钥常用方式

ECB:电子密码本 Electronic Code Block

CBC:密码块链接  Cipher Block Chaining

CFB:密码反馈方式 Cipher Feedback Mode

OFB:输出反馈方式 Output Feedback Mode

PCBC:填充密码块链接  Propagating Cipher Block Chaining 

私钥算法 DES TripleDES AES RC2 RC4 RC5 Blowfish PBE 


公钥加密  不对称加密 密钥对

    生成密钥对,公钥对外发布,公钥加密则使用私钥解密,私钥加密则使用公钥解密

    公钥加密相对比较慢

/// 生成密钥对 含 公钥 私钥
KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
gen.initialize(2048);
KeyPair pair = gen.generateKeyPair();
/// 使用 公钥 或 私钥 加密对象
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pair.getPublic()); 
///cipher.init(Cipher.ENCRYPT_MODE, pair.getPrivate()); 

/// 加密明文
byte[] encrypts = cipher.doFinal(plainText);

/// 初始化解密对象 
cipher.init(Cipher.DECRYPT_MODE, pair.getPrivate()); 
///cipher.init(Cipher.DECRYPT_MODE, pair.getPublic());
/// 
byte[] decrypts = cipher.doFinal(encrypts);

数字签名  确认身份

数字签名不提供消息加密,需要把消息明文和签名发送给对方,所以必须配合加密技术使用

MessageDigest md = ...
byte[] digests = md.digest(); /// 消息摘要

/// 生成密钥对 含 公钥 私钥
KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
gen.initialize(2048);
KeyPair pair = gen.generateKeyPair();
/// 使用 公钥 或 私钥 加密对象
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pair.getPrivate());  /// 此处使用私钥

/// 操作明文叫作加密  操作消息摘要叫数字签名 
byte[] encrypts = cipher.doFinal(digests);

可以直接使用 RSA算法用于数字签名和加密,名为 DSA Digital Signature Algorithm

MD2/RSA   MD5/RSA   SHA1/DSA   SHA1/RSA

/// 生成密钥对 含 公钥 私钥
KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
gen.initialize(2048);
KeyPair pair = gen.generateKeyPair();
/// 签名对象
Signature sig = Signature.getInstance("MD5WithRSA");
sig.initSign(key.getPrivate());
sig.update(plainText);
byte[] signatures = sig.sign(); /// 对明文plainText的摘要进行签名
public static void main(String[] args) throws Exception {
	String plainText = "Hello,you!I-am-going-to-destroy-you!";
	byte[] bytes = plainText.getBytes("utf-8");
	
	/// 密钥对
	KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
	generator.initialize(1024);
	KeyPair kpr = generator.generateKeyPair();
	PrivateKey prk = kpr.getPrivate();  /// 私钥 
	PublicKey puk = kpr.getPublic();    /// 公钥
	
	byte[] md5_bs = md5(bytes); /// MD5
	System.out.println("MD5:" + DatatypeConverter.printHexBinary(md5_bs));
	
	byte[] rsa_bs = rsa(md5_bs, prk);
	System.out.println("RSA:" + DatatypeConverter.printHexBinary(rsa_bs));
	
	byte[] de_rsa = de_rsa(rsa_bs, puk);
	System.out.println("---:" + DatatypeConverter.printHexBinary(de_rsa));
	
	byte[] sign_bs = sign(bytes, prk);
	System.out.println("SIGN:" + DatatypeConverter.printHexBinary(sign_bs));
	
	boolean verified = sign_verify(bytes, puk, sign_bs);
	System.out.println("verified:" + verified);
}

static byte[] md5(byte[] bytes) throws Exception {
	MessageDigest md = MessageDigest.getInstance("MD5");
	md.update(bytes);
	return md.digest();
}

static byte[] rsa(byte[] bytes, PrivateKey key) throws Exception {
	Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
	cipher.init(Cipher.ENCRYPT_MODE, key);
	return cipher.doFinal(bytes);
}

static byte[] de_rsa(byte[] bytes, PublicKey key) throws Exception {
	Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
	cipher.init(Cipher.DECRYPT_MODE, key);
	return cipher.doFinal(bytes);
}

static byte[] sign(byte[] plainText, PrivateKey key) throws Exception {
	Signature sig = Signature.getInstance("MD5WithRSA");
	sig.initSign(key);
	sig.update(plainText);
	return sig.sign();
}

static boolean sign_verify(byte[] bytes, PublicKey key, byte[] signs) throws Exception {
	Signature sig = Signature.getInstance("MD5WithRSA");
	sig.initVerify(key);
	sig.update(bytes);
	return sig.verify(signs);
}

数字证书  密钥、证书管理工具keytool  密钥库keystore  信任公钥库truststore  认证中心CA

JDK 支持 X.509 数字证书标准

CertPath API 证书路径,操作读取系统密钥等     证书链   CRL证书撤销列表   证书期限

    CRL Certificate Revocation Lists

代码签名:对打包的jar文件进行签名

jarsigner 签名工具   提供jar、私钥、证书   生成jar文件的签名版本

# jarsigner HelloWorld.jar KeyAlias   /// 用KeyAlias密钥来进行签名

# jarsigner -verify -verbose -certs HelloWorld.jar  /// 验证下


SSL/TLS  

https连接成功,服务器向客户端发送证书,客户端用本机安装的公共CA证书来校验服务器身份

    因为RSA公钥加密时间较长,一般做法是,客户端生成新密钥,如DES、RC4,

    然后把此密钥用服务器的公钥加密,并传送给服务器,之后会话就用新密钥来加密解密

/// 证书路径环境变量
System.setProperty("javax.net.ssl.trustStore", KEYSTORE_PATH);

/// 读取证书创建SSLContext上下文
SSLContext context = SSLContext.getInstance("TLS");
KeyStore ks ...
ks.load(..)
KeyManagerFactory kf ...
kf.init(..)
context.init(kf.getKeyManagers(), null, null); 

/// 根据证书生成 SSLServerSocket
ServerSocket ss = context.getServerSocketFactory()
    .createServerSocket(PORT);
/// 设置信任证书库的位置
System.setProperty("javax.net.ssl.trustStore", KEYSTORE_PATH);
System.setProperty("javax.net.debug", "ssl.handshake"); /// 打印LOG

/// 使用已安装的信任证书库创建 Socket
Socket socket = SSLSocketFactory.getDefault()
    .createSocket(REMOTE_IP, REMOTE_PORT);
/// socket instanceof SSLSocket   true

生成RSA密钥

# keytool -genkey -alias key-unique-alias -keyalg RSA 

导出公钥证书

# keytool -export -alias key-unique-alias -keystore path -file export_file

导入公钥证书

# keytool -import -trustcacerts -alias key-unique-alias -file cer_file -keystore path


SSL协议位于 TCP/IP协议与各种应用层协议之间

    SSL记录协议 SSL Record Protocol:数据封装、压缩、加密

    SSL握手协议 SSL Handshake Protocol:身份认证、协商加密算法、交换加密密钥

SSL协议针对双方,多方时参考 Visa和MasterCard 制定的 SET 协议

SSL 连接:单次数据传输,与SSL会话相关联

SSL 会话:客户端与服务器的关联,被SSL连接共享,避免频繁创建

 

六、远程对象 RMI CORBA IDL EJB+JBoss+Tomcat

RMI 远程方法调用 Remote Method Invocation 

远程对象interface (调用端、服务端)extends java.rmi.Remote { }

远程对象实现类(服务端)extends UnicastRemoteObject ... throws RemoteException { }

RMI调用类(调用端 Naming.lookup)

RMI发布类(服务端 Naming.bind  Name.rebind)


查找某接口实现 RemoteException NotBoundException MalformedURLException

Naming.lookup("rmi://192.168.8.188:1099/location/coordinate/toaddress")

绑定发布某接口实现,可被远程调用

LocationService ls = new LocationServiceImpl();

Naming.rebind("rmi://localhost:1099/location/coordinate/toaddress");

             rebind不会抛出AlreadyBoundException


编写远程对象实现类,编译,生成代码存根,开户注册服务,运行服务端、开户调用端

public class LocationServiceImpl extends UnicastRemoteObject implements LocationService { }

# javac LocationServiceImpl.java

# rmic LocationServiceImpl   /// 为实现类生成代码存根,会生成两份个class文件

     LocationServiceImpl_Stub.class(调用端用)  LocationServiceImpl_Skeleton.class

# rmiregistry   /// 开启 Naming.bind 的注册服务

RMI系统:框架层、远程引用层、传输层      RMI目前基于TCP实现


CORBA Common Object Request Broker Architecture 公用对象请求代理结构

IDL接口描述语言InterfaceDescriptionLanguage    ORB对象请求代理    互操作协议IIOP

对象管理组织 OMG 为解决分布式处理环境 DEC 中硬件和软件系统互联提出的一种解决方案

用于在不同编程语言,不同进程甚至是不同物理机器上的进程之间进行通信

IDL描述对象呈现的接口,编程语言去实现 Ada C C++ Smalltalk Java Python 均支持

如有文件 location.idl 定义了 LocationService 远程调用接口

module Location { 
    interface LocationService { 
        string toaddress(in double lan, in double lng); 
    };
};

# idlj -fall location.idl   /// idlj java内置的idl文件编译工具

会生成一个 Location (module的名称) 目录,包含

    LocationService.java     LocationServiceHelper.java     LocationServiceHolder.java

    LocationServiceOperations.java     _LocationServiceStub.java

# javac *.java   /// 对编写与生成的文件进行编译

# tnameserv -ORBInitialPort 900     /// 启动命名服务,相当于启动查找服务

   COBRA通过IOR(Interoperable Object Reference 可互操作对象引用)给远程服务定位

   IOR:0000db42362.....十六进制数字...983ba34

# java LocationServiceServerStarter -ORBInitialPort 900  /// 启动远程调用服务,指定注册端口

# java LocationClientStarter -ORBInitialHost 192.168.8.188 -ORBInitialPort 900  /// 启动调用端


EJB Enterprise Java Bean 

  会话Bean(SessionBean    实体Bean(EntityBean    消息驱动Bean(MessageDrivenBean

开发步骤:

开发:一般三个文件  Bean类、Bean本地接口、Bean远程接口

配置:XML文件,声明绑定Bean类,定义环境属性

组装:安装到服务器、与其它Bean组合

ejb-jar.xml: EJB组件发布描述文件,定义EJB组件类型,指定Remote接口,Home接口与Bean类

jboss.xml: EJB组件发布到JBoss服务器的必要描述文件,需指定JNDI名字

-----------------  ejb-jar.xml  jboss.xml 打包发布组件 

jboss-web.xml: WEB应用发布到JBoss-Tomcat时的文件,与web.xml并列

web.xml: WEB应用必要文件,可加入<ejb-ref>指向jboss-web.xml定义的EJB组件

-----------------  jboss-web.xml web.xml 发布JBoss中Web应用

EJB基础为 RMI-IIOP(J2EE网络机制) 和 JNDI

   Java Remote Method Invocation over the Internet Inter-ORB Protocol 

     允许编写的分布式对象在内存中跨Java虚拟机及物理设备调用执行

   Java Naming and Directory Interface 命名及目录接口

     J2EE提供的标准接口,定位用户、机器、网络、对象及服务    

 

七、OSGi Open Service Gateway initiative Java动态模块编程标准

bundle [ˈbʌndl]     大神撰写的 https://blog.csdn.net/acmman/category_6128357.html

个人理解:OSGi开发的项目类似于Tomcat中webapps目录下的Web工程,Tomcat管理界面可以

                  动态的对这些项目进行管理,卸载,启动,停止,上传新工程(war) 等;   或者像 

                  openfire_src 开发中的独立插件,加入进去即可设置启动、停止、卸载等等; 亦或者

                  像微服务中的单个工程,可以动态的注册或熔断、停止等,其它工程通过注册中心调用。


public class Activator implements BundleActivator { }

OSGi框架会使用 Class.newInstance() 方法创建 BundleActivator 对象,必须存在无参构造函数(反射)

public void start(BundleContext context) throws Exception { 初始化 }

public void stop(BundleContext context) throws Exception { 销毁注销 }


OSGi可以被当作正常jar来引用,但是当在 MANIFEST.MF 加入一系列属性后,就能被识别为OSGi模块

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: LocationService
Bundle-SymbolicName: LocationService
Bundle-Version: 1.0.0
Bundle-Activator: org.abc.def.LocationActivator
Bundle-ActivationPolicy: lazy
Bundle-RequireExecutionEnvironment: JavaSE-1.8
Import-Package: org.osgi.framework;version="1.3.0"

Bundle组件之间的依赖关系更像是提供者与使用者,而非上下级关系

    通过 Import 引用,Export 对外提供


调用其它 Bundle 模块 Export 提供的服务

BundleContext  context = ...  模块上下文

ServiceReference ref = context.getServiceReference(""); 获取服务引用

       /// ref = context.getServiceReference("", "");

         context.getService(ref);    接口实现对象

提供 Bundle 模块的对外可见的服务

BundleContext context = ... 

context.registerService("", instance, properties); 注册服务 可被外部调用

context.registerService(String[], instance, properties);


Eclipse 选择 Plug-in Project 项目去创建 OSGi 类型的工程

发布的时候,可以选择 Deployable plug-ins and fragments

若选择导出目录为  D:\workspace\osgi-location ,则会创建 plugins 子文件夹

里面生成 相应的 jar 文件,可以创建 plugins 同级文件夹 configuration ,其内部

新建 config.ini 配置文件,在 eclipse 的 plugins 目录找到 org.eclipse.osgi.***.jar 

复制到与 configuration 同级,然后打开终端到当前位置

# java -jar org.eclipse.osgi.***.jar -console 


Bundle 模式,通过设置 Export 导出,隐藏了除接口外的实现,调用者只能看到公共接口部分

项目引用 org.osgi.service.event   org.eclipse.osgi.services   org.eclipse.equinox.event

获取 org.osgi.service.event.EventAdmin 服务  getServiceReference(EventAdmin.class.getName()) 

    可以实现 osgi 框架内事件 发布/订阅

发布事件

EventAdmin ea = ...

        ea.sendEvent(event); 同步方式提交事件

        ea.postEvent(event);   /// event instanceof org.osgi.service.event.Event = true 异步

class MovingEvent extends Event { MovingEvent() { super("EVENT_TOPIC", properties); } }

接收监听事件

class MovingEventHandler implements EventHandler {  }

Hashtable<String,String[]> properties = ...

    properties.put(EventConstants.EVENT_TOPIC, new String[] { "EVENT_TOPIC" });

bundleContext.registerService("", new MovingEventHandler(), properties); 注册事件监听对象


OSGi + HTTP 服务   org.osgi.service.http javax.servlet  javax.servlet.http

HpptService  hs = bundleContext.getService(bundleContext.getServiceReference(HttpService.class.getName()));

    hs.registerResources("alias", "directory", hs.createDefaultHttpContext());       类似静态资源映射

    hs.registerServlet("alias", servlet, properties, hs.createDefaultHttpContext()); 映射Servlet访问路径

Servlet jsp=new ContextPathServletAdaptor(new JspServlet(context.getBundle(), "/web/"),"/jsp"); 

    hs.registerServlet("/jsp/*.jsp", jsp, properties, hc);

扩展点XML配置  plugin.xml

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
    <extension point="org.eclipse.equinox.http.registry.servlets">
        <servlet alias="/location_servlet" 
            class="a.b.c.d.LocationServiceServlet"></servlet>
        <servlet alias="/jsp/*.jsp"
            class="org.eclipse.equinox.jsp.jasper.registry.JSPFactory:/Webroot/jsp">
        </servlet>
    </extension>
    <extension point="org.eclipse.equinox.http.registry.resources">
        <resource alias="/html" base-name="/Webroot/html"/>
    </extension>
</plugin>

该方式则还需在 Activator 中显示的调用 registerXXX 来注册 资源 及 Servlet 等


Servlet 嵌入 OSGi 框架

Equinox 官方典型模式,在 web.xml 加入 Servlet 

<servlet id="bridge">
    <servlet-name>equinoxbridgeservlet</servlet-name>
    <display-name>Equinox Bridge Servlet</display-name>
    <servlet-class>org.eclipse.equinox.servletbridge.BridgeServlet</servlet-class>
    <init-param>
        <param-name>commandline</param-name>
        <param-value>-console</param-value>
    </init-param>
    enableFrameworkControls  true
    extendedFrameworkExports  
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>equinoxbridgeservlet</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>equinoxbridgeservlet</servlet-name>
    <url-pattern>*.jsp</url-pattern>
</servlet-mapping>

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值