간단 한 JDK 버 전 동적 에이전트
실현 절차
1.대상 클래스 의 인터페이스 형식 에 따라 프 록 시 클래스 의 자바 파일 을 생 성 합 니 다.
2.프 록 시 클래스 자바 파일 을.class 바이트 파일 로 컴 파일 합 니 다.
3.컴 파일 된 바이트 파일 을 jvm 에 불 러 옵 니 다.
4.프 록 시 대상 을 생 성하 고 되 돌려 줍 니 다.
코드 구현
1.프 록 시 클래스
public class CLProxy {
private static final String ENTER= "\r
";
private static final String PAKAGE=CLProxy.class.getPackage().toString()+";";
private static final String CLASS_NAME="$Proxy";
private static final AtomicInteger NUMBER= new AtomicInteger(0);
public static Object newProxyInstance(CLClassLoader classLoader, Class<?>[] interfaces,CLInvocationHandler h) throws Exception{
String className =CLASS_NAME+NUMBER.getAndIncrement();
// java
String javaString = createJavaString(interfaces, className);
String parentPath = CLProxy.class.getResource("").getPath();
File file =new File(parentPath,className+".java" );
FileWriter writer = new FileWriter(file);
writer.write(javaString);
writer.flush();
writer.close();
//System.out.println(file);
//
JavaCompiler systemJavaCompiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager standardFileManager = systemJavaCompiler.getStandardFileManager(null, null, null);
Iterable<? extends JavaFileObject> javaFileObjects = standardFileManager.getJavaFileObjects(file);
JavaCompiler.CompilationTask task = systemJavaCompiler.getTask(null, standardFileManager, null, null, null, javaFileObjects);
task.call();
standardFileManager.close();
//
Class<?> aClass = classLoader.findClass(className);
Constructor<?> constructor = aClass.getConstructor(CLInvocationHandler.class);
Object instance = constructor.newInstance(h);
//file.delete();
return instance;
}
/**
* java
* @param interfaces
* @return
*/
private static String createJavaString(Class<?>[] interfaces , String className ){
StringBuffer buffer = new StringBuffer();
buffer.append(PAKAGE+ENTER);
buffer.append("import java.lang.reflect.Method;"+ ENTER);
StringBuffer interfaceString= new StringBuffer();
int length= interfaces.length;
for (int i = 0; i<length ; ++i){
interfaceString.append(interfaces[i].getName());
if (i!=length-1){
interfaceString.append(",");
}
}
buffer.append("public final class ");
buffer.append(className);
buffer.append(" implements ");
buffer.append(interfaceString);
buffer.append(" {"+ENTER);
buffer.append("private CLInvocationHandler handler;"+ENTER);
buffer.append("public "+className+"(CLInvocationHandler handler) {"+ENTER);
buffer.append(" this.handler= handler;"+ENTER);
buffer.append("}"+ENTER);
for (int i =0 ;i<length;++i){
Class<?> clazz= interfaces[i];
Method[] methods = clazz.getMethods();
for (Method method : methods){
String returnTypeString = method.getReturnType().getName();
Class<?>[] parameterTypes = method.getParameterTypes();
StringBuffer paramTypeString = new StringBuffer();
StringBuffer methodParamString = new StringBuffer();
StringBuffer invokeParamString = new StringBuffer();
paramTypeString.append("new Class[]{");
int paramLength= parameterTypes.length;
for (int j =0 ; j<paramLength ;++j){
Class<?> paramClazz= parameterTypes[j];
paramTypeString.append(paramClazz.getName()+".class");
String paramFieldName = "var"+j;
methodParamString.append(paramClazz.getName() +" "+paramFieldName);
invokeParamString.append(paramFieldName);
if (j!= paramLength-1){
paramTypeString.append(",");
methodParamString.append(",");
invokeParamString.append(",");
}
}
paramTypeString.append("}");
int modifiers = method.getModifiers();
if (Modifier.isPublic(modifiers)){
buffer.append("public");
}else if (Modifier.isPrivate(modifiers)){
buffer.append("private");
}else if (Modifier.isProtected(modifiers)){
buffer.append("protected");
}
buffer.append(" final "+returnTypeString+" "+ method.getName()+"("+methodParamString+"){"+ ENTER);
buffer.append("try{"+ENTER);
buffer.append("Method method = "+clazz.getName()+".class.getMethod(\""+method.getName()+"\","+paramTypeString+" );"+ENTER);
if (!"void".equals(returnTypeString)){
buffer.append("return ("+returnTypeString+")");
}
if (invokeParamString.toString().length()==0){
invokeParamString.append("null");
}else{
invokeParamString = new StringBuffer("new Object[]{"+invokeParamString.toString()+"}");
}
buffer.append("this.handler.invoke(this,method,"+invokeParamString+");"+ENTER);
buffer.append("}catch(Throwable e){"+ENTER);
buffer.append("e.printStackTrace();"+ENTER);
buffer.append("}"+ENTER);
if (!"void".equals(returnTypeString)){
buffer.append("return null;"+ENTER);
}
buffer.append("}"+ENTER);
}
}
buffer.append("}");
return buffer.toString();
}
public static void main(String[] args) throws Exception {
Person person = (Person)CLProxy.newProxyInstance(new CLClassLoader(), XiaoMing.class.getInterfaces(), new CLInvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before");
Object result= method.invoke(new XiaoMing(), args);
System.out.println("after");
return result;
}
});
String laoxu = person.call("laoxu");
System.out.println(laoxu);
/* person.eat();
Class<?>[] interfaces = person.getClass().getInterfaces();
for (Class<?> in:interfaces){
System.out.println(in.getName());
}
*/
Person person2= (Person)CLProxy.newProxyInstance(new CLClassLoader(), XiaoMing.class.getInterfaces(), new CLInvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before");
Object result= method.invoke(new XiaoMing(), args);
System.out.println("after");
return result;
}
});
System.out.println(person2.getClass());
}
}
2.InvocationHandler 인터페이스
public interface CLInvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
3.ClassLoader 클래스 로 더
public class CLClassLoader extends ClassLoader {
private File classPathFile;
public CLClassLoader(){
String classPath = CLClassLoader.class.getResource("").getPath();
this.classPathFile= new File(classPath);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String className = CLClassLoader.class.getPackage().getName()+"."+name;
if (classPathFile!= null ){
File classFile = new File(classPathFile, name.replace("\\.", "/") + ".class");
if (classFile.exists()){
FileInputStream inputStream =null;
ByteArrayOutputStream outputStream = null;
try{
inputStream=new FileInputStream(classFile);
outputStream= new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int len;
while ((len=inputStream.read(bytes))!=-1){
outputStream.write(bytes,0,len);
}
return defineClass(className,outputStream.toByteArray(),0,outputStream.size());
}catch (Exception e){
e.printStackTrace();
}finally {
if (inputStream!= null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outputStream!=null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
return super.findClass(name);
}
}
4.테스트 에 사용 되 는 인터페이스 와 대상 클래스
//
public interface Person {
void eat();
String call(String name);
}
//
public class XiaoMing implements Person {
@Override
public void eat() {
System.out.println(" ");
}
//@Override
public String call(String name) {
return name;
}
}
테스트 방법 은 CLProxy main 방법 에 있 습 니 다.이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
【Java】 STS (Eclipse)에 AdoptOpen JDK 설정· Eclipse를 2020-09로 업데이트하면 jre로 Eclipse를 움직이고 있습니다! 라는 메시지가 나온다. ・메모리 상태의 파악을 위해 MissionControl 넣으려고 하면 JDK로 움직이지 않으면 안 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.