`

实现动态代理

 
阅读更多

AOP的实现有两种,一种是接口的实现,一种是产生自己实现,分别的代表为JDK的Proxy和CGLIB的Proxy

下面是模拟接口代理实现 ,通过模拟JDK的动态代理,更深刻的理解

通过动态代理可以面向切面编程

1 定义被代理的对象和接口

public interface BookInterface {
	void selling();
}

 

public interface PhoneInterface {
	void selling();
}

 

public class Book implements BookInterface {
	@Override
	public void selling() {
		System.out.println("books selling.....");
	}
}

 

public class VivoPhone implements PhoneInterface {
	@Override
	public void selling() {
		System.out.println("selling vivo x5");
	}
}

 

 2 定义切面类

public class TimeAspect {
	static long bgn;
	public static void before(){
		bgn = System.currentTimeMillis();
		System.out.println("begin time...  " + bgn);
	}
	public static void after(){
		long end = System.currentTimeMillis();
		System.out.println("end time...  " + (end-bgn));
	}
}
public class LogAspect{
	public static void before(){
		 
		System.out.println("begin log...");
	}
	public static void after(){
		System.out.println("finish log...");
	}
}

 3 定义InvocationHander  代理接口

import java.lang.reflect.Method;
public interface InvocationHander {
	public void invoke(Object o,Method m);
}

   代理类(切面编程里面也可以做一些特殊的处理)

import java.lang.reflect.Method;   
  
public class ProxyHander implements InvocationHander {  
    private Object target;  
    public ProxyHander(Object target) {  
        this.target = target;  
    }  
    @Override  
    public void invoke(Object o, Method m) {  
        try {  
            TimeAspect.before();  
            if(!(o instanceof BookInterface)){//只有非BookInterface接口调用日志  
                LogAspect.before();  
            }  
              
            m.invoke(target);  
               
            if(!(o instanceof BookInterface)){  
                LogAspect.after();  
            }  
            TimeAspect.after();  
        } catch (Exception e) {  
            e.printStackTrace();  
        }   
    }  
}  

    动态代理类

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;


import org.apache.commons.io.FileUtils;

public class Proxy {
	/*
	 * 空的构造函数
	 */
	private Proxy(){
	}
	/*
	 * 返回代理类
	 */
	public static Object newProxyInstance(Class inter,InvocationHander h){
		String packageName  = inter.getPackage().getName();
		// String temp = new String(packageName);
		String proxyClassName = "$"+packageName.replace(".","_") + "_" + inter.getSimpleName() +"Proxy";
		
		String InHanderPackage = h.getClass().getPackage().getName();
		String rt = "\r\n";// 换行
		String methodCode = "";
		for (Method method:inter.getMethods()) {
			methodCode+="	@Override"+rt+
			
			"	public void "+ method.getName()+"() {"+rt+
			"		try{"+rt+
			"			Method method  = "+inter.getName()+".class.getMethod(\"" 
			+ 			method.getName()+	"\");"+rt+
			"			h.invoke(this,method);      "+rt+
			" 	 	}catch(Exception e ){" +rt+
			"			e.printStackTrace();" +rt+
			"		}"+rt+
			"	}";
		}
		/*
		 * 总的java代码
		 */
		String javaCode=  
		"package  "+packageName+";"+rt+
		"import "+InHanderPackage+".InvocationHander;"+rt+
		
		"import java.lang.reflect.Method;"+rt+
		"public class "+proxyClassName+" implements "+inter.getName()+" {"+rt+
		"	public "+proxyClassName+"("+InHanderPackage+".InvocationHander h) {"+rt+
		"		super();"+rt+
		"		this.h = h;"+rt+
		"	}"+rt+
		"	private "+InHanderPackage+".InvocationHander h;"+rt+
		methodCode+rt+
		"}";
		/*
		 *  生成java文件
		 */
		// 生成文件路径
		String filename =  System.getProperty("user.dir")+"/bin/"+packageName.replace(".", "//")+"/"+proxyClassName+".java";
		File file = new File(filename);
		try {
			// 需要commons-io的jar方便的操作文件
			FileUtils.writeStringToFile(file, javaCode); 
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		
		// 编译  拿到编译器
		JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
		// 文件管理
		StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
		//获取文件
		Iterable units = fileMgr.getJavaFileObjects(filename);
		
		// 编译任务
		CompilationTask t  = compiler.getTask(null, fileMgr, null, null, null, units);
		// call进行编译
		t.call();
		try {
			fileMgr.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		// load到内存
		ClassLoader cl = ClassLoader.getSystemClassLoader();
		try {
			Class c = cl.loadClass(packageName+"."+proxyClassName);
			Constructor ctr = c.getConstructor(InvocationHander.class);
			return ctr.newInstance(h);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
}

4 测试

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class TestProxy {
	@Before
	public void  before(){
		System.out.println("-----------------start-------------------");
	}
	@Test
	public  void test() {
		Book book = new Book();
		InvocationHander h = new ProxyHander(book);
		BookInterface bi = (BookInterface)Proxy.newProxyInstance(BookInterface.class,h);
		bi.selling(); // 没有日志打印
		
		System.out.println("==================分割==============================");
		
		PhoneInterface car = new VivoPhone();
		h = new ProxyHander(car);
		PhoneInterface pi = (PhoneInterface)Proxy.newProxyInstance(PhoneInterface.class,h);
		pi.selling(); // 有日志打印
	}
	@After
	public void  after(){
		System.out.println("-----------------end-------------------");	
	}
}

 Proxy类里面生成代理类名称的方法是根据包名来的,全类名长度加起来超过250多个长度可能会让java类无法编译,那就需要特殊处理了。超过250个长度的全类名那种项目没见过,不考虑

上面是他的原理,spring中如何使用aop呢?

 请参考

 参考文章  

 

0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics