Spring攻略学习笔记(3.08)------为Bean引入状态
一、知识点
有时候,你可能希望为一组现有的对象添加新的状态,跟踪它们的使用情况,如调用次数、最后修改日期等。如果所有对象都有相同的基类,这就不成问题。但是,如果不同的类不在相同的类层次结构中,添加这样的状态就很难。
可以为对象引入一个新的接口,它有一个带有状态字段的实现类。然后,编写另一个通知来根据特定的条件改变状态。
二、代码示例
假定你希望跟踪每个计算器对象的调用次数。由于在原来的计算器类当中没有保存计数器的字段,你需要使用Spring AOP引入一个。首先,为计算器的操作创建一个接口。
package com.codeproject.jackie.springrecipesnote.springaop; /** * @author jackie * */ public interface Counter { public void increase(); public int getCount(); }
实现类Counterlmpl
package com.codeproject.jackie.springrecipesnote.springaop; public class CounterImpl implements Counter { // 存储计数器值 private int count; @Override public void increase() { count++; } @Override public int getCount() { return count; } }
为了将以Counterlmpl为实现的Counter接口引入所有的计算器对象,可以编写如下的带有一个匹配所有计算器实现的类型匹配表达式的引入。
package com.codeproject.jackie.springrecipesnote.springaop; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.DeclareParents; /** * @author jackie * */ @Aspect public class CalculatorIntroduction { @DeclareParents(value = "com.codeproject.jackie.springrecipesnote.springaop.*CalculatorImpl", defaultImpl = CounterImpl.class) public Counter counter; }
这个引入为每个计算器类引入Counterlmpl。但是,它仍然不能够跟踪调用次数。必须在每次调用一个计算器方法时增加计数器值。为此,可以编写一个最终(After)通知。注意,必须取得this对象,而不是target对象,因为只有代理对象实现了Counter接口。
package com.codeproject.jackie.springrecipesnote.springaop; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.DeclareParents; /** * @author jackie * */ @Aspect public class CalculatorIntroduction { 。。。。。 @After("execution(* com.codeproject.jackie.springrecipesnote.springaop.*Calculator.*(..)) && this(counter)") public void increaseCount(Counter counter) { counter.increase(); } }
测试类如下
package com.codeproject.jackie.springrecipesnote.springaop; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @author jackie * */ public class IntroduceStateTest { @Test public void testIntroduceState() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator)applicationContext.getBean("arithmeticCalculator"); arithmeticCalculator.add(1, 2); arithmeticCalculator.sub(1, 2); arithmeticCalculator.mul(1, 2); arithmeticCalculator.div(1, 2); UnitCalculator unitCalculator = (UnitCalculator) applicationContext.getBean("unitCalculator"); unitCalculator.kilogramToPound(100); unitCalculator.kilometerToMile(100); Counter arithmeticCounter = (Counter) arithmeticCalculator; System.out.println(arithmeticCounter.getCount()); Counter unitCounter = (Counter) unitCalculator; System.out.println(unitCounter.getCount()); } }