zoukankan      html  css  js  c++  java
  • Spring 中如何自动创建代理(spring中的三种自动代理创建器)

    Spring 提供了自动代理机制,可以让容器自动生成代理,从而把开发人员从繁琐的配置中解脱出来 。 具体是使用 BeanPostProcessor 来实现这项功能。

    这三种自动代理创建器 为:BeanNameAutoProxyCreator     ,  DefaultAdvisorAutoProxyCreator  ,    AbstractAdvisorAutoProxyCreator。

    1BeanPostProcessor

    BeanPostProcessor 代理创建器的实现类可以分为 3 类:

    类型实现类
    基于 Bean 配置名规则 BeanNameAutoProxyCreator
    基于 Advisor 匹配规则 DefaultAdvisorAutoProxyCreator
    基于 Bean 中的 AspectJ 注解标签的匹配规则 AnnotationAwareAspectJAutoProxyCreator

    BeanPostProcessor 类继承关系

    所有的自动代理器类都实现了 BeanPostPorcessor ,在容器实例化 Bean 时, BeanPostProcessor 将对它进行加工处理,所以自动代理创建器能够对满足匹配规则的 bean 自动创建代理对象。

    2 BeanNameAutoProxyCreator

    假设有以下两个实体类(用户与充电宝)。

    用户类:

    public class User {
    
        public void rent(String userId) {
            System.out.println("User:租赁【充电宝】");
        }
    
        public void back(String userId){
            System.out.println("User:归还【充电宝】");
    
        }
    }

    充电宝:

    public class Charger {
    
        public void rent(String userId) {
            System.out.println("Charger:【充电宝】被租赁");
        }
    }

    我们希望通过 BeanNameAutoProxyCreator 通过 Bean 的名称来自动创建代理,实现增强:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:p="http://www.springframework.org/schema/p"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
    
        <bean id="user" class="net.deniro.spring4.aop.User"/>
        <bean id="charger" class="net.deniro.spring4.aop.Charger"/>
    
        <!-- 前置增强-->
        <bean id="rentBeforeAdvice" class="net.deniro.spring4.aop.RentBeforeAdvice"/>
    
        <!-- 使用 BeanNameAutoProxyCreator-->
        <bean
                class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"
                p:beanNames="*er"
                p:interceptorNames="rentBeforeAdvice"
                p:optimize="true"
                ></bean>
    </beans>

    BeanNameAutoProxyCreator的 beanNames 属性允许指定一组需要自动代理的 Bean 名称, 这里可以使用 * 通配符 。

    因为我们需要代理的类名分别是 user 与 charger,都是以 er 结尾的,所以我们这里定义为 *er

    也可以通过 beanNames 的 value 值来明确指定需要代理的 Bean 名称,多个以逗号分隔(更常用)。

    <!-- 指定自动代理的 Bean 名称-->
    <property name="beanNames" value="user,charger">
    </property>

    也可以通过 list 方式来指定 beanNames 的值:

    <property name="beanNames">
        <list>
            <value>user</value>
            <value>charger</value>
        </list>
    </property>

    p:optimize 设置为 true,则表示使用 CGLib 动态代理技术。

    通过这样的配置之后,容器在创建 user 和 charger Bean 的实例时,就会自动为它们创建代理对象,而这一操作对于使用者来说完全是透明的 。

    单元测试:

    User user = (User) context.getBean("user");
    Charger charger = (Charger) context.getBean("charger");
    
    String userId = "001";
    user.rent(userId);
    charger.rent(userId);

    输出结果:

    准备租赁的用户 ID:001
    User:租赁【充电宝】
    准备租赁的用户 ID:001
    Charger:【充电宝】被租赁

    3 DefaultAdvisorAutoProxyCreator

    切面 Advisor 是切点和增强的复合体,而 DefaultAdvisorAutoProxyCreator 能够扫描 Advisor, 并将 Advisor 自动织入到匹配的目标 Bean 中。

    <bean id="user" class="net.deniro.spring4.aop.User"/>
    <bean id="charger" class="net.deniro.spring4.aop.Charger"/>
    
    <!-- 前置增强-->
    <bean id="rentBeforeAdvice" class="net.deniro.spring4.aop.RentBeforeAdvice"/>
    
    <!-- 静态正则表达式方法名匹配-->
    <bean id="regexpAdvisor"
          class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"
          p:advice-ref="rentBeforeAdvice">
        <!-- 匹配模式-->
        <property name="patterns">
            <list>
                <!-- 匹配字符串-->
                <value>.*rent.*</value>
            </list>
        </property>
    </bean>
    
    <!-- 使用 DefaultAdvisorAutoProxyCreator-->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

    首先我们配置了以静态正则表达式方法名匹配的切面,然后直接配置了 DefaultAdvisorAutoProxyCreator Bean。

    测试代码与输出结果与上一小节的 BeanNameAutoProxyCreator 相同。

    JDK 动态代理是通过接口来实现方法拦截,所以必须确保要拦截的目标在接口中有定义。

    CGLib 动态代理是通过动态生成代理子类来实现方法拦截,所以必须确保要拦截的目标方法可以被子类所访问,也就是目标方法必须定义为非 final, 且非私有实例方法 。

  • 相关阅读:
    【HDOJ】2774 Shuffle
    【POJ】2170 Lattice Animals
    【POJ】1084 Square Destroyer
    【POJ】3523 The Morning after Halloween
    【POJ】3134 Power Calculus
    【Latex】如何在Latex中插入伪代码 —— clrscode3e
    【HDOJ】4801 Pocket Cube 的几种解法和优化
    【HDOJ】4080 Stammering Aliens
    【HDOJ】1800 Flying to the Mars
    SQL语法
  • 原文地址:https://www.cnblogs.com/weixupeng/p/10482122.html
Copyright © 2011-2022 走看看