AOP框架的实现
2016-02-29 12:34
405 查看
AOP的框架的实现
对于一款MVC框架,AOP当然是不可缺少的,这里我们当然也会借鉴spring AOP框架,实现基于切面注解的AOP框架。接下来我们根据代码逐渐分析,这里我们对所有的类(不管有没有父类)均使用cglib。首先添加一个Aspect(切面)的注解,其中有一个value,主要是让框架可以区分是基于Controller的切面还是,还是基于Service的切面。
import java.lang.annotation.*; /** * 切面注解 * 只能作用于类上,运行时 * Created by lizhaoz on 2015/12/20. */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Aspect { Class<? extends Annotation> value(); }
接着在实现一个代理接口
/** * 代理接口 * Created by lizhaoz on 2015/12/20. */ public interface Proxy { /** * 执行链式代理 * author:Lizhao * Date:15/12/20 * version:1.0 * * @param proxyChain * * @return * * @throws Throwable */ Object doProxy(ProxyChain proxyChain) throws Throwable; }
这里我们会执行一个链式代理,按照链上的先后顺序执行,这里传入的参数就是代理链。
对于ProxyChain的实现如下:
public class ProxyChain { private final Class<?> targetClass; //目标类 private final Object targetObject;//目标对象 private final Method targetMethod;//目标方法 private final MethodProxy methodProxy;//方法代理 private final Object[] methodParams;//方法参数 private List<Proxy> proxyList=new ArrayList<Proxy>(); //代理列表 private int proxyIndex = 0;//代理索引 public ProxyChain(Class<?> targetClass, Object targetObject, Method targetMethod, MethodProxy methodProxy, Object[] methodParams, List<Proxy> proxyList) { this.targetClass = targetClass; this.targetObject = targetObject; this.targetMethod = targetMethod; this.methodProxy = methodProxy; this.methodParams = methodParams; this.proxyList = proxyList; } public Object[] getMethodParams(){ return methodParams; } public Class<?> getTargetClass(){ return targetClass; } public Method getTargetMethod(){ return targetMethod; } public Object doProxyChain() throws Throwable{ Object methodResult; if(proxyIndex<proxyList.size()){ //代理策略,通过proxyIndex来充当代理对象的计数器,若未达到proxyList的上限 //就执行proxy对象的proxy方法 //最后就执行目标对象的业务逻辑方法 methodResult=proxyList.get(proxyIndex++).doProxy(this); }else { //执行业务逻辑方法 methodResult=methodProxy.invokeSuper(targetObject,methodParams); } return methodResult; } }
在ProxyChain中有很多成员变量,targetClass-目标类,也就是我们需要代理的类,targetObject–目标对象,targetMethod–目标方法,MethodProxy 方法代理,methodParams方法参数,proxyList–代理列表,proxy–代理索引用来记录当前在哪个代理,其中有一个最重要的方法doProxyChain,这个是用来执行方法的逻辑具体分析可以看代码中的注释有详细的解释。
到目前为止我们还没有用到CGLib,这个时候我们就要使用CGLib了,添加Maven依赖就不必多说了
,如果我们想生成一个代理类就必须使用代理管理器。
/** * 代理管理器 * 我们使用CGLIB提供的ENhancer#create方法来创建代理对象,将intercept的参数传入ProxyChain的构造器中即可 * Created by lizhaoz on 2015/12/20. */ public class ProxyManager { public static <T> T createProxy(final Class<?> targetClass,final List<Proxy> proxyList){ return (T) Enhancer.create(targetClass, new MethodInterceptor() { @Override public Object intercept(Object targetObject, Method targetmethod, Object[] methodParams, MethodProxy methodProxy) throws Throwable { return new ProxyChain(targetClass,targetObject,targetmethod,methodProxy,methodParams, proxyList).doProxyChain(); } }); } }
这里使用的createProxy的两个参数一个是目标类,一个是代理列表,Enhancer.create(Class type, Callback callback)也是CGLIB中的方法用来生成CGLIB代理对象,这里用匿名内部类生成一个方法拦截器,intercept方法这里也是拦截方法,每次调用代理对象都会调用这个方法,这里直接使用ProxyChain.doProxyChain开始执行拦截。
在这里我们需要一个统一的切面模板类如下:
/** * 切面代理 * 提供模板方法,让子类方便实现 * Created by lizhaoz on 2015/12/20. */ public abstract class AspectProxy implements Proxy { private static final Logger LOGGER= LoggerFactory.getLogger(AspectProxy.class); @Override public final Object doProxy(ProxyChain proxyChain) throws Throwable{ Object result=null; Class<?> cls=proxyChain.getTargetClass(); Method method=proxyChain.getTargetMethod(); Object[] params =proxyChain.getMethodParams(); begin();//begin的模板 try{ //拦截的模板 if(intercept(cls,method,params)){ //前置增强的模板 before(cls,method,params); result =proxyChain.doProxyChain(); after(cls,method,params,result); } else { result = proxyChain.doProxyChain(); } }catch (Exception e){ LOGGER.error("proxy failure",e); error(cls,method,params,e); throw e; } finally { end(); } return result; } public void end() throws Throwable{ } public void error(Class<?> cls, Method method, Object[] params, Exception e)throws Throwable { } public void after(Class<?> cls, Method method, Object[] params, Object result)throws Throwable { } public void before(Class<?> cls, Method method, Object[] params) throws Throwable{ } public boolean intercept(Class<?> cls, Method method, Object[] params)throws Throwable { return true; } public void begin() throws Throwable{ } }
其中有许多空方法,这些都是采用了模板模式,子类继承他实现即可。AOP的框架基本实现了,现在如何加入AOP,如何把代理类加入进去,接下来需要一个AOP助手类。
static { try{ //创建代理类和他所要代理的每个类所有集合的映射 Map<Class<?>,Set<Class<?>>> proxyMap=createProxyMap(); //根据上面的映射创建得到每个类有哪些代理的映射。 Map<Class<?>,List<Proxy>> targetMap=createTargetMap(proxyMap); //然后遍历目标类,替换目标类的实例为代理对象 for(Map.Entry<Class<?>,List<Proxy>> targetEntry:targetMap.entrySet()){ Class<?> targetClass =targetEntry.getKey(); List<Proxy> proxyList=targetEntry.getValue(); Object proxy= ProxyManager.createProxy(targetClass,proxyList); //添加目标类和代理实例 BeanHelper.setBean(targetClass,proxy); } }catch (Exception e){ LOGGER.error("aop failure",e); }
具体实现github地址:https://github.com/lzggsimida123/iframework
相关文章推荐
- Shell终端收听音乐--网易云音乐命令行版
- 记录一下nginx对upstream上流服务器的数据读取
- Shell终端收听音乐--豆瓣FM命令行版
- putty连接HDFS常用操作命令
- OpenStack 系列之File Share Service(Manila)详解
- OpenStack 系列之File Share Service(Manila)详解
- 【DSP开发】德州仪器达芬奇五年之路七宗罪,嵌入式处理器架构之争决战2012
- Visual Studio下OpenCV最完美的环境配置方法
- nginx均衡多tomcat环境配置,及这种环境下的remoteIp及ServerName获取方式
- Linux修改网卡名字(CentOS)
- 显示popupWindow
- 网站访问慢排查方法及解决方案
- Linux常用命令大全
- Shell中编写简单计算器
- Hadoop概括——学习笔记<一>转
- ctrl+c,ctrl+d,ctrl+z在linux中意义
- linux内存管理内幕
- 讣告:『Linux 中国』联合创始人王兴江先生因病辞世
- linux中为什么要有分段和分页机制
- shell脚本分行、分词