JavaEE實驗框架原理
阿新 • • 發佈:2021-10-08
實驗一: Tomcat Embedded 啟動(實現一個Servlet)
- 要求:使用Tomcat實現一個Servlet。 通過http://localhost:<學號後五位>/Test訪問這個Servlet,返回文字“學號:<學號>,學生姓名:<學生姓名>”
初始目錄
原始碼
import java.io.File; import java.io.IOException; import java.io.Writer; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Context; import org.apache.catalina.LifecycleException; import org.apache.catalina.startup.Tomcat; public class DemoServlet{ public static void main(String[] args) throws LifecycleException, InterruptedException, ServletException { Tomcat tomcat = new Tomcat(); tomcat.setPort(16584); //設定埠號,學號後五位做埠號 Context ctx = tomcat.addContext("/", new File(".").getAbsolutePath()); Tomcat.addServlet(ctx, "Test", new HttpServlet() { private static final long serialVersionUID = 1L; @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setCharacterEncoding("UTF-8"); response.setContentType("text/plain"); try (Writer writer = response.getWriter()) { writer.write("2019216584:<2019216584>,丁帥帥:<丁帥帥>"); // 響應請求的內容 writer.flush(); } } }); ctx.addServletMappingDecoded("/*", "Test"); // 對映訪問路徑 tomcat.start(); tomcat.getServer().await(); } }
編譯
javac -cp ".;tomcat-embed-core.jar;annotations-api.jar" -encoding "UTF-8" DemoServlet.java
執行
java -cp ".;tomcat-embed-core.jar;annotations-api.jar" DemoServlet
截圖
測試
截圖
結構圖
實驗二:Java的動態特性實現Java的動態特性實現
- 實驗要求:實驗通過位元組碼工具Javassist實現Java的動態特性。為一個已經編譯好的Java類(.class檔案),新增一個方法sayHi()
原始碼
// 被加方法的類,可以是別的類
public class User{
private int id;
private String name;
}
import javassist.*; import java.lang.reflect.Method; public class DemoModifyByteCode{ public static void main(String[] args) throws Exception { ClassPool pool = ClassPool.getDefault(); try { CtClass ct = pool.get("User"); //獲得要修改的類物件 CtMethod sayHi = CtNewMethod.make("public void sayHi(){System.out.println(\"Hi! 2019216584-丁帥帥\");}",ct); ct.addMethod(sayHi); Class clazz = ct.toClass(); User u = new User(); Method getName = User.class.getDeclaredMethod("sayHi",new Class[]{}); getName.invoke(u); //u.getName(); //不能直接呼叫 //ct.writeFile(); } catch (NotFoundException e) { System.out.println(e); } } }
編譯
javac -encoding UTF-8 User.java
javac -cp ".;javassist.jar" -encoding "UTF-8" DemoModifyByteCode.java
執行
java -cp ".;javassist.jar" DemoModifyByteCode
截圖
實驗三: 框架實現方法實驗(反射與註解)
原始碼
// 註解(不用修改)
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RunTest{
//引數預設為空
String value() default "";
}
// 監聽程式(不需要修改)
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.io.File;
import java.io.FileInputStream;
import java.util.List;
import java.lang.reflect.*;
//import javassist.*;
public class ClassMonitor {
public static void main(String[] args) throws Exception {
// 需要監聽的檔案目錄(只能監聽目錄)
String path = "./classes";
WatchService watchService = FileSystems.getDefault().newWatchService();
Path p = Paths.get(path);
p.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY,
StandardWatchEventKinds.ENTRY_DELETE,
StandardWatchEventKinds.ENTRY_CREATE);
Thread thread = new Thread(() -> {
try {
while(true){
WatchKey watchKey = watchService.take();
List<WatchEvent<?>> watchEvents = watchKey.pollEvents();
for(WatchEvent<?> event : watchEvents){
//根據事件型別採取不同的操作
System.out.println("["+path+"/"+event.context()+"]檔案發生了["+event.kind()+"]事件");
if(event.kind().equals(StandardWatchEventKinds.ENTRY_CREATE)||
event.kind().equals(StandardWatchEventKinds.ENTRY_MODIFY))
{
System.out.println(event.context());
String s = event.context().toString();
if(s.contains(".class"))
{
try{
Thread.currentThread().sleep(1000);
Class clazz = Class.forName(s.replace(".class",""));
File newfile = new File(s);
byte[] bytes = new byte[(int)newfile.length()];
new FileInputStream(newfile).read(bytes);
System.out.println("類的名字是:"+clazz.getName());
System.out.println("類的屬性是:");
Field[] fields = clazz.getDeclaredFields();
for(Field fd : fields)
{
System.out.println(fd);
}
System.out.println("類的方法是:");
//獲取該類的所有方法,不包括父類(僅自定義)
Method[] declaredMethods = clazz.getDeclaredMethods();
for(Method md : declaredMethods)
{
System.out.println(md);
RunTest declaredAnnotation = md.getDeclaredAnnotation(RunTest.class);
//獲取到他的值
if(declaredAnnotation != null){
String value = declaredAnnotation.value();
System.out.println(value);
md.invoke(clazz.getConstructor().newInstance());
}
}
clazz = null;
}
catch(Exception e){
System.out.println(e);
}
}
}
}
watchKey.reset();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.setDaemon(false);
thread.start();
// 增加jvm關閉的鉤子來關閉監聽
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
watchService.close();
} catch (Exception e) {
}
}));
}
}
// 測試類
public class Test{
public int id;
public String name;
@RunTest("Test Run")
public void print()
{
System.out.println("==============");
System.out.println("測試註解");
}
@RunTest("測試註解的變數")
public void show()
{
System.out.println("Show test world");
}
@RunTest
public void show2()
{
System.out.println("show TTTTT");
}
}
編譯
javac -encoding "UTF-8" RunTest.java
javac -encoding "UTF-8" ClassMonitor.java
javac -encoding "UTF-8" Test.java
執行
java ClassMonitor
測試
mkdir classes
copy Test.class classes
觀察執行java ClassMonitor的視窗變化