Spring Aop Step-By-Step 学习笔记(下)

本文详细介绍 Spring AOP 的各种应用场景,包括引入通知、BeanNameAutoProxyCreator、DefaultAdvisorAutoProxyCreator、可热交换的目标源等核心概念和技术实现。通过实战代码示例,帮助读者深入理解并掌握 Spring AOP 的使用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

五. Spring-Aop 引入的介绍
 
    下面我们介绍一种通知“引入”,关于引入,如同它的名字一样,给对象添加方法和属性。呵呵,好厉害吧。它是通过CBLIB来动态生成类的,所以自己用的时候别忘了加载这个包。
    
     代码:
     购物时候放东西的包包;
public interface CustomerBag {
     void addBag(Object obj);
 
     void clean();
 
     int getCount();
}
 
我们要给别的对象类添加的Mixin,嘿嘿。
public class CustomerMixin extends DelegatingIntroductionInterceptor implements CustomerBag {
 
     private static final long serialVersionUID = 5296015143432822715L;
    
     private ArrayList bag = new ArrayList();
 
     public void addBag(Object obj) {
          bag.add(obj);
     }
 
     public void clean() {
          bag = new ArrayList();
     }
 
     public ArrayList getBag() {
          return bag;
     }
 
     public int getCount() {
          return bag.size();
     }
 
}
 
     我们的xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
 
<beans>
    
     <bean id="customer" class="demo.Customer" singleton="false" />
 
     <bean id="customerMixin" class="demo.CustomerMixin" singleton="false" />
 
 
     <bean id="customerMixinAdvisor" class="org.springframework.aop.support.DefaultIntroductionAdvisor"
          singleton="false">
          <constructor-arg>
               <ref bean="customerMixin" />
          </constructor-arg>
     </bean>
 
     <bean id="customerBean" class="org.springframework.aop.framework.ProxyFactoryBean">
          <property name="proxyTargetClass" value="true" />
          <property name="singleton" value="false" />
          <property name="interceptorNames">
               <list>
                    <value>customerMixinAdvisor</value>
               </list>
          </property>
          <property name="target">
               <ref bean="customer" />
          </property>
     </bean>
 
</beans>
 
可以看到singleton="false"处处可见,因为我们要每个新的对象都有自己引入的状态,不可能只有一个对象来维持,那个我们肯定是不希望的。
修改我们的RunDemo类,添加一个方法:
     /**
      * 创建引用通知;
      */
     public static void customer() {
 
          ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo/customer.xml");
 
          // 这个类是有CGLIB动态生成的;
          Customer bag = (Customer) context.getBean("customerBean");
          CustomerBag bag2 = (CustomerBag) bag;
          bag2.addBag(new Object());
 
          System.out.println(bag.getName());
          System.out.println(bag2.getCount());
     }
 
          在main中调用这个方法,运行,结果如下:
              
               悠~游!
1
 
          在这里我要说明一下,关于引入这个通知的使用我仅仅是看了一眼,具体的例子可能有不恰当之处还请高手们指点。
 
六. Spring-Aop 之 BeanNameAutoProxyCreator
 
BeanNameAutoProxyCreator 看其名,大概知道其意。根据bean的名字自动匹配拦截代理,让我们看看它能带来什么?
代码:
public class PerformanceThresholdInterceptor implements MethodInterceptor {
 
     private final long thresholdInMillis;
 
     PerformanceThresholdInterceptor(long time) {
          thresholdInMillis = time;
 
     }
 
     public Object invoke(MethodInvocation invocation) throws Throwable {
         
          System.out.println(" 开始测试时间.");
          long t = System.currentTimeMillis();
          Object o = invocation.proceed();
          t = System.currentTimeMillis() - t;
          if (t > thresholdInMillis) {
               System.out.println(" 警告:调用的方法所耗费的时间超过预警时间(" + thresholdInMillis + " 微秒)");
          }
          System.out.println(" 测试时间结束.");
          return o;
     }
}
这个又是自定义的,呵呵。我们继承MethodInterceptor这换类,实现我们自己的方法过滤器。具体要实现的功能就是检验我们要调用的方法,和OnePerCustomerInterceptor这个类一样。
接下来是我们的xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
 
<beans>
     <bean id="kwikEMartTarget" class="demo.ApuKwikEMart"></bean>
    
     <bean id="performanceThresholdInterceptor" class="demo.advice.PerformanceThresholdInterceptor">
          <constructor-arg>
               <value>5000</value>
          </constructor-arg>
     </bean>
 
     <bean id="beanNameAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
          <property name="beanNames">
               <list>
                    <value>*Target</value>
               </list>
          </property>
          <property name="interceptorNames">
               <value>performanceThresholdInterceptor</value>
          </property>
     </bean>
 
</beans>
 
在main方法中加入我们的方法:
   /**
    * 创建beanNameAutoProxyCreator动态代理;
    */
   public static void beanNameProxy() {
 
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo/beanNameProxy.xml");
 
        KwikEMart akem = (KwikEMart) context.getBean("kwikEMartTarget");
        try {
             akem.buyCheese(new Customer());
        } catch (KwikEMartException e) {
             e.printStackTrace();
        }
   }
 
     运行我们的例子,结果如下:
    
开始测试时间.
--我想买:奶酪!
测试时间结束.
    
     看到了么?Spring aop自动寻找Bean的名字为* Target 的类,进行方法过滤。呵呵,可能你会说这个有什么用?自己写不也一样么?其实如果系统变得庞大的话,自己配置也是十分耗费精力的。
 
七. Spring-Aop DefaultAdvisorAutoProxyCreator
 
     接下来我们将介绍更加强大的一个代理器:DefaultAdvisorAutoProxyCreator。
     DefaultAdvisorAutoProxyCreator 和BeanNameAutoProxyCreator不同的是,DefaultAdvisorAutoProxyCreator只和Advisor 匹配,所以我们写一个Advisor到xml文档中去。
     XML 文档如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
 
<beans>
 
     <bean id="kwikEMartTarget" class="demo.ApuKwikEMart"></bean>
     <bean id="performanceThresholdInterceptor" class="demo.advice.PerformanceThresholdInterceptor">
          <constructor-arg>
               <value>5000</value>
          </constructor-arg>
     </bean>
 
     <!-- 使用RegexpMethodPointcutAdvisor来匹配切入点完成个一个Advisor; -->
     <bean id="regexpFilterPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
          <property name="pattern">
               <!--    
                    匹配的名字为方法名;
               -->
               <value>.*buy.*</value>
          </property>
          <property name="advice">
               <ref bean="performanceThresholdInterceptor"/>
          </property>
     </bean>
 
     <bean id="defaultAdvisorAutoProxyCreator"
     class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
 
</beans>
    
     添加下面方法调用main方法中去:
/**
* 创建defaultAdvisorAutoProxyCreator动态代理;
*/
   public static void defaultAdvisorProxy() {
 
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo/defaultAdvisorProxy.xml");
 
        KwikEMart akem = (KwikEMart) context.getBean("kwikEMartTarget");
        try {
             akem.buyCheese(new Customer());
        } catch (KwikEMartException e) {
             e.printStackTrace();
        }
   }
     运行,结果如下:
         
开始测试时间.
--我想买:奶酪!
测试时间结束.
 
 
八. Spring-Aop TargetSources 介绍
 
1. 可热交换的目标源
 
可热交换的目标源主要是在你程序运行中切换目标对象,而此时调用者引用的对象也会自动切换。具体的概念你可以参考Spring-Reference关于它的介绍,我们主要在程序中体会它给我们带来的改变。
修改我们的xml成为下面的样子:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
 
 
<beans>
 
     <bean id="kwikEMartTarget" class="demo.ApuKwikEMart" ></bean>
    
     <bean id="swapApuKwikEMart" class="demo.SwapApuKwikEMart" singleton="false"></bean>
    
     <bean id="onePerCustomerInterceptor" class="demo.advice.OnePerCustomerInterceptor" />
 
     <bean id="nameMatchfilterPointcut" class="org.springframework.aop.support.NameMatchMethodPointcut">
          <property name="mappedName">
               <value>buy*</value>
          </property>
     </bean>
 
     <bean id="runDemofilterPointcutAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
          <property name="pointcut">
               <ref bean="nameMatchfilterPointcut" />
          </property>
          <property name="advice">
               <ref bean="onePerCustomerInterceptor" />
          </property>
     </bean>
 
     <bean id="swappable" class="org.springframework.aop.target.HotSwappableTargetSource">
          <constructor-arg><ref local="kwikEMartTarget"/></constructor-arg>
     </bean>
 
     <bean id="kwikEMart" class="org.springframework.aop.framework.ProxyFactoryBean">
          <property name="proxyInterfaces" value="demo.KwikEMart" />
          <property name="interceptorNames">
               <list>
                    <value>runDemofilterPointcutAdvisor</value>
               </list>
          </property>
          <property name="targetSource">
               <ref bean="swappable" />
          </property>
     </bean>
 
</beans>
 
代码:
切换后的对象
public class SwapApuKwikEMart implements KwikEMart {
     private boolean cheeseIsEmpty = false;
 
     private boolean pepperIsEmpty = false;
 
     private boolean squishIsEmpty = false;
 
     public Cheese buyCheese(Customer customer) throws KwikEMartException {
 
          if (cheeseIsEmpty) {
               throw new NoMoreCheeseException();
          }
 
          Cheese s = new Cheese();
          System.out.println("-- 我不是ApuKwikEMart,我想买:" + s);
          return s;
 
     }
 
     public Pepper buyPepper(Customer customer) throws KwikEMartException {
 
          if (pepperIsEmpty) {
               throw new NoMorePepperException();
          }
 
          Pepper s = new Pepper();
          System.out.println("-- 我不是ApuKwikEMart,我想买:" + s);
          return s;
 
     }
 
     public Squish buySquish(Customer customer) throws KwikEMartException {
 
          if (squishIsEmpty) {
               throw new NoMoreSquishException();
          }
 
          Squish s = new Squish();
          System.out.println("-- 我不是ApuKwikEMart,我想买:" + s);
          return s;
 
     }
 
     public void setCheeseIsEmpty(boolean cheeseIsEmpty) {
        &n
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值