Spring Developer Tools Source Analysis
Introduction to Spring Devtools
https://blog.csdn.net/isea533/article/details/70495714
Spring Developer Tools, hereafter referred to as devtools, this tool is not only easy to use, but also in the source code of this tool, there are many very valuable to learn the design, this series will be analyzed Devtools, and finally make reading this reader can not only understand The realization of Devtools can also learn some design ideas of devtools.
The Devtools function is based on detecting code changes, so start with this relatively independent section. First, the file directory monitoring design
Starting with JDK 7, Java provides java.nio.file.WatchService for file monitoring, and Commons IO provides Org.apache.commons.io.monitor.FileAlterationObserver is used to monitor directories.
Devtools himself to achieve a simple file monitoring, through the independent thread, at a certain time interval, the monitoring of the directory to do a snapshot, and then compare the two before and after the snapshot, compare the file information to determine whether the file is new, modified or deleted.
The following diagram is a class diagram of the classes related to file monitoring:
The following classes are described below. 1.1 Type enumeration, changing state
In this enumeration class, three states of file change are defined: Add,modify,delete. 1.2 changedfile, change of File
This class records the resource directory where the file resides, the file itself, and the file's changing state. 1.3 Changedfiles, a collection of change files
This class is a collection of changedfile. Contains all the files that change under the same resource directory. 1.4 filesnapshot File Snapshot
Records the information of a single file, including whether it exists, the length of the file, and the time it was modified. 1.5 foldersnapshot Directory snapshot
A resource directory that corresponds to a directory snapshot, when creating Foldersnapshot through the directory, recursively traverses all subdirectories, gets all the internal files, and all the specific files have a filesnapshot file snapshot.
The class also provides the following methods:
Public changedfiles getchangedfiles (foldersnapshot snapshot,
filefilter triggerfilter)
This method can compare two directory snapshots to obtain the difference file, that is, the changedfiles in 1.3. The method logic is relatively simple, the first comparison of the two snapshots must be the same directory (when the File class equals, as long as the same path is equal), the current instance (this) is an early snapshot, the incoming snapshot is the latest snapshot, by contrast, if the previous one is not, and the new one is The new file. The reverse is deletion , if the two snapshots of the various attributes are different, is modified .
The Triggerfilter (triggering file) in this method is used to implement features that are restarted when the specified file changes.
The previous 5 classes are simple classes, and only foldersnapshot contains slightly more complex logic.
Now as long as we can get two different time directory snapshots, we can compare the changes in the file. 1.6 FileSystemWatcher File system monitoring
This class provides configurable parameters for controlling the monitoring cycle, monitoring times, and so on. By default, the number of monitors (Remainingscans) is-1, that is, unlimited number of times, will continue to poll the monitoring directory.
The most important code in this class is the Start method:
/**
* Start monitoring the source folder for changes.
*/public
void Start () {
synchronized (this.monitor) {
saveinitialsnapshots ();
if (This.watchthread = = null) {
map<file, foldersnapshot> localfolders = new hashmap<> ();
Localfolders.putall (this.folders);
This.watchthread = new Thread (New Watcher (This.remainingscans,
new Arraylist<> (this.listeners), This.triggerfilter,
this.pollinterval, This.quietperiod, localfolders));
This.watchThread.setName ("File Watcher");
This.watchThread.setDaemon (This.daemon);
This.watchThread.start ();}}
Here you create a watchthread to perform watcher, tasks, and specific content in the Watcher class below. 1.7 Watcher Monitoring class
The Watcher class is the core of the entire monitoring design, looking first at the main run methods:
@Override public
Void Run () {
int remainingscans = This.remainingScans.get ();
while (Remainingscans > 0 | | remainingscans = = 1) {
try {
if (Remainingscans > 0) {
This.remainingscans . Decrementandget ();
Scan ();
}
catch (Interruptedexception ex) {
thread.currentthread (). interrupt ();
}
Remainingscans = This.remainingScans.get ();
}
}
Note that when you create a worker thread, the Remainingscans default value is-1, and in this while judgment, the value of 1 does not change, and the loop always executes. Then look at the specific scan method:
private void Scan () throws Interruptedexception {
thread.sleep (this.pollinterval-this.quietperiod);
Map<file, foldersnapshot> previous;
Map<file, foldersnapshot> current = This.folders;
do {
previous = current;
Current = Getcurrentsnapshots ();
Thread.Sleep (This.quietperiod);
}
while (Isdifferent (previous);
if (Isdifferent (this.folders, current)) {
updatesnapshots (current.values ());
}
}
This method will wait 1000-400 milliseconds by default, then call Getcurrentsnapshots (the result is ordered), wait 400 milliseconds, and if the directory does not change (isdifferent = = False), it will be polled in 400 milliseconds. If the file has changed, call the Updatesnapshots method, there is no complex logic, do not elaborate on the various methods.
Then look at the Updatesnapshots method:
private void Updatesnapshots (collection<foldersnapshot> snapshots) {Map<File,
foldersnapshot> updated = new linkedhashmap<> ();
set<changedfiles> ChangeSet = new linkedhashset<> ();
for (Foldersnapshot snapshot:snapshots) {foldersnapshot previous = This.folders.get (Snapshot.getfolder ());
Updated.put (Snapshot.getfolder (), snapshot);
Changedfiles changedfiles = previous.getchangedfiles (snapshot, This.triggerfilter);
if (!changedfiles.getfiles (). IsEmpty ()) {Changeset.add (changedfiles);
} if (!changeset.isempty ()) {firelisteners (Collections.unmodifiableset (ChangeSet));
} this.folders = Updated; } private void Firelisteners (Set<changedfiles> changeSet) {for (Filechangelistener listener:this.listeners)
{Listener.onchange (ChangeSet); }
}
This compares the two snapshots of the project directory, finds the difference file, gets set<changedfiles>, and then calls the OnChange listener method using the differential file as a parameter. All registered listener will receive notification of changes to the file at this time.
Later we continue to see how Devtools uses FileSystemWatcher to monitor the classpath.