Spring中使用的设计模式
简单工厂模式
又叫做静态工厂方法(StaticFactory Method)模式,但不属于23种GOF设计模式之一。
简单工厂模式本质就是由一个工厂类根据传进入的参数,动态决定应该创建哪一个产品类。
spring中的BeanFactory就是简单工厂模式的体现。根据传入一个唯一的标识来获得bean对象,但是是再传入参数之后创建还是前创建根据具体情况来定。
工厂方法模式
一般而言,应用程序使用new来创建新的对象,为了将对象的创建和使用分离,采用工厂模式,也就是把对象的创建以及初始化职责交给了工厂对象。
将应用程序的工厂对象交给Spring管理,那么Spring管理的不是普通的bean,而是工厂bean。
以工厂方法中的静态方法为例
import java.util.Random;
public class StaticFactoryBean {
public static Integer createRandom() {
return new Integer(new Random().nextInt());
}
}
建一个config.xm配置文件,将其纳入Spring容器来管理,需要通过factory-method指定静态方法名称
<bean id="random" class="org.lgq.StaticFactoryBean" factory-method="createRandom" scope="prototype"
/>
测试
public static void main(String[] args) {
//调用getBean()时,返回随机数.如果没有指定factory-method,会返回StaticFactoryBean的实例,即返回工厂Bean的实例
XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("config.xml"));
System.out.println("random 对象:"+factory.getBean("random").toString());
}
单例模式
保证一个类仅有一个实例,并提供一个访问它的全局访问点。spring中的单例完成了后半句话,即提供了全局访问点BeanFactory。但是没有从构造器级别去控制单例。
Spring下默认的bean均为singleton,可以通过singleton="true|false"
或者scope="?"
来指定。
适配器模式
将一个接口转换成客户期待的另一个接口。 使原本接口不兼容的类可以一起工作。
SpringAOP中,使用Advice来增强被代理类的功能。
// Adapter接口
public interface AdvisorAdapter {
boolean supportsAdvice(Advice advice);
MethodInterceptor getInterceptor(Advisor advisor);
}
// MethodBeforeAdviceAdapter实现类
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof MethodBeforeAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
}
装饰器模式
在不改变原有对象的基础上,将功能附加到对象上。
spring中用到的装饰器模式在类名上有两种表现:一种是类名中含有Wrapper,另一种是类名中含有Decorator。基本上都是动态地给一个对象添加一些额外的职责。
代理模式
为其他对象提供一种代理以控制对这个对象的访问。 从结构上来看和Decorator模式类似,但Proxy是控制,更像是一种对功能的限制,而Decorator是增加职责。spring的Proxy模式在aop中有体现,比如JdkDynamicAopProxy和Cglib2AopProxy。
观察者模式
定义了对象之间的一对多依赖,让多个观察者对象同时监听某个主题对象,当主题对象发生变化时,它的所有依赖者(观察者)都会收到通知并更新。
spring中Observer模式常用的地方是listener的实现。如ApplicationListener
。
策略模式
定义了一系列算法,分别封装起来,让它们之间可以互相替換,此模式让算法的变化不会影响到使用算法的用户。
spring中在实例化对象的时候用到Strategy模式。
org.springframework.beans.factory.support.SimpleInstantiationStrategy
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
if (!bd.hasMethodOverrides()) {
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
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(
(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
}
else {
constructorToUse = clazz.getDeclaredConstructor();
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
模板方法
定义了一个算法框架,并允许子类为一个或多个步骤提供实现。模板方法使得子类可以不改变一个算法的结构也可以重定义该算法的某些步骤。
一般需要继承。Spring中的jdbcTemplate
,没有使用继承,而是把变化的部分抽取出来,作为参数传入jdbcTemplate
的方法中。
org.springframework.jdbc.core.JdbcTemplate
,使用时传入connection
回调对象。
public <T> T execute(ConnectionCallback<T> action) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
Connection con = DataSourceUtils.getConnection(obtainDataSource());
try {
// Create close-suppressing Connection proxy, also preparing returned Statements.
Connection conToUse = createConnectionProxy(con);
return action.doInConnection(conToUse);
}
catch (SQLException ex) {
// Release Connection early, to avoid potential connection pool deadlock
// in the case when the exception translator hasn't been initialized yet.
String sql = getSql(action);
DataSourceUtils.releaseConnection(con, getDataSource());
con = null;
throw translateException("ConnectionCallback", sql, ex);
}
finally {
DataSourceUtils.releaseConnection(con, getDataSource());
}
}