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

