在开始正文之前,先聊点其它的,原本规划的《Spring AOP实现原理》系列的最后一章节是讲解Spring AOP源码的。刚开始对此也是信心满满的,直到我深入读了源码之后才发现这事情没有那么简单。
首先,Spring AOP源码有些多,不够精简,这就给书面讲解造成很大麻烦。其次,完全基于Spring AOP源码讲解它的实现似乎也没有太大意义。
因此我决定另辟蹊径,从Spring AOP的特性和功能发起,然后结合着Spring AOP实现的思路,大致实现一个Spring AOP的架子。
特别声明:在实现的过程中,由于篇幅原因,砍掉了不少优化部分,特别是有关工厂,懒加载,缓存,并发等。
从上一章节中,我们得知了Spring AOP的特性以及其要完成功能,我们抽取出其中的重点列举一下:
我们针对这些特性做一个功能分析,大致有如下功能:
AOP,主要专注于基于方法的AOP功能实现,分为三个方面:
对象代理,支持JDK和CGLIB两种代理方式,实现根据目标对象(target)生成对应的代理对象
配置解析,支持XML和Annotation两种配置方式的解析,实现根据配置解析出对应的Advisor等
IoC集成,集成BeanFactory,实现对IoC容器中bean的访问;实现BeanPostProcesser,将配置解析、创建代理对象等纳入到bean初始化流程
注:我们看下官网对Advisor的解释:*
An advisor is like a small self-contained aspect that has a single piece of advice.
*Advisor是具有 单个 Advice以及可以使用Pointcut的组合类,可以看作是一个特殊的Aspect。
在列出了Spring AOP功能之后,我们接下来讨论下功能实现的流程
我把流程简单分为两大部分,创建代理阶段和代理调用阶段,其中前者是由Spring IoC初始化触发的,后者是由程序调用触发的,详细流程参考下图:
Spring IoC容器触发Bean初始化,通过BeanPostProcesser接口
调用BeanPostProcesser接口实现方法postProcessAfterInitialization
进入构建Advisor的流程,通过反射找到所有匹配的Advisor
筛选出符合的Advisor
进入创建代理的流程,将上一个流程中得到的Advisor集合传递给代理对象,并且根据规则判断使用哪种代理方式
在列出了Spring AOP功能之后,我们接下来讨论功能的实现部分功能的实现
首先对AspectJ中的概念抽象,我们简单定义下Aspect、JoinPoint、Advice、Pointcut等类。
public class Aspect { } public class JoinPoint { } public interface Pointcut { public String getExpression(); } public class Advice { private Method adviceMethod; private Aspect aspect; } 复制代码
SpringAOP中引入了Advisor的概念,我们同时定义一个Advisor类
public class Advisor { private Advice advice; private Pointcut pointcut; private Aspect aspect; } 复制代码
为了融合AspectJ的表达式,我们针对Pointcut进一步改造
增加字符串表达式转换为AspectJ的表达式(PointcutExpression)
import org.aspectj.weaver.tools.PointcutExpression; //.... /** * 转换为AspectJ的切入点表达式 * @return */ public PointcutExpression buildPointcutExpression(); 复制代码
引入AspectJ解析类(PointcutParser),实现buildPointcutExpression方法
import org.aspectj.weaver.tools.PointcutExpression; import org.aspectj.weaver.tools.PointcutParser; public class AspectJPointcut implements Pointcut { public String expression; public AspectJPointcut(String expression) { this.expression = expression; } @Override public String getExpression() { return this.expression; } @Override public PointcutExpression buildPointcutExpression() { PointcutParser parser = PointcutParser .getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution(); return parser.parsePointcutExpression(this.expression); } } 复制代码
以上,定义了几个基本类。有的小伙伴会说,为什么没有看到BeforeAdvice这些定义呢?这里先卖个关子,等到后面引入方法拦截器的时候再定义。
集成本身比较简单,实现接口BeanPostProcessor和BeanFactoryAware,直接上代码
import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.config.BeanPostProcessor; public abstract class AbstractAOPProxyCreator implements BeanPostProcessor, BeanFactoryAware { //子类可实现 protected void initBeanFactory(BeanFactory beanFactory) { this.beanFactory = beanFactory; } //获取匹配的Advisor protected abstract List<Advisor> getMatchedAdvisors(); //创建代理对象 protected abstract Object createProxy(List<Advisor> advisors, Object bean); @Override public void setBeanFactory(BeanFactory arg0) throws BeansException { } @Override public Object postProcessBeforeInitialization(Object bean, String beanName){ return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName){ return bean; } } 复制代码
实现了BeanFactoryAware接口的setBeanFactory方法,以及BeanPostProcessor接口的postProcessAfterInitialization方法和postProcessBeforeInitialization方法。
下面我们引入 模板方法 设计模式,来制定处理流程:
public Object postProcessAfterInitialization(Object bean, String beanName){ //构建所有Advisor List<Advisor> advisors = buildAdvisors(); //获取符合的Advisor advisors = this.getMatchedAdvisors(); //根据获取的Advisor生成代理对象 Object object = createProxy(advisors,bean); //返回代理对象 return object == null ? bean : object; } 复制代码
解析配置主要就是用到了反射,找到被@Aspect标记的类,进而找到@Advice,@Pointcut等,最终将这些组合成Advisor实例,实现起来并不复杂,不再赘述
public class AnnotationParser implements ConfigParser { //避免重复构建,增加了缓存 private final Map<String, List<Advisor>> cache = new ConcurrentHashMap<>(); @Override public List<Advisor> parse() { if(cache != null) { return getAdvisorsFromCache(); } //获取所有被@Aspect注解的类 List<Class> allClasses = getAllAspectClasses(); for (Class class1 : allClasses) { cache.putIfAbsent(class1.getName(), getAdvisorsByAspect(class1)); } return getAdvisorsFromCache(); } /** * 根据Aspect类生成Advisor类 * @param class1 * @return */ private List<Advisor> getAdvisorsByAspect(Class class1) { List<Advisor> advisors = new ArrayList<>(); for (Method method : getAdvisorMethods(class1)) { Advisor advisor = getAdvisor(method, class1.newInstance()); advisors.add(advisor); } return advisors; } } 复制代码
我们要从所有的Advisor中过滤出来与代理目标Bean相关的,以Bean的方法和Advisor的Pointcut作为过滤条件,这里利用了AspectJ的表达式以及比对工具
import org.aspectj.weaver.tools.ShadowMatch; /** * 从所有的Advisor中获取匹配的 * @param advisors * @return */ public static List<Advisor> getMatchedAdvisors(Class cls, List<Advisor> advisors) { List<Advisor> aList = new ArrayList<>(); for (Method method : cls.getDeclaredMethods()) { for (Advisor advisor : advisors) { ShadowMatch match = advisor.getPointcut() .buildPointcutExpression() .matchesMethodExecution(method); if(match.alwaysMatches()) { aList.add(advisor); } } } return aList; } 复制代码
我们定义了一个工厂,代理对象转交给由工厂创建
public class AOPProxyFactory { public Object getProxyObject(List<Advisor> advisors, Object bean) { if(isInterface()) { return new CglibProxyImpl(advisors,bean).getProxyObject(); } else { return new JdkDynamicProxyImpl(advisors,bean).getProxyObject(); } } private boolean isInterface() { return false; } } 复制代码
同时也实现了两种代理方式,JDK Dynamic Proxy和CGLIB,下面逐一讲解下
注:可以先忽略掉方法拦截器链
JDK 实现方式,需要实现InvocationHandler接口,并且在接口方法invoke中实现方法拦截器链的调用
public class JdkDynamicProxyImpl extends AOPProxy implements InvocationHandler { public JdkDynamicProxyImpl(List<Advisor> advisors, Object bean) { super(advisors, bean); } @Override protected Object getProxyObject() { return Proxy.newProxyInstance(this.getClass().getClassLoader(), ReflectHelper.getInterfaces(this.getTarget().getClass()), this); } /** * 实现InvocationHandler的接口方法,将具体的调用委托给拦截器链MethodInterceptorChain */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MyMethodInterceptor[] iterceptors = AdvisorHelper.getMethodInterceptors(this.getAdvisors(), method); Object obj = new MethodInterceptorChain(iterceptors) .intercept(method,args,proxy); return obj; } } 复制代码
CGLIB是通过回调(Callback)实现的,需要实现CGLIB的MethodInterceptor
import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class CglibProxyImpl extends AOPProxy { public CglibProxyImpl(List<Advisor> advisors, Object bean) { super(advisors, bean); } @Override protected Object getProxyObject() { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.getTarget().getClass()); enhancer.setCallback(new AOPInterceptor()); return enhancer.create(); } /** * 实现cglib的拦截器,在intercept中将拦截器调用委托给拦截器链MethodInterceptorChain */ private class AOPInterceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { MyMethodInterceptor[] iterceptors = AdvisorHelper.getMethodInterceptors(CglibProxyImpl.this.getAdvisors(), method); Object o = new MethodInterceptorChain(iterceptors) .intercept(method, args, obj); return o; } } } 复制代码
以上,基本上实现了创建代理对象的流程,那么我们思考一个问题
我们先用一种简单的实现方式说明一下,以JDK代理方式为例:
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return obj; } 复制代码
我们知道,执行代理对象的任何方法都会进入到invoke里(对动态代理还不清楚的同学可以回看第三章动态代理的实现),那么进入到invoke里面之后我们需要做如下判断:
我们以BeforeAdvice为例,展示一下如何实现Advice调用
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { BeforeAdvice beforeAdvice = getBeforeAdvice(method); beforeAdvice.before(proxy, method, args);//调用Advice处 return method.invoke(this.bean, args); } /** * 以返回BeforeAdvice为例 * @return */ private BeforeAdvice getBeforeAdvice(Method method) { for (Advisor advisor : this.getAdvisors()) { if(AdvisorHelper.isMatch(advisor, method) && advisor.getAdvice() instanceof BeforeAdvice) { return (BeforeAdvice) advisor.getAdvice(); } } return null; } 复制代码
那么,问题来了,如果我们获取到匹配的Advice中还有AfterAdvice呢?我们向invoke方法中增加代码
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { BeforeAdvice beforeAdvice = getBeforeAdvice(method); beforeAdvice.before(proxy, method, args);//调用Advice处 Object o = method.invoke(this.bean, args); AfterAdvice afterAdvice = getAfterAdvice(method); afterAdvice.after(proxy, method, args);//调用Advice处 return o; } 复制代码
那么,如果我们获得到两个或者多个相同类型的Advice呢?并且相同类型的Advice间有执行顺序需求。上面这种简单实现就无法满足了,我们需要引入 方法拦截器链
这里做一个简单的扩展,很多拦截器(interceptor),过滤器(filter)的实现都是基于职责链模式实现的,在定义方法拦截器链之前,我们先看看Tomcat是如何实现过滤器(filter)的。
注:确切来说是,Tomcat基于JavaEE标准实现的
Java Sevlet接口
public interface FilterChain { public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException; } public interface Filter { public void init(FilterConfig filterConfig) throws ServletException; public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException; public void destroy(); } 复制代码
Tomcat过滤器链实现
public final class ApplicationFilterChain implements FilterChain { private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0]; void addFilter(ApplicationFilterConfig filterConfig) { //.. } @Override public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { // Call the next filter if there is one //C-1 if (pos < n) { ApplicationFilterConfig filterConfig = filters[pos++]; Filter filter = filterConfig.getFilter(); filter.doFilter(request, response, this); return; } // We fell off the end of the chain -- call the servlet instance servlet.service(request, response); } } 复制代码
Session初始化过滤器
public class SessionInitializerFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { ((HttpServletRequest)request).getSession(); //C-2 chain.doFilter(request, response); } @Override public void init(FilterConfig filterConfig) throws ServletException { // NO-OP } @Override public void destroy() { // NO-OP } } 复制代码
以上实现有几个关键点:
我们引入职责链模式, 将Advice抽象成一个MethodInterceptor 。这对功能实现上有如下好处:
定义拦截器,为了和CGLIB的拦截器区分开,我们命名为MyMethodInterceptor
public interface MyMethodInterceptor { public Object intercept(Method method, Object[] arguments, Object target, MethodInterceptorChain chain); } 复制代码
定义BeforeAdvice和AfterAdvice
public class BeforeAdvice extends Advice implements MyMethodInterceptor { public BeforeAdvice(Method adviceMethod, Aspect aspect) { super(adviceMethod, aspect); } public void before(final Object target, final Method method, final Object[] args) { this.invokeAspectMethod(target, method, args); ; } @Override public Object intercept(Method method, Object[] arguments, Object target, MethodInterceptorChain chain) { this.before(target, method, arguments); return chain.intercept(method, arguments, target); } } public class AfterAdvice extends Advice implements MyMethodInterceptor { public AfterAdvice(Method adviceMethod, Aspect aspect) { super(adviceMethod, aspect); } public void after(final Object target, final Method method, final Object[] args) { this.invokeAspectMethod(target, method, args); } @Override public Object intercept(Method method, Object[] arguments, Object target, MethodInterceptorChain chain) { Object obj = chain.intercept(method, arguments, target); this.after(target, method, arguments); return obj; } } 复制代码
实现方法拦截器链
public class MethodInterceptorChain { private MyMethodInterceptor[] methodInterceptors; public MethodInterceptorChain(MyMethodInterceptor[] methodInterceptors) { this.methodInterceptors = methodInterceptors; } private int index = 0; public Object intercept(Method method, Object[] arguments, Object target) { if (index == methodInterceptors.length) { // call method return method.invoke(target, arguments); } else { return methodInterceptors[index++] .intercept(method, arguments, target, this); } return null; } } 复制代码
那么回到我们最开始的思考题,我们可以把原本简单的实现替换成MethodInterceptorChain,如下:
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MyMethodInterceptor[] iterceptors = AdvisorHelper.getMethodInterceptors(this.getAdvisors(), method); Object obj = new MethodInterceptorChain(iterceptors) .intercept(method,args,proxy); return obj; } 复制代码
这样,我们就将代理方法的调用转移到了MethodInterceptorChain
最后,这里面还隐藏一个小问题,就是代理对象中的Advisor是所有和这个类相关的,我们仍然需要根据method和pointcut找到与方法相匹配的拦截器,这和前面筛选Advisor的实现是一样的,都是基于AspectJ具
在讲完方法拦截器链之后,代理调用的流程也就清晰了,也就不再赘述。
我们本次实现仅仅是基于AspectJ的Annotation配置,Spring AOP同时也支持基于Schema配置。时间与篇幅原因,就不再做深入探讨。
除了本文重点提到的职责链模式,Spring AOP还运用了大量的工厂模式、模板方法模式、适配器模式等。特别是大量使用工厂(比如Aspect工厂,Advisor工厂等)同时配合Spring IoC的情况下,能够支持类和对象(Aspect、Advisor等)强大的管理,包括了加载策略,比如单例,多例,懒加载等。笔者认为,这些值得大家深入学习和研究的。