- Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathFileWatcher.java
More file actions
Latest commit
185 lines (166 loc) · 8.9 KB
/
Copy pathFileWatcher.java
File metadata and controls
185 lines (166 loc) · 8.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
packagecom.tuniu.mob.dist.site.utils;
importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
importorg.springframework.beans.BeansException;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.beans.factory.annotation.Value;
importorg.springframework.context.ApplicationContext;
importorg.springframework.context.ApplicationContextAware;
importorg.springframework.stereotype.Component;
importorg.springframework.stereotype.Repository;
importorg.springframework.stereotype.Service;
importorg.springframework.util.ReflectionUtils;
importjavax.annotation.PostConstruct;
importjavax.tools.JavaCompiler;
importjavax.tools.ToolProvider;
importjava.io.IOException;
importjava.lang.reflect.Field;
importjava.nio.file.*;
importjava.nio.file.attribute.BasicFileAttributes;
/**
* @Auther: zhengpeng
* @Date: 2019/3/21 19:43
* @Description:
*/
@Component
publicclassFileWatcherimplementsApplicationContextAware {
privatestaticfinalLoggerLOGGER = LoggerFactory.getLogger(FileWatcher.class);
publicstaticApplicationContextapplicationContext;
privateWatchServicewatchService;
@Value("${howLoading.directory}")
privateStringwatchFile;
@Value("${howLoading.enabled}")
privatebooleanhotLoading;
@Autowired
privateLocalProcessorlocalProcessor;
@PostConstruct
publicvoidinit() {
if (!hotLoading) {
return;
}
try {
watchService = FileSystems.getDefault().newWatchService();
Pathpath = Paths.get(watchFile);
// 单层文件夹下
// path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE,
// StandardWatchEventKinds.ENTRY_MODIFY,
// StandardWatchEventKinds.ENTRY_DELETE);
// 多层文件夹下
Files.walkFileTree(path, newSimpleFileVisitor<Path>() {
@Override
publicFileVisitResultpreVisitDirectory(Pathdir, BasicFileAttributesattrs)
throwsIOException {
dir.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE);
returnFileVisitResult.CONTINUE;
}
});
} catch (IOExceptione) {
LOGGER.warn("读取修改的文件失败", e);
}
newThread(newWatchThread()).start();
/**注册关闭钩子*/
Threadhook = newThread(() -> {
try {
watchService.close();
} catch (IOExceptione) {
e.printStackTrace();
}
});
Runtime.getRuntime().addShutdownHook(hook);
}
@Override
publicvoidsetApplicationContext(ApplicationContextapplicationContext) throwsBeansException {
this.applicationContext = applicationContext;
}
publicclassWatchThreadimplementsRunnable {
@Override
publicvoidrun() {
while (true) {
finalWatchKeykey;
try {
key = watchService.take();
for (WatchEvent<?> watchEvent : key.pollEvents()) {
finalWatchEvent.Kind<?> kind = watchEvent.kind();
if (kind == StandardWatchEventKinds.OVERFLOW) {
continue;
}
//创建事件
if (kind == StandardWatchEventKinds.ENTRY_CREATE) {
LOGGER.info("[新建]");
}
//修改事件
if (kind == StandardWatchEventKinds.ENTRY_MODIFY) {
// 热加载进jvm 并且加入spring
PathfilePath = (Path) watchEvent.context();
if (!filePath.toString().endsWith(".java")) {
continue;
}
Pathpath = (Path) key.watchable();
LOGGER.info("[修改]:" + filePath.toString());
// 动态编译
JavaCompilerjavac = ToolProvider.getSystemJavaCompiler();
LOGGER.info("加载文件到" + this.getClass().getResource("/").getPath());
StringrealFilePath = String.format("%s/%s", key.watchable().toString(), filePath.toString());
intstatus = javac.run(null, null, null, "-d", this.getClass().getResource("/").getPath(), realFilePath);
if (status != 0) {
LOGGER.info("没有编译成功!");
} else {
// 动态加载 在JVM中,一个实例是通过本身的类名+加载它的ClassLoader识别的,也就是说 不同的ClassLoader 加载同一个类在JVM是不同的。
StringclassName = filePath.getFileName().toString().split("\\.")[0];
StringbeanName = className.substring(0, 1).toLowerCase() + className.substring(1);
// String classPathName = applicationContext.getType(beanName).getTypeName();
// String classPathName = applicationContext.getType(beanName).getGenericSuperclass().getTypeName();
StringclassPathName = realFilePath.split("java/")[1].replace("/",".").replace(".java","");
Class<?> cla = newSelfClassload(classPathName).loadClass(classPathName); // 需要重新new,不然一个加载器多次加载同一个类会报错 // 创建实例,判断这个对象是不是@Service等注解修饰,如果是则替换spring容器中的对象 对象中注入的不用管
if (cla.isAnnotationPresent(Component.class) || cla.isAnnotationPresent(Service.class)
|| cla.isAnnotationPresent(Repository.class) && cla.getInterfaces().length > 0) {
// CouponServiceImpl couponService1 = () cla.newInstance(); // 会报错 相同的类,不同的ClassLoader,将导致ClassCastException异常
//先移除spring中的bean
localProcessor.removeBean(beanName);
//注入spring中
localProcessor.addBean(beanName, cla);
// if (cla.isAnnotationPresent(Component.class) || cla.isAnnotationPresent(Service.class) || cla.isAnnotationPresent(Repository.class)) {
// 利用反射给使用到上面属性的对象重新赋值
ObjectspringObj = applicationContext.getBean(beanName);
StringfieldName = beanName.endsWith("Impl") ? beanName.substring(0, beanName.length() - 4) : beanName;
String[] beans = applicationContext.getBeanDefinitionNames();
for (Stringbean : beans) {
try {
Objecttemp = applicationContext.getBean(bean);
Fieldf;
f = temp.getClass().getDeclaredField(fieldName);
ReflectionUtils.makeAccessible(f);
f.set(temp, springObj);
} catch (Exceptione) {
continue;
}
}
}
LOGGER.info("{}热加载完毕", beanName);
// }
// if (cla.isAnnotationPresent(Controller.class) || cla.isAnnotationPresent(RestController.class)) {
// localProcessor.registerController(beanName, cla);
// }
}
}
//删除事件
if (kind == StandardWatchEventKinds.ENTRY_DELETE) {
LOGGER.info("[删gh除]");
}
}
booleanvalid = key.reset();
if (!valid) {
break;
}
} catch (Exceptione) {
LOGGER.warn("热加载出错", e);
// 重新开启线程
newThread(newWatchThread()).start();
}
}
}
}
publicstaticvoidmain(String[] args) {
// System.out.println(System.getProperty("user.dir"));
}
}