zoukankan      html  css  js  c++  java
  • Spring AOP

    spring 提供了多种不同的方案实现对 bean 的 aop proxy, 包括 ProxyFactoryBean, 便利的 TransactionProxyFactoryBean 以及 AutoProxyCreator 等,
    下图是 proxy class diagram 以供参考

    这里重点说一下最常用的 ProxyFactoryBean, TransactionProxyFactoryBean, BeanNameAutoProxyCreator, DefaultAdvisorAutoProxyCreator 的联系和区别

    1. ProxyFactoryBean : 使用率最高的 proxy 方式, 它通过配置 interceptorNames 属性决定加入哪些 advisor (method interceptor 将会被自动包装成 advisor, 下文将描述这个细节),
    注意是 "interceptorNames" 而不是 "interceptors",

    原因是 ProxyFactoryBean 可能返回非 singleton 的 proxy 实例, 而 advisior 可能也是非 singleton 的,

    因此不能通过 interceptor reference 来注入

    2. TransactionProxyFactoryBean : 特定用于 transaction proxy, 注意其 super class 是 AbstractSingletonProxyFactoryBean, 也就是说,

    TransactionProxyFactoryBean 永远无法返回非 singleton 的 proxy 实例 !!!

    如果你需要非 singleton 的 proxy 实例, 请考虑使用 ProxyFactoryBean.

    3. BeanNameAutoProxyCreator : 故名思义, 根据 bean name 进行 auto proxy, bean name 的 match 规则参见 org.springframework.util.PatternMatchUtils

    4. DefaultAdvisorAutoProxyCreator : 更强大的 auto proxy creator, 强大之处在于它会 cahce 容器中所有注册的 advisor, 然后搜索容器中所有的 bean ,
    如果某个 bean 满足 advisor 中的 Pointcut, 那么将会被自动代理, 与 BeanNameAutoProxyCreator 相比, 省去了配置 beanNames 的工作,

    引用:
    eg :

    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
    <bean id="defaultPointcutAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor" scope="prototype">
    <property name="pointcut" ref="fooPointcut"/>
    <property name="advice" ref="fooAdvice"/>
    </bean>

    <bean id="fooAdvice" class="com.mycompany.FooAdvice" scope="prototype" />

    <bean id="fooPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut" scope="prototype">
    <property name="patterns">
    <list>
    <value>com.mycompany.FooService.*</value>
    </list>
    </property>
    </bean>


    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
    <bean id="defaultPointcutAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor" scope="prototype">
    <property name="pointcut" ref="fooPointcut"/>
    <property name="advice" ref="fooAdvice"/>
    </bean>

    <bean id="fooAdvice" class="com.mycompany.FooAdvice" scope="prototype" />

    <bean id="fooPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut" scope="prototype">
    <property name="patterns">
    <list>
    <value>com.mycompany.FooService.*</value>
    </list>
    </property>
    </bean>

    以上配置将自动代理容器中所有 com.mycompany.FooService 类型的 bean, 并拦截其所有方法


    深度话题

    1. MethodInterceptor 如何被包装成 Advisor ?

    在 AdvisorAdapterRegistry#wrap(Object) 方法中实现, code as below
    public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
    if (adviceObject instanceof Advisor) {
    return (Advisor) adviceObject;
    }
    if (!(adviceObject instanceof Advice)) {
    hrow new UnknownAdviceTypeException(adviceObject);
    }
    Advice advice = (Advice) adviceObject;
    if (advice instanceof MethodInterceptor) {
    // So well-known it doesn't even need an adapter.
    return new DefaultPointcutAdvisor(advice);
    }
    for (int i = 0; i < this.adapters.size(); i++) {
    / Check that it is supported.
    AdvisorAdapter adapter = (AdvisorAdapter) this.adapters.get(i);
    if (adapter.supportsAdvice(advice)) {
    return new DefaultPointcutAdvisor(advice);
    }
    }
    throw new UnknownAdviceTypeException(advice);
    }

    public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
    if (adviceObject instanceof Advisor) {
    return (Advisor) adviceObject;
    }
    if (!(adviceObject instanceof Advice)) {
    hrow new UnknownAdviceTypeException(adviceObject);
    }
    Advice advice = (Advice) adviceObject;
    if (advice instanceof MethodInterceptor) {
    // So well-known it doesn't even need an adapter.
    return new DefaultPointcutAdvisor(advice);
    }
    for (int i = 0; i < this.adapters.size(); i++) {
    / Check that it is supported.
    AdvisorAdapter adapter = (AdvisorAdapter) this.adapters.get(i);
    if (adapter.supportsAdvice(advice)) {
    return new DefaultPointcutAdvisor(advice);
    }
    }
    throw new UnknownAdviceTypeException(advice);
    }

    从代码可以看到, 如果 adviceObject(也就是 interceptorNames 对应的 bean) 不是 advisor
    而是 MethodInterceptor 或 Advice, 那么 spring 将其包装成 DefaultPointcutAdvisor,
    而 DefaultPointcutAdvisor 中定义的 Pointcut 是 TruePointcut :
    class TruePointcut implements Pointcut, Serializable {

    public static final TruePointcut INSTANCE = new TruePointcut();

    /**
    * Enforce Singleton pattern.
    */
    private TruePointcut() {
    }

    public ClassFilter getClassFilter() {
    return ClassFilter.TRUE;
    }

    public MethodMatcher getMethodMatcher() {
    return MethodMatcher.TRUE;
    }

    /**
    * Required to support serialization. Replaces with canonical
    * instance on deserialization, protecting Singleton pattern.
    * Alternative to overriding <code>equals()</code>.
    */
    private Object readResolve() {
    return INSTANCE;
    }

    public String toString() {
    return "Pointcut.TRUE";
    }

    }

  • 相关阅读:
    SpringMVC请求静态资源
    Spring视图和视图解析器
    @ModelAttribute运行流程
    SpringMVC模型数据处理
    SpringMVC简单映射请求参数介绍
    队列和栈的问题
    非比较排序——计数排序、基数排序、桶排序
    递归
    对数器的使用
    常见的比较排序
  • 原文地址:https://www.cnblogs.com/huangchuansen/p/SPRNG.html
Copyright © 2011-2022 走看看