Spring中常用的設計模式:策略模式
阿新 • • 發佈:2018-11-16
在閻巨集博士的《JAVA與模式》一書中開頭是這樣描述策略(Strategy)模式的:
策略模式屬於物件的行為模式。其用意是針對一組演算法,將每一個演算法封裝到具有共同介面的獨立的類中,從而使得它們可以相互替換。策略模式使得演算法可以在不影響到客戶端的情況下發生變化。
Spring 中在例項化物件的時候用到策略模式, 在SimpleInstantiationStrategy 有使用。
採用實現部分,抽象部分的策略。為了更好的擴充套件性,把一部分再次抽象,後面可以採用多種實現方式。
- 具體程式碼分析
spring中角色分工很明確,建立物件的時候先通過 ConstructorResolver找到對應的例項化方法和引數,再通過例項化策略InstantiationStrategy進行例項化,根據建立物件的三個分支( 工廠方法、有參構造方法、無參構造方法 ), InstantiationStrategy提供了三個介面方法:
public interface InstantiationStrategy {
//預設構造方法
Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) throws BeansException;
//指定構造方法
Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner, Constructor<?> ctor,
Object[ ] args) throws BeansException;
//指定工廠方法
Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner, Object factoryBean,
Method factoryMethod, Object[] args) throws BeansException;
}
在SimpleInstantiationStrategy中對這三個方法做了簡單實現。
如果工廠方法例項化直接用反射建立物件,如果是構造方法例項化的則判斷是否有MethodOverrides,如果無MethodOverrides也是直接用反射,如果有MethodOverrides就需要用cglib例項化物件,SimpleInstantiationStrategy把通過cglib例項化的任務交給了它的子類CglibSubclassingInstantiationStrategy。
public class SimpleInstantiationStrategy implements InstantiationStrategy {
// FactoryMethod的ThreadLocal物件,執行緒所有的變數
private static final ThreadLocal<Method> currentlyInvokedFactoryMethod = new ThreadLocal<Method>();
// 返回當前執行緒所有的FactoryMethod變數值
public static Method getCurrentlyInvokedFactoryMethod() {
return currentlyInvokedFactoryMethod.get();
}
// 第一種例項化方法,實現部分,部分抽象
@Override
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
// bd物件定義裡,是否包含MethodOverride列表;spring有兩個標籤引數會產生MethodOverrides ,分別是 lookup-method,replaced-method
// 沒有MethodOverride物件,可以直接例項化
if (bd.getMethodOverrides().isEmpty()) {
// 例項化物件的構造方法
Constructor<?> constructorToUse;
// 鎖定物件,使獲得例項化構造方法執行緒安全
synchronized (bd.constructorArgumentLock) {
// 檢視bd物件裡是否含有
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
// 沒有就生成
if (constructorToUse == null) {
final Class<?> clazz = bd.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor<?>>() {
@Override
public Constructor<?> run() throws Exception {
return clazz.getDeclaredConstructor((Class[]) null);
}
});
}
else {
constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
}
// 生成成功後,賦值給bd物件,後面使用
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Exception ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
// 反射生成物件
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// 有MethodOverride物件,需要使用另一種實現方式,之類實現
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
// 第一種例項化方法的抽象部分
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, String beanName, BeanFactory owner) {
throw new UnsupportedOperationException("Method Injection not supported in SimpleInstantiationStrategy");
}
// 第二種例項化方法,實現部分,抽象部分
@Override
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner,
final Constructor<?> ctor, Object... args) {
// 檢視bd物件是否有MethodOverride物件
// 沒有MethodOverride,則直接例項化物件
if (bd.getMethodOverrides().isEmpty()) {
if (System.getSecurityManager() != null) {
// use own privileged to change accessibility (when security is on)
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
ReflectionUtils.makeAccessible(ctor);
return null;
}
});
}
// 反射例項化物件
return BeanUtils.instantiateClass(ctor, args);
}
else {
// 有MethodOverride,之類實現例項化方法
return instantiateWithMethodInjection(bd, beanName, owner, ctor, args);
}
}
// 第二種例項化方法的抽象部分
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, String beanName, BeanFactory owner,
Constructor<?> ctor, Object... args) {
throw new UnsupportedOperationException("Method Injection not supported in SimpleInstantiationStrategy");
}
// 第三種例項化方法,全部實現
@Override
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner,
Object factoryBean, final Method factoryMethod, Object... args) {
try {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
ReflectionUtils.makeAccessible(factoryMethod);
return null;
}
});
}
else {
ReflectionUtils.makeAccessible(factoryMethod);
}
// currentlyInvokedFactoryMethod,這塊暫時還沒看到在哪個地方用到了
// 先取出原有的 Method
Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
try {
// 設定當前的Method
currentlyInvokedFactoryMethod.set(factoryMethod);
// 使用factoryMethod例項化物件
return factoryMethod.invoke(factoryBean, args);
}
finally {
// 例項化完成,恢復現場
if (priorInvokedFactoryMethod != null) {
currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
}
else {
currentlyInvokedFactoryMethod.remove();
}
}
}
catch (IllegalArgumentException ex) {
throw new BeanInstantiationException(factoryMethod.getReturnType(),
"Illegal arguments to factory method '" + factoryMethod.getName() + "'; " +
"args: " + StringUtils.arrayToCommaDelimitedString(args), ex);
}
catch (IllegalAccessException ex) {
throw new BeanInstantiationException(factoryMethod.getReturnType(),
"Cannot access factory method '" + factoryMethod.getName() + "'; is it public?", ex);
}
catch (InvocationTargetException ex) {
String msg = "Factory method '" + factoryMethod.getName() + "' threw exception";
if (bd.getFactoryBeanName() != null && owner instanceof ConfigurableBeanFactory &&
((ConfigurableBeanFactory) owner).isCurrentlyInCreation(bd.getFactoryBeanName())) {
msg = "Circular reference involving containing bean '" + bd.getFactoryBeanName() + "' - consider " +
"declaring the factory method as static for independence from its containing instance. " + msg;
}
throw new BeanInstantiationException(factoryMethod.getReturnType(), msg, ex.getTargetException());
}
}
}