Spring攻略学习笔记(3.07)------为Bean引入行为
一、知识点
有时候,你可能有一组共享公共行为的类。在OOP中,它们必须扩展相同的基类或者实现相同的接口。这确实是可以用AOP模块化的一个横切关注点。此外,Java的单继承机制仅允许一个类最多继承一个基类。所以,你不能同时从多个实现类中继承行为。
引入(Introduction)是AOP中一种特殊类型的通知。通过为一个接口提供实现类,它允许对象动态地实现该接口。这看上去就像是对象在运行时继承了实现类。而且,你可以用多个实现类将多个接口同时引入对象。这可以实现与多重继承相同的效果。
二、代码示例
MaxCalculator和MinCalculator接口,用于定义max()和min()运算。
[java] package com.codeproject.jackie.springrecipesnote.springaop;
/**
* @author jackie
*
*/
public inte易做图ce MaxCalculator {
public double max(double a, double b);
}
package com.codeproject.jackie.springrecipesnote.springaop;
/**
* @author jackie
*
*/
public inte易做图ce MaxCalculator {
public double max(double a, double b);
}
[java] package com.codeproject.jackie.springrecipesnote.springaop;
/**
* @author jackie
*
*/
public inte易做图ce MinCalculator {
public double min(double a, double b);
}
package com.codeproject.jackie.springrecipesnote.springaop;
/**
* @author jackie
*
*/
public inte易做图ce MinCalculator {
public double min(double a, double b);
} 相应的实现类
[java] package com.codeproject.jackie.springrecipesnote.springaop;
/**
* @author jackie
*
*/
public class MaxCalculatorImpl implements MaxCalculator {
public double max(double a, double b) {
double result = (a >= b) ? a : b;
System.out.println("max(" + a + ", " + b + ") = " + result);
return result;
}
}
package com.codeproject.jackie.springrecipesnote.springaop;
/**
* @author jackie
*
*/
public class MaxCalculatorImpl implements MaxCalculator {
public double max(double a, double b) {
double result = (a >= b) ? a : b;
System.out.println("max(" + a + ", " + b + ") = " + result);
return result;
}
}[java] package com.codeproject.jackie.springrecipesnote.springaop;
/**
* @author jackie
*
*/
public class MinCalculatorImpl implements MinCalculator {
public double min(double a, double b) {
double result = (a <= b) ? a : b;
System.out.println("min(" + a + ", " + b + ") = " + result);
return result;
}
}
package com.codeproject.jackie.springrecipesnote.springaop;
/**
* @author jackie
*
*/
public class MinCalculatorImpl implements MinCalculator {
public double min(double a, double b) {
double result = (a <= b) ? a : b;
System.out.println("min(" + a + ", " + b + ") = " + result);
return result;
}
} 如果希望ArithmeticCalculatorlmpl也执行max()和min()计算。由于Java语言仅支持单继承,让 ArithmeticCalculatorlmpl 类同时扩展 MaxCalculatorlmpl 和 MinCalculatorlmpl 是不可能的。唯一可能的方法是通过复制实现代码或者将处理委派给实际的实现类,扩展某个类 (例如MaxCalculatorlmpl)并实现另一个接口(例如MinCalculator)。在两种情况下,你都必须重复方法的声明。
有了引入,通过使用实现类MaxCalculatorlmpl和MinCalculatorlmpl,可以使ArithmeticCalculatorlmpl动态地实现MaxCalculator和MinCalculator接口。这和从 MaxCalculatorlmpl 和 MinCalculatorlmpl多重继承有相同的效果。引入的非凡之处在于不需要修改ArithmeticCalculatorlmpl类引入新的方法。
引入是通过动态代理在Spring AOP中实现这一切的。因为可以为动态代理指定一组需要实现的接口。引入就是通过向动态代理添加一个接口(例 如MaxCalculator)来工作的。当这个接口中声明的方法在代理对象上调用时,代理将把调用委派给后端实现类(例如MaxCalculatorlmpl)。
引入和通知类似,必须在一个aspect中声明。可以创建一个新的aspect或者重用现有的aspect。在下面这个aspect中,可以使用@DeclareParents注解任意一个字段来声明引入。
[java] package com.codeproject.jackie.springrecipesnote.springaop;
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.ArithmeticCalculatorlmpl", defaultImpl = MaxCalculatorImpl.class)
public MaxCalculator maxCalculator;
@DeclareParents(value = "com.codeproject.jackie.springrecipesnote.springaop.ArithmeticCalculatorlmpl", defaultImpl = MinCalculatorImpl.class)
public MinCalculator minCalculator;
}
package com.codeproject.jackie.springrecipesnote.springaop;
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.ArithmeticCalculatorlmpl", defaultImpl = MaxCalculatorImpl.class)
public MaxCalculator maxCalculator;
@DeclareParents(value = "com.codeproject.jackie.springrecipesnote.springaop.ArithmeticCalculatorlmpl", defaultImpl = MinCalculatorImpl.class)
public MinCalculator minCalculator;
}
@DeclareParents注解的value属性表示引入的目标类。引入的接口由被注解的字段类型确定。最后,用于新接口的实现类在defaultlmpl属性中指定。
通过这两个引入,你可以动态地为ArithmeticCalculatorlmpl类引入两个接口。实际上,可以在@DeclareParents注解的value属性中指定一个AspectJ类型匹配表达式,将一个接口引入多个类。最后需要在应用上下文中声明这个aspect的一个实例。
[html] <bean class="com.codeproject.jackie.springrecipesnote.springaop.CalculatorIntroduction" />
<bean class="com.codeproject.jackie.springrecipesnote.springaop.CalculatorIntroduction" />
测试类
[java] package com.codeproject.jackie.springrecipesnote.springaop;
import org.junit.Test;
import org.springframework.context.ApplicationContext; 补充:软件开发 , Java ,