在学习spring的过程中,了解到一个很重要的java编程思想,就是面向切面的编程(aop)。什么是面向切面的编程呢?对于这个概念我在网上查了,得到如下的答案:
AOP(Aspect-Oriented Programming,面向切面的编程),它是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。它是一种新的方法论,它是对传统OOP编程的一种补充。
概念性的东西比较死,关键是要理解其中的原理。看下图所示:
当你有一个写好的方法,想要在其调用的前面或者后面加上一些记录日志或别的一些逻辑,但又不想更改(或者不能改)原有的代码时,AOP就能发挥它极大的优势了。接下来看看使用Proxy和 InvocationHandler是如何实现的。
public interface UserDao { public void save(User user) ; } //定义一个保存User对象到数据库的接口
public class UserDaoImpl implements UserDao { @Override public void save(User user) { System.out.println("user saved!"); } } //接口的实现
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; //编写切面逻辑类,必须要实现InvocationHandler 接口 public class DebugInterceptor implements InvocationHandler { private Object target; public Object getTarget() { return target; } public void setTarget(Object target) { this.target = target; } //需要插入的逻辑 private void before(Method m) { System.out.println(m.getName() + " start!"); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(method); method.invoke(target, args);//使用java反射调用代理方法 return null; } }
使用Junit4写了个单元测试,测试代理方法。调用Proxy类的静态方法newProxyInstance(classloader,interfaces,handler)产生代理对象。代理对象与被代理对象实现了同一个接口UserDao,所以能调用其中的save方法。
public class ProxyTest { @Test public void testProxy() { UserDao userDao = new UserDaoImpl(); DebugInterceptor di = new DebugInterceptor(); di.setTarget(userDao); UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), di); userDaoProxy.save(new User()); } }
测试结果
save start!
user saved!
成功将切面逻辑加入到方法调用之前,嘿嘿。
到此,Proxy与InvocationHandler实现动态代理的实现过程就搞定了。java动态代理不只有这一个方法,还能用CGlib,CGlib是一个强大的,高性能,高质量的代码生成类库,这里就不多做介绍了,大家可以到网上自己查。
还有spring的AOP实现的动态代理不只是这样子,它使用aspectJ这个切面框架。具体的等以后再继续说吧。继续研究。。。
最后,发现自己写得好少,也存在很多不足,欢迎大家指点与吐槽。
在交流中成长。