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; import jdkproxy.LogTranService; import jdkproxy.TimeTranService; public class ProxyHander implements InvocationHander { private Object target; public ProxyHander(Object target) { this.target = target; } @Override public void invoke(Object o, Method m) { try { TimeTranService.before(); if(!(o instanceof BookInterface)){//只有非BookInterface接口调用日志 LogTranService.before(); } m.invoke(target); if(!(o instanceof BookInterface)){ LogTranService.after(); } TimeTranService.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呢?
请参考
参考文章