一说到AOP,你们必定会想到Spring,由于这东西实在是太强大了.可是你们必定要清楚,AOP是一只编程思想,而Spring仅仅是AOP的一种实现罢了.
java
首先百度下:
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,经过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP能够对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度下降,提升程序的可重用性,同时提升了开发的效率。
若是你对AOP尚未了解请左移百度百科:http://baike.baidu.com/search/word?word=AOP查看.
今天呢,我们就一块儿用Java原生代理实现简单的AOP功能.
首先,你得须要了解基本的反射知识,不然可能会感到困惑.
不罗嗦了,直接开始撸码
首先,我们先写一个简单的接口.名字叫AnimalInterface,用来声明规范动物的一些基本方法.
这些方法包括 设置名字,获取名字,叫声,属性(原谅我没文化,其实就是得到是陆栖仍是水栖或者水陆两栖)
git
package proxy.imp; public interface AnimalInterface { //设置名字 void setName(String name); //获取名字 String getName(); //叫声 void say(); //获取栖性 void getProperty(); }
而后我们实现这个接口,建立一个名叫小黑的Doggithub
package proxy; import proxy.imp.AnimalInterface; public class DogImp implements AnimalInterface { private String name = "小黑"; public DogImp() { } @Override public void setName(String name) { this.name = name; } @Override public String getName() { return this.name; } @Override public void say() { System.out.println("小狗:汪汪汪汪....."); } @Override public void getProperty() { System.out.println("小狗是陆地动物,可是会游泳哦"); } }
你们必定火烧眉毛了,怎么实现相似AOP的功能呢….
我们先建立一个名为AOPHandle的类,让其实现InvocationHandler接口,
不能使用invoke时使用proxy做为反射参数时,由于代理对象的接口,不一样于对象,
这种代理机制是面向接口,而不是面向类的,若是使用proxy,会形成无限递归.而后就是栈溢出,可是依旧能反射成功一次,
这说明代理对象和对象的代理是不同的,可是我们能够经过proxy参数的proxy.getClass()得到class对象,而后得到被代理
类的方法和参数,这也为注解注入,特定方法注入,属性注入提供了一种实现途径吧,关于这个,我们后面再说..
编程
package proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class AOPHandle implements InvocationHandler{ //保存对象 private Object o; public AOPHandle(Object o) { this.o=o; } /** * 这个方法会自动调用,Java动态代理机制 * 会传入下面是个参数 * @param Object proxy 代理对象的接口,不一样于对象 * @param Method method 被调用方法 * @param Object[] args 方法参数 * 不能使用invoke时使用proxy做为反射参数时,由于代理对象的接口,不一样于对象 * 这种代理机制是面向接口,而不是面向类的 **/ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //方法返回值 Object ret=null; //打印方法名称 System.err.println("执行方法:"+method.getName()+"n参数类型为:"); //打印参数 for(Class type:method.getParameterTypes()) System.err.println(type.getName()); //打印返回类型 System.err.println("返回数据类型:"+method.getReturnType().getName()); //反射调用方法 ret=method.invoke(o, args); //声明结束 System.err.println("方法执行结束"); //返回反射调用方法的返回值 return ret; } }
动态代理已经搞定..而后就是我们的AnimalFactory了..我们继续
框架
package proxy; import java.lang.reflect.Proxy; public class AnimalFactory { /*** * 获取对象方法 * @param obj * @return */ private static Object getAnimalBase(Object obj){ //获取代理对象 return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new AOPHandle(obj)); } /*** * 获取对象方法 * @param obj * @return */ @SuppressWarnings("unchecked") public static T getAnimal(Object obj){ return (T) getAnimalBase(obj); } /*** * 获取对象方法 * @param className * @return */ @SuppressWarnings("unchecked") public static T getAnimal(String className){ Object obj=null; try { obj= getAnimalBase(Class.forName(className).newInstance()); } catch (Exception e) { e.printStackTrace(); } return (T)obj; } /*** * 获取对象方法 * @param clz * @return */ @SuppressWarnings("unchecked") public static T getAnimal(Class clz){ Object obj=null; try { obj= getAnimalBase(clz.newInstance()); } catch (Exception e) { e.printStackTrace(); } return (T)obj; } }
终于到最后了…还差什么呢,你们来这里看看效果吧…
哈哈…小二,上个菜..哦~不对,是个测试类..哈哈////ide
package proxy; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.BlockJUnit4ClassRunner; import proxy.AnimalFactory; import proxy.imp.AnimalInterface; @RunWith(BlockJUnit4ClassRunner.class) public class AOPTest { @Test public void Test1() { AnimalInterface dog=AnimalFactory.getAnimal(DogImp.class); dog.say(); System.out.println("个人名字是"+dog.getName()); dog.setName("二狗子"); System.out.println("个人名字是"+dog.getName()); } }
对,我们的效果已经看到了..
,咦,你会说没图没真相???
好,那就上图…函数式编程
图片在sae上已经丢失,请你们脑补
啥?什么,,到了最后说,,这又卵用,这不是坑爹么?就捕获一个这个玩意,什么用啊…
什么AOP,我怎么一点AOP的影子都没有看到,怎么切入自定义方法,就一个syso输入,往这忽悠观众来了?…..
好吧,那我们继续…看看如何实现注入自定义方法…
首先增长一个接口,我们就称为AOP注入接口吧.取名AOPMethod哈
建立after和before方法,接收Object proxy, Method method, Object[] args参数
这样就能作更多的事情叻…好比执行方法前,记录类状态,写入log.监控xx变量,,,
开启你的脑洞吧.函数
package proxy.imp; import java.lang.reflect.Method; public interface AOPMethod{ //实例方法执行前执行的方法 void after(Object proxy, Method method, Object[] args); //实例方法执行后执行的方法 void before(Object proxy, Method method, Object[] args); }
而后修改AOPHandle类,增长AOPMethod属性.
在修改构造方法,让在类初始化时得到AOPMethod实例.
最后修改invoke方法….直接上代码哈
学习
package proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import proxy.imp.AOPMethod; public class AOPHandle implements InvocationHandler{ //保存对象 private AOPMethod method; private Object o; public AOPHandle(Object o,AOPMethod method) { this.o=o; this.method=method; } /** * 这个方法会自动调用,Java动态代理机制 * 会传入下面是个参数 * @param Object proxy 代理对象的接口,不一样于对象 * @param Method method 被调用方法 * @param Object[] args 方法参数 * 不能使用invoke时使用proxy做为反射参数时,由于代理对象的接口,不一样于对象 * 这种代理机制是面向接口,而不是面向类的 **/ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object ret=null; //修改的地方在这里哦 this.method.before(proxy, method, args); ret=method.invoke(o, args); //修改的地方在这里哦 this.method.after(proxy, method, args); return ret; } }
呼呼,大功告成,,看起来一切都么问题,萌萌哒..
赶忙更新下测试类…测试
package proxy; import java.lang.reflect.Method; import org.junit.runner.RunWith; import org.junit.runners.BlockJUnit4ClassRunner; import proxy.imp.AOPMethod; import proxy.imp.AnimalInterface; @RunWith(BlockJUnit4ClassRunner.class) public class AOPTest { public static void main(String[] args) { AnimalInterface dog = AnimalFactory.getAnimal(DogImp.class, new AOPMethod() { // 这里写方法执行前的AOP切入方法 public void before(Object proxy, Method method, Object[] args) { System.err.println("我在" + method.getName() + "方法执行前执行"); } // 这里系方法执行后的AOP切入方法 public void after(Object proxy, Method method, Object[] args) { System.err.println("我在 " + method.getName() + "方法执行后执行"); } }); dog.say(); String name1="个人名字是" + dog.getName(); System.out.println(name1); dog.setName("二狗子"); String name2="个人名字是"+dog.getName(); System.out.println(name2); } }
来个效果图:
图片在sae上已经丢失,请你们脑补
呼呼,亲们,是否是有注入的感受了?是否是感受把本身的方法切进去了???哈哈…. 看起来一切都已经完美了,可是总以为差了点什么?哦,对,缺乏了相似于Spring那么样的配置文件.. 其实那些已经很简单了,交给大家去作吧,设计好XML格式化就妥了,等等,你说什么,还不能拦截自定义方法? 不能像Spring那样拦截自定义方法?oh~~NO,其实已经能够了在 before(Object proxy, Method method, Object[] args) 中利用method和的给methodName就能作判断了. 固然,本例的并无什么实用意义,更不能个各类完善的AOP框架相比,本文仅仅为您提供一种思路,可是必定要记住,再牛的东西也是一点点积累出来的 学习了解原理,是为了更好的驾驭所掌握的知识和技能.咱再会回嘿嘿.