在 Servlet 规范中存在三大组件:Servlet 接口、Listener 接口、Filter 接口。我们在这里 要学习监听器接口 Listener。监听器是一种设计模式,是观察者设计模式的一种实现。所以 我们需要先学习观察者设计模式,再学习监听器设计模式。
从现实角度来说,我们每一个人都是一个观察者,同时也是一个被观察者。作为被观察 者,我们会发出一些信息,观察者在接收到这些信息后,会做出相应的反映;而作为观察者, 我们是可以被“被观察者”所发出的信息影响的。一个被观察者,可能存在多个观察者。也 就是说,一个被观察者所发出的信息,可能会影响到多个观察者。 观察者设计模式,定义了一种一对多的关联关系。一个对象 A 与多个对象 B、C、D 之 间建立“被观察与观察关系”。当对象 A 的状态发生改变时,通知所有观察者对象 B、C、D。 当观察者对象 B、C、D 在接收到 A 的通知后,根据自身实际情况,做出相应改变。 当然,观察者与被观察者指的都是具有某一类功能的对象,所以这里的观察者与被观察
代码实现:
// 定义观察者接口
public interface IObserver {
// 处理被观察者发送来的信息
void handleNotify(String message);
}
// 定义观察者两个实现类
public class FirstObserver implements IObserver{
@Override
public void handleNotify(String message) {
// TODO Auto-generated method stub
System.out.println("一号观察者接收到消息["+message+"], 正在处理消息....");
}
}
public class SecondObserver implements IObserver{
@Override
public void handleNotify(String message) {
// TODO Auto-generated method stub
System.out.println("二号观察者接收到消息["+message+"], 正在处理消息....");
}
}
// 定义被观察者接口
public interface IObserverable {
// 添加观察者
void addObserver(IObserver observer);
// 删除观察者
void removeObserver(IObserver observer);
// 向观察者发送信息
void notifyObservers(String message);
}
// 定义被观察者实现类
public class Some implements IObserverable {
// 声明观察者集合
private List<IObserver> observers;
// 在被观察者对象创建时,将观察者集合创建
public Some() {
observers = new ArrayList<>();
}
@Override
public void addObserver(IObserver observer) {
observers.add(observer);
}
@Override
public void removeObserver(IObserver observer) {
observers.remove(observer);
}
@Override
public void notifyObservers(String message) {
// 通知每一个观察者
for(IObserver observer : observers) {
observer.handleNotify(message);
}
}
}
// 定义测试类
public class MyTest {
public static void main(String[] args) {
// 创建多个观察者
IObserver firstObserver = new FirstObserver();
IObserver secondObserver = new SecondObserver();
// 创建被观察者
Some some = new Some();
// 被观察者添加观察者
some.addObserver(firstObserver);
some.addObserver(secondObserver);
// 被观察者向所有观察者发送消息
some.notifyObservers("hello world");
// 被观察者删除一个观察者
some.removeObserver(firstObserver);
// 被观察再次向所有观察者发送消息
System.out.println("------------------------");
some.notifyObservers("hello world");
}
}
监听器设计模式,是观察者设计模式的一种实现,它并不是 23 种设计模式之一。
这里的监听器实际对应的就是观察者,而被监听对象,则是指被观察者。当被监听对象的状态发生改变时,也需要通知监听器,监听器在收到通知后会做出相应改变。 与观察者设计模式不同点:
其实质与观察者设计模式是相同的。
下面以对被监听者所执行的增删改查 CURD 操作进行监听为例,来演示监听器设计模式 的用法。
// 定义监听器接口
public interface IListener {
// 处理事件
void handle(ICurdEvent event);
}
// 定义监听器实现类
public class CrudLisntener implements IListener {
@Override
public void handle(ICurdEvent event) {
String eventType = event.getEventType();
if(ICurdEvent.CRE_EVENT.equals(eventType)) {
System.out.println("事件源执行 添加 操作");
} else if(ICurdEvent.DEL_EVENT.equals(eventType)) {
System.out.println("事件源执行 删除 操作");
} else if(ICurdEvent.UPD_EVENT.equals(eventType)) {
System.out.println("事件源执行 更新 操作");
} else if(ICurdEvent.RET_EVENT.equals(eventType)) {
System.out.println("事件源执行 查询 操作");
}
}
}
// 定义事件接口
// 通常对于事件对象,我们需要从事件对象中获取到事件源对象的
public interface ICurdEvent {
// 声明事件类型
public static String CRE_EVENT = "create_event";
public static String RET_EVENT = "retrive_event";
public static String UPD_EVENT = "update_event";
public static String DEL_EVENT = "delete_event";
// 获取事件源对象
public abstract IListenerable getEventSource();
// 获取事件类型
public abstract String getEventType();
}
// 定义事件实现类
public class CrudEvent implements ICurdEvent {
private IListenerable eventSource;
private String methodName;
public CrudEvent(IListenerable eventSource, String methodName) {
super();
this.eventSource = eventSource;
this.methodName = methodName;
}
@Override
public IListenerable getEventSource() {
return eventSource;
}
// 根据事件源执行的不同方法返回不同的事件类型
@Override
public String getEventType() {
String eventType = null;
if(methodName.startsWith("create")) {
eventType = CRE_EVENT;
} else if(methodName.startsWith("update")) {
eventType = UPD_EVENT;
} else if(methodName.startsWith("delete")) {
eventType = DEL_EVENT;
} else if(methodName.startsWith("find")) {
eventType = RET_EVENT;
} else {
eventType = "not found";
}
return eventType;
}
}
// 定义事件源接口
public interface IListenerable {
// 为事件源注册监听器
public abstract void setListener(IListener listener);
// 触发监听器
public abstract void triggerListener(ICurdEvent event);
}
// 定义事件源实现类
public class Some implements IListenerable {
private IListener listener;
// 注册监听器
@Override
public void setListener(IListener listener) {
this.listener = listener;
}
// 触发监听器
@Override
public void triggerListener(ICurdEvent event) {
listener.handle(event);
}
}
// 定义测试类
public class MyTest {
public static void main(String[] args) {
// 定义监听器
IListener listener = new CrudLisntener();
// 定义事件源
IListenerable eventSource = new Some();
// 定义事件对象
ICurdEvent event = new CrudEvent(eventSource, "update table");
// 事件源注册监听器
eventSource.setListener(listener);
// 事件源触发监听器
eventSource.triggerListener(event);
}
}
运行结果:
事件源执行 更新 操作
会造成脏读,即一个事务读取另外一个事务还没有提交的数据。 原因:事务T1修改了一行数据,但是还没有提交,这时候事务T2读取了被事务T1修改后的数据,之后事务T1因为某种原因Rollback了,那么事务T2读取的数据就是脏的。 Oracle默认的隔离级别是【读提交】(read commited),MySQL 默认的隔离级别是 【可重复读】(repeatable read)
会造成不可重复读,即在同一个事务内,两个相同的查询返回了不同的结果。 原因:事务T1读取某一数据,事务T2读取并修改了该数据,T1为了对读取值进行检验而再次读取该数据,便得到了不同的结果。
以操作同一行数据为前提,读事务禁止其他写事务(但允许其他读事务),未提交的写事务禁止其他读事务和写事务。 此隔离级别可以防止更新丢失、脏读、不可重复读,但不能防止幻读。 此隔离级别可以通过“共享读锁”和“排他写锁”实现。
提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,不能并发执行。
此隔离级别可以防止更新丢失、脏读、不可重复读、幻读。
参考博客:
CSDN三、数据库由于并发事务而引起的问题以及事务的隔离级别
CSDN四、数据库锁机制–行级锁(悲观锁与乐观锁)与表级锁
The different actors in a blockchain network include peers, orderers, client applications, administrators and more. Each of these actors — active elements inside or outside a network able to consume services — has a digital identity encapsulated in an X.509 digital certificate. These identities really matter because they determine the exact permissions over resources and access to information that actors have in a blockchain network.
PKI certificate authorities and MSPs provide a similar combination of functionalities. A PKI is like a card provider — it dispenses many different types of verifiable identities. An MSP, on the other hand, is like the list of card providers accepted by the store, determining which identities are the trusted members (actors) of the store payment network. MSPs turn verifiable identities into the members of a blockchain network.
MSPs turn verifiable identities into the members of a blockchain network.
The elements of Public Key Infrastructure (PKI). A PKI is comprised of Certificate Authorities who issue digital certificates to parties (e.g., users of a service, service provider), who then use them to authenticate themselves in the messages they exchange with their environment.
There are four key elements to PKI:
A digital certificate is a document which holds a set of attributes relating to the holder of the certificate. The most common type of certificate is the one compliant with the X.509 standard, which allows the encoding of a party’s identifying details in its structure.
Authentication and message integrity are important concepts in secure communications. Authentication requires that parties who exchange messages are assured of the identity that created a specific message. For a message to have “integrity” means that cannot have been modified during its transmission. For example, you might want to be sure you’re communicating with the real Mary Morris rather than an impersonator. Or if Mary has sent you a message, you might want to be sure that it hasn’t been tampered with by anyone else during transmission.
Technically speaking, digital signature mechanisms require each party to hold two cryptographically connected keys: a public key that is made widely available and acts as authentication anchor, and a private key that is used to produce digital signatures on messages. Recipients of digitally signed messages can verify the origin and integrity of a received message by checking that the attached signature is valid under the public key of the expected sender.
Technically speaking, digital signature mechanisms require each party to hold two cryptographically connected keys: a public key that is made widely available and acts as authentication anchor, and a private key that is used to produce digital signatures on messages. Recipients of digitally signed messages can verify the origin and integrity of a received message by checking that the attached signature is valid under the public key of the expected sender.
As you’ve seen, an actor or a node is able to participate in the blockchain network, via the means of a digital identity issued for it by an authority trusted by the system. In the most common case, digital identities (or simply identities) have the form of cryptographically validated digital certificates that comply with X.509 standard and are issued by a Certificate Authority (CA).
In a blockchain setting, every actor who wishes to interact with the network needs an identity. In this setting, you might say that one or more CAs can be used to define the members of an organization’s from a digital perspective. It’s the CA that provides the basis for an organization’s actors to have a verifiable digital identity.
CAs come in two flavors: Root CAs and Intermediate CAs. Because Root CAs (Symantec, Geotrust, etc) have to securely distribute hundreds of millions of certificates to internet users, it makes sense to spread this process out across what are called Intermediate CAs. These Intermediate CAs have their certificates issued by the root CA or another intermediate authority, allowing the establishment of a “chain of trust” for any certificate that is issued by any CA in the chain.
题目描述 操作给定的二叉树,将其变换为源二叉树的镜像。
二叉树的镜像定义:源二叉树 8 / \ 6 10 / \ / \ 5 7 9 11 镜像二叉树 8 / \ 10 6 / \ / \ 11 9 7 5
利用递归
代码实现
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public void Mirror(TreeNode root) {
if(root == null)
return;
swap(root);
Mirror(root.left);
Mirror(root.right);
}
public void swap(TreeNode root) {
TreeNode t = root.left;
root.left = root.right;
root.right = t;
}
}
题目描述 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回
前序遍历的第一个值为根节点的值,使用这个值将中序遍历结果分成两部分,左部分为树的左子树中序遍历结果,右部分为树的右子树中序遍历的结果。
代码实现
/**
* Definition for binary tree
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
import java.util.Map;
import java.util.HashMap;
public class Solution {
private Map<Integer, Integer> inOrderNumsIndexs = new HashMap<>();
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
for(int i=0; i<in.length; i++) {
inOrderNumsIndexs.put(in[i], i);
}
return reConstructBinaryTree(pre, 0, pre.length-1, 0, in.length-1);
}
public TreeNode reConstructBinaryTree(int[] pre, int preL, int preR, int inL, int inR) {
if(preL > preR)
return null;
TreeNode root = new TreeNode(pre[preL]);
int inIndex = inOrderNumsIndexs.get(root.val);
int leftTreeSize = inIndex - inL;
root.left = reConstructBinaryTree(pre, preL + 1, preL + leftTreeSize, inL, inL + leftTreeSize - 1);
root.right = reConstructBinaryTree(pre, preL + leftTreeSize + 1, preR, inL + leftTreeSize + 1, inR);
return root;
}
}
题目描述 输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
代码实现
public class Solution {
public boolean HasSubtree(TreeNode root1,TreeNode root2) {
if(root1 == null || root2 == null)
return false;
return isSubtreeWithRoot(root1, root2) || HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2);
}
private boolean isSubtreeWithRoot(TreeNode root1, TreeNode root2) {
if(root2 == null)
return true;
if(root1 == null)
return false;
if(root1.val != root2.val)
return false;
return isSubtreeWithRoot(root1.left, root2.left) && isSubtreeWithRoot(root1.right, root2.right);
}
}