1.解释器模式【interpreter】
Spring在SpEL中应用的解释器模式,很典型的应用场景。
Spring的SpEL是一门DSL语言,它的表达式由org.springframework.expression.ExpressionParser的实现负责分析和执行。ExpressionParser变得实现接收SpEL表达式最为输入字符串,并将其转换为一个org.springframework.expression.Expression实例。
2.构建者模式【Builder】
Spring中典型的构建者类是BeanDefinitionBuilder,主要是在加载自定义的BeanDfinition时使用。
Spring仅认为"http://www.springframework.org/schema/beans"命名空间属于默认命名空间,其他都属于自定义的命名空间,在解析自定义的命名空间时,需要找出该命名空间对应的BeanDefinitionParser,而BeanDefinitionBuilder即使在解析这些自定义的元素时候使用的。
举例子,在解析context:时候,其对应的BeanDefinitionParser是PropertyPlaceholderBeanDefinitionParser:
public abstract class AbstractBeanDefinitionParser implements BeanDefinitionParser {
public final BeanDefinition parse(Element element, ParserContext parserContext) {
// 为了将真实的解析逻辑,下沉到子类,调用parserInternal来解析dom元素
AbstractBeanDefinition definition = parseInternal(element, parserContext);
if (definition != null && !parserContext.isNested()) {
try {
String id = resolveId(element, definition, parserContext);
if (!StringUtils.hasText(id)) {
parserContext.getReaderContext().error(
"Id is required for element '" + parserContext.getDelegate().getLocalName(element)
+ "' when used as a top-level tag", element);
}
String[] aliases = null;
if (shouldParseNameAsAliases()) {
String name = element.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(name)) {
aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
}
}
BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
registerBeanDefinition(holder, parserContext.getRegistry());
if (shouldFireEvents()) {
BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
postProcessComponentDefinition(componentDefinition);
parserContext.registerComponent(componentDefinition);
}
}
catch (BeanDefinitionStoreException ex) {
String msg = ex.getMessage();
parserContext.getReaderContext().error((msg != null ? msg : ex.toString()), element);
return null;
}
}
return definition;
}
}
public abstract class AbstractSingleBeanDefinitionParser extends AbstractBeanDefinitionParser {
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
// 构建一个BeanDefinitionBuilder
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
String parentName = getParentName(element);
if (parentName != null) {
// 向构建者设置parent属性
builder.getRawBeanDefinition().setParentName(parentName);
}
Class<?> beanClass = getBeanClass(element);
if (beanClass != null) {
builder.getRawBeanDefinition().setBeanClass(beanClass);
}
else {
String beanClassName = getBeanClassName(element);
if (beanClassName != null) {
builder.getRawBeanDefinition().setBeanClassName(beanClassName);
}
}
builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
BeanDefinition containingBd = parserContext.getContainingBeanDefinition();
if (containingBd != null) {
// 设置Scope,同时保证内外作用域必须一致
builder.setScope(containingBd.getScope());
}
if (parserContext.isDefaultLazyInit()) {
// 设置延迟初始化
builder.setLazyInit(true);
}
doParse(element, parserContext, builder);
// 从BeanDefinitionBuilder提取出构建的对象,即BeanDefinition
return builder.getBeanDefinition();
}
}
构建者的实现很简单,Spring的实现亦如此,读者自行阅读BeanDefinitionBuilder即可。
3.工厂方法
Spring通过配置的形式,支持静态工厂方法【static factory method】和实例工厂方法【instance factory method】
静态工厂方法【static factory method】
<bean id="staticFactoryMethod" class="com.telecom.spring.designpattern.StaticFactoryMethod" factory-method="instance" >
</bean>
POJO:
public class StaticFactoryMethod {
/**
* 静态工厂方法,注意,该方法一定要是静态的
* @return
*/
public static StaticFactoryMethod instance(){
return new StaticFactoryMethod();
}
}
在< bean>中指定class,即静态工厂类,然后在facory-method中指定工厂方法
实例工厂方法[instance factory method]
<bean id="instanceFactoryMethod" class="com.telecom.spring.designpattern.InstanceFactoryMethod">
</bean>
<bean id="targetBean" factory-bean="instanceFactoryMethod" factory-method="createTargetBean">
</bean>
POJO:
public class InstanceFactoryMethod {
/**
* 实例工厂方法
* @return
*/
public TargetBean createTargetBean(){
return new TargetBean();
}
}
与通过静态工厂方法实例化类似,使用实例工厂方法实例化将从容器中调用现有bean的非静态方法来创建新bean。要使用此机制,请保留class属性为空,并在factory-bean属性中,指定当前(或父或父)容器中的bean的名称,该容器包含要调用来创建对象的实例方法。使用factory-method属性设置factory方法的名称。
4.抽象工厂
5.代理模式【proxy】
代理的工作原理类似于对象的镜像。由于它,代理对象不仅可以覆盖真实对象,还可以扩展它们的特性。代理是一个封装了真实对象的对象。
Spring中代理模式的实现栗子是:org.springframework.aop.framework.ProxyFactoryBean。这个工厂基于Spring bean构建AOP代理。ProxyFactoryBean类实现了FactoryBean接口,它定义了getObject()方法。此方法用于将所需bean的实例返回到bean工厂。getObject()方法返回的不是Bean实例的原型,而是AOP代理后的Bean实例。
<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor"/>
<!--代理模式-->
<bean id="proxyBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<bean class="com.telecom.spring.designpattern.TargetBean">
<property name="sugar" value="Piemon"/>
</bean>
</property>
<property name="interceptorNames">
<list>
<value>debugInterceptor</value>
</list>
</property>
</bean>
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("config/Bootstrap_test.xml");
TargetBean proxy = (TargetBean) context.getBean("proxyBean");
System.out.println(proxy.getSugar());
}
Spring的ProxyFacroyBean与将Spring Ioc与Spring Aop结合了起来。但是除此之外,Spring还支持Spring Ioc无关的Bean的代理,提供该特性支持的是ProxyFactory。我们可以以编码的形式,完成对某个对象的代理,就像使用JDK动态代理一样。
public static void main(String[] args) {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TargetBean("A"));
proxyFactory.addAdvice(new BeforeConstructAdvice());
TargetBean targetBean = (TargetBean) proxyFactory.getProxy();
System.out.println(targetBean.getSugar());
}
public static class BeforeConstructAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] arguments, Object target) throws Throwable {
System.out.println("action before ...");
}
}
5.策略模式【Strategy】
Spring支持对各种资源的加载,ResourceLoader负责将给定的路径地址,解析为Resource资源。
Resource是对资源的高度抽象,因此他就是策略模式中的Strategy接口。
Resource的子类则对应于具体的策略:
- ByteArrayResource:二进制数组表示的资源,二进制数组资源可以在内存中通过程序构造
- ClassPathResource:类路径下的资源,资源以相对于类路径的方式表示。
- FileSystemResource:文件系统资源,资源以文件系统路径的方式表示,如 C:\Users\admin\Desktop\xx.txt
- InputStreamResource:对应一个InputStream的资源。
- ServletContextResource:为访问Web容器上下文中的资源而设计的类,负责以相对于Web应用根目录的路径加载资源,它支持以流和URL的方式访问,在WAR解包的情况下,也可以通过File的方式访问,该类还可以直接从JAR包中访问资源。
- UrlResource:封装了java.net.URL,它使用户能够访问任何可以通过URL表示的资源,如文件系统的资源、HTTP资源、FTP资源等。
而负责选取策略的Context,则是ApplicationContext,或者说是PathMatchingResourcePatternResolver,它是ResourceLoader的实现,ApplicationContext虽然继承了DefaultResourceLoader类,但是他还是将解析的工作,委托给了PathMatchingResourcePatternResolver,因为他的功能更全面~
6.模板模式【Template】
太多地方使用了,定义骨干,将逻辑下沉。
7.观察者模式【Observer】
Spring的ApplicationEventPublisher、ApplicationEventMulticaster