一個簡單JDK版動態(tài)代理
本文實例為大家分享了手動實現(xiàn)的一個簡單JDK版動態(tài)代理,供大家參考,具體內(nèi)容如下
一.實現(xiàn)步驟
1.根據(jù)目標(biāo)類的接口類型生成代理類的java文件。
2.編譯代理類java文件為.class字節(jié)碼文件。
3.將編譯好的字節(jié)碼文件加載到j(luò)vm中。
4.生成代理類對象并返回。
二.代碼實現(xiàn)
1.Proxy類
public class CLProxy {
private static final String ENTER= "\r\n";
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();
//創(chuàng)建實例
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.測試使用的接口與目標(biāo)類
//測試使用的接口
public interface Person {
void eat();
String call(String name);
}
//測試使用目標(biāo)類
public class XiaoMing implements Person {
@Override
public void eat() {
System.out.println("吃東西");
}
//@Override
public String call(String name) {
return name;
}
}
注意測試方法在CLProxy 的main 方法中。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Spring AOP注解失效的坑及JDK動態(tài)代理
- java動態(tài)代理(jdk與cglib)詳細(xì)解析
- 詳解Spring的兩種代理方式:JDK動態(tài)代理和CGLIB動態(tài)代理
- 深入理解java動態(tài)代理的兩種實現(xiàn)方式(JDK/Cglib)
- java jdk動態(tài)代理詳解
- 淺談Java代理(jdk靜態(tài)代理、動態(tài)代理和cglib動態(tài)代理)
- jdk中動態(tài)代理異常處理分析:UndeclaredThrowableException
- java代理 jdk動態(tài)代理應(yīng)用案列
- Java JDK動態(tài)代理(AOP)的實現(xiàn)原理與使用詳析
- Java JDK動態(tài)代理的基本原理詳細(xì)介紹
相關(guān)文章
SpringBoot+ThreadLocal+AbstractRoutingDataSource實現(xiàn)動態(tài)切換數(shù)據(jù)源
最近在做業(yè)務(wù)需求時,需要從不同的數(shù)據(jù)庫中獲取數(shù)據(jù)然后寫入到當(dāng)前數(shù)據(jù)庫中,因此涉及到切換數(shù)據(jù)源問題,所以本文采用ThreadLocal+AbstractRoutingDataSource來模擬實現(xiàn)dynamic-datasource-spring-boot-starter中線程數(shù)據(jù)源切換,需要的朋友可以參考下2023-08-08
java使用common-fileupload實現(xiàn)文件上傳
這篇文章主要為大家詳細(xì)介紹了java使用common-fileupload實現(xiàn)文件上傳的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-10-10
IntelliJ IDEA本地代碼覆蓋后恢復(fù)原來的代碼圖解
今天小編就為大家分享一篇關(guān)于IntelliJ IDEA本地代碼覆蓋后恢復(fù)原來的代碼圖解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2018-10-10
Java實現(xiàn)飛機(jī)大戰(zhàn)-連接數(shù)據(jù)庫并把得分寫入數(shù)據(jù)庫
這篇文章給大家分享了Java實現(xiàn)飛機(jī)大戰(zhàn)中連接數(shù)據(jù)庫并把得分寫入數(shù)據(jù)庫的相關(guān)知識點和代碼,有興趣的可以學(xué)習(xí)參考下。2018-07-07
Spring?Data?JPA?在?@Query?中使用投影的方法示例詳解
這篇文章主要介紹了Spring?Data?JPA?在?@Query?中使用投影的方法,大家需要注意如果要在 @Query 中使用投影,必須要主動聲明要查詢的字段,并且主動寫明字段的別名才行,本文通過sql代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2022-07-07

