Spring AOP
此文主要是对于spring中AOP实现的一些思考总结 图。
一、先认识两个AOP功能类
1、根据一个表达式判断一个Method是否匹配。
2、根据拦截类类名和拦截器的方法名,获取指定拦截器方法Method。(拦截器即Advice)
其实,在Spring中,还对MethodLocatingFactory提出了一个更高层次的抽象FactoryBean(无非就是说,这个Bean是一个工厂Bean,它的功能是做其他事情,而不是直接供用户使用。比如我们现在的MethodLocatingFactory就是用于生成一个指定的Method)。如下图(AspectInstanceFactory暂忽略,后面生成Advice会用到):
补充:面试中可能会问到BeanFactory和FactoryBean的区别?
二、讲解一个策略ReflectiveMethodInvocation(重要!重要!重要!)
一个可以实现按一定规则(before、afterReturning、afterThrowing等)链式调用增强方法的策略ReflectiveMethodInvocation。如下图:
三、代理工厂AopProxyFactory
对以上的封装:
AopConfig<-AopConfigSupport:包含有:advice拦截器集合、target目标对象。
主要作用是提供一个方法:通过指定的方法获取其匹配的拦截器集合List<MethodInterceptor>。封装到DynamicAdvisedInterceptor中,最终传递给 ReflectiveMethodInvocation去链式处理。
最后封装到AopProxyFactory中,如下图所示:
四、拦截器Advice的合成
AOP中的重中之重,说白了就是根据配置文件生成拦截器,然后通过CGLIB或者JDK生成出代理对象。
(CGLIB和JDK动态代理,可戳此文https://www.cnblogs.com/zomicc/p/12255510.html)
Advice的建立依赖于PointCut,先引入PointCut,PointCut如下图:
在Spring中,生成一个对象是通过BeanDefinition,Advice也不例外。
先介绍下构造Advice对应的BeanDefinition和构造Advice都需要哪些信息:
Advice(Method adviceMethod,AspectJExpressionPointcut pointcut,AspectInstanceFactory adviceObjectFactory):
参数一:拦截器执行方法;
参数二:切入点(顾名思义,用于指定拦截器在哪个TargetMethod上执行);
参数三:切面初始化工厂(用于获取拦截器对象)。
Advice对应的BeanDefinition构造参数都有:
参数一:GenericBeanDefinition(Class类型是MethodLocatingFactory,作用是在生成Advice时获取Method对象。为什么不直接是Method,是因为在xml
解析阶段不进行其他逻辑操作)
参数二:RuntimeReference(对应切入点)
参数三:GenericBeanDefinition(Class类型是AspectInstanceFactory)
以AspectJBeforeAdvice为例,介绍合成BeanDefinition的原理,如下图所示:
至此,拦截器对应的BeanDefinition就已经定义好了,通过XmlBeanDefinitionReader解析即可将所有的合成BeanDefinition加入到BeanFactory。
然后就是使用Ioc中的构造器注入即可生产出真实的拦截器对象Advice。
需要注意的两点是:对于嵌套BeanDefinition需要进一步取值处理,对于FactoryBean类型的也需要获取到真实内容:(重要!重要!重要)
1 public Object resolveValueIfNecessary(Object value) { 2 3 if (value instanceof RuntimeBeanReference) { 4 RuntimeBeanReference ref = (RuntimeBeanReference) value; 5 String refName = ref.getBeanName(); 6 Object bean = this.beanFactory.getBean(refName); 7 return bean; 8 9 }else if (value instanceof TypedStringValue) { 10 return ((TypedStringValue) value).getValue(); 11 } else if (value instanceof BeanDefinition) {//一、对于嵌套的BeanDefinition需要进一步取值 12 // Resolve plain BeanDefinition, without contained name: use dummy name. 13 BeanDefinition bd = (BeanDefinition) value; 14 15 String innerBeanName = "(inner bean)" + bd.getBeanClassName() + "#" + 16 Integer.toHexString(System.identityHashCode(bd)); 17 18 return resolveInnerBean(innerBeanName, bd); 19 20 } 21 else{ 22 return value; 23 } 24 } 25 private Object resolveInnerBean(String innerBeanName, BeanDefinition innerBd) { 26 27 try { 28 29 Object innerBean = this.beanFactory.createBean(innerBd);//二、获取内部BeanDefinition对应的Bean 30 31 if (innerBean instanceof FactoryBean) {//三、如果是FactoryBean类型,则需要通过getObject()方法获取真实的内容 32 try { 33 return ((FactoryBean<?>)innerBean).getObject(); 34 } catch (Exception e) { 35 throw new BeanCreationException(innerBeanName, "FactoryBean threw exception on object creation", e); 36 } 37 } 38 else { 39 return innerBean; 40 } 41 } 42 catch (BeansException ex) { 43 throw new BeanCreationException( 44 innerBeanName, 45 "Cannot create inner bean '" + innerBeanName + "' " + 46 (innerBd != null && innerBd.getBeanClassName() != null ? "of type [" + innerBd.getBeanClassName() + "] " : "") 47 , ex); 48 } 49 }
五、最终通过Bean生命周期的“钩子”函数AspectJAutoProxyCreator生成真实的代理对象
本质上就是通过BeanPostProcessor的afterInitialization()方法对AopProxyFactory的进一步封装。AspectJAutoProxyCreator代码如下:
public class AspectJAutoProxyCreator implements BeanPostProcessor { ConfigurableBeanFactory beanFactory; public Object beforeInitialization(Object bean, String beanName) throws BeansException { return bean; } public Object afterInitialization(Object bean, String beanName) throws BeansException { //如果这个Bean本身就是Advice及其子类,那就不要再生成动态代理了。 if(isInfrastructureClass(bean.getClass())){ return bean; } List<Advice> advices = getCandidateAdvices(bean);//获取可用拦截器 if(advices.isEmpty()){ return bean; } return createProxy(advices,bean); } private List<Advice> getCandidateAdvices(Object bean){ List<Object> advices = this.beanFactory.getBeansByType(Advice.class); List<Advice> result = new ArrayList<Advice>(); for(Object o : advices){ Pointcut pc = ((Advice) o).getPointcut(); if(canApply(pc,bean.getClass())){ result.add((Advice) o); } } return result; } protected Object createProxy( List<Advice> advices ,Object bean) { AopConfigSupport config = new AopConfigSupport(); for(Advice advice : advices){ config.addAdvice(advice);//构造AopConfig(添加拦截器) } Set<Class> targetInterfaces = ClassUtils.getAllInterfacesForClassAsSet(bean.getClass()); for (Class<?> targetInterface : targetInterfaces) { config.addInterface(targetInterface); } config.setTargetObject(bean);//构造AopConfig(添加目标对象) AopProxyFactory proxyFactory = null; if(config.getProxiedInterfaces().length == 0){ proxyFactory = new CglibProxyFactory(config);//cglib代理 } else{ proxyFactory = new JdkAopProxyFactory(config); } return proxyFactory.getProxy();//获取代理对象 } protected boolean isInfrastructureClass(Class<?> beanClass) { boolean retVal = Advice.class.isAssignableFrom(beanClass); return retVal; } public void setBeanFactory(ConfigurableBeanFactory beanFactory) { this.beanFactory = beanFactory; } public static boolean canApply(Pointcut pc, Class<?> targetClass) { MethodMatcher methodMatcher = pc.getMethodMatcher(); Set<Class> classes = new LinkedHashSet<Class>(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); classes.add(targetClass); for (Class<?> clazz : classes) { Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { if (methodMatcher.matches(method/*, targetClass*/)) {//有一个方法与切入点匹配,则该bean就是需要动态代理的对象 return true; } } } return false; } }
最后,Bean生命周期图附一张:
AOP就这么多了,你品,你细品!