对于aop一词,大家已经不在陌生,以下是来自百度百科对aop 的定义:
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
这里举个常见的例子来看aop是如何实现的
@Log
public class UserController {
public User select(int userId) {
log.info("输入的参数是:" + userId);
//...
User result = new User();
log.info("执行的结果是:" + result.toString());
return result;
}
public int insert(User user) {
log.info("输入的参数是:" + user.toString());
//...
int result = 1;
log.info("执行的结果是:" + result);
return result;
}
public int update(String num, String pass) {
log.info("输入的参数是:" + num + " " + pass);
//...
int result = 1;
log.info("执行的结果是:" + result);
return result;
}
}
此时我们发现代码中有些共有重复性的代码:
log.info("输入的参数是:");
log.info("执行的结果是:");
如何将这些重复性的代码抽象出来,首先我们可以想到利用设计模式中的动态代理模式(动态代理模式这里不做细讲,有兴趣可参考:https://github.com/happy-bean/design-pattern)
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log.info("输入的参数是:"+args.toString());
Object result = method.invoke(object, args);
log.info("执行的结果是:" + result);
return result;
}
在这个例子中,我们可以将重复性的代码抽象在动态代理invoke方法中,这也就是aop的横切过程,将通用的日志逻辑织入到被代理类要执行的方法中。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高代码的可重用性,同时提高了开发的效率。
spring中也是使用动态代理模式实现的aop,使用到了JDK动态代理技术和CGLib动态代理技术,我们来看下源码了解一下spring在生成代理对象时会使用哪种实现方式:
org.springframework.aop.framework.DefaultAopProxyFactory
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
1.isOptimize表示让spring自行优化,默认为false
2.isProxyTargetClass表示是否对类生成代理,默认为false(即使用JDK Proxy,只代理接口)
3.hasNoUserSuppliedProxyInterfaces表示bean没有实现任何接口或者实现的接口是SpringProxy接口
以上情况使用CGLib方式实现
1.isInterface表示是否是接口
2.Proxy.isProxyClass 表示类是否是代理类
满足以上条件的使用JDK方式实现(JDK实现方式和CGLib实现方式的区别这里暂不做介绍)。