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就这么多了,你品,你细品!

 

posted @ 2020-02-01 11:47  zomicc  阅读(155)  评论(0编辑  收藏  举报