Spring核心问题回顾2:Spring中用到的设计模式
Spring中用到的设计模式:
一、从ioc的角度看:
1)工厂模式(Factory Pattern)
:通过BeanFactory和ApplicationContext来创建对象。首先可以解决bean之间的依赖问题,达到松耦合的效果;其次可以在实例化bean过程中,进行一些额外的处理;
2)单例模式(Singleton Pattern)
:在Spring中的Bean默认的作用域就是singleton单例的。单例模式的好处在于对一些重量级的对象,省略了重复创建对象花费的时间,减少了系统的开销;其次是使用单例可以减少new操作的次数,减少了GC线程回收内存的压力。
3)模板模式(Template Pattern)
:spring框架中调用refresh方法完成上下文的启动,即模板方法。模版模式的特点:从头至尾,各个属性的位置都是固定的,是一个大而全的东西,固定了流程,按照模版来就行。
4)策略模式(Strategy Pattern)
:spring在加载bean定义信息的时候,来源可能是xml,可能是注解,也可能是properties等等。而spring都是通过BeanDefinitionReader这个接口来解析的。这种不用考虑具体来源,就可以完成即系的方式就是策略模式。
5)装饰器模式(Decorator Pattern)
:Spring中含有Wrapper和含有Decorator的类都用到了装饰器模式,都是动态地给一个对象添加一些额外的属性或者功能。比如Spring中配置DataSource时 ,DataSource可以是不同的数据库和数据源.为了在少修改原有类的代码下动态切换不同的数据源,这时就用到了装饰器模式。
6)观察者模式(Observer Pattern)
:Spring 事件驱动模型就是观察者模式很经典的一个应用。
二:从aop的角度看:
7)代理模式(Proxy Pattern)
:Spring AOP实现的关键在于动态代理,通过DefaultAopProxyFactory的createAopProxy()方法创建动态代理类。
8)适配器模式(Adapter Pattern)与责任链模式(Chain of Responsibility Pattern)
:在SpringAOP中有一个很重要的功能就是使用的 Advice(通知) 来增强被代理类的功能,Spring需要将每个 Advice 都封装成对应的拦截器类型返回给容器,所以需要使用适配器模式对 Advice 进行转换。转为拦截类之后,就添加到拦截器集合中。添加到拦截器集合之后,就用到了责任链模式:递归调用ReflectiveMethodInvocation类的JdkDynamicAopProxy的invoke()方法。
1、工厂模式(Factory Pattern)
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
Spring使用工厂模式,通过BeanFactory和ApplicationContext来创建对象。
BeanFactory是Spring最底层的接口,是IoC的核心,定义了IoC的基本功能,包含了各种Bean的定义、加载、实例化,依赖注入和生命周期管理。BeanFactroy采用的是延迟加载形式来注入Bean的,只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。
设计意义:
松耦合
:可以将原来硬编码的依赖,通过Spring的beanFactory注入依赖,也就是说原来只有依赖方和被依赖方,现在我们引入了第三方——spring的beanFactory,由它来解决bean之间的依赖问题,达到了松耦合的效果.
bean的额外处理
:通过Spring接口的暴露,在实例化bean的阶段,我们可以进行一些额外的处理,这些额外的处理只需要让bean实现对应的接口即可,那么spring就会在bean的生命周期调用我们实现的接口来处理该bean。
2、单例模式(Singleton Pattern)
单例模式保证一个类仅有一个实例,并提供一个访问它的全局访问点。
在Spring中的Bean默认的作用域就是singleton单例的。单例模式的好处在于对一些重量级的对象,省略了重复创建对象花费的时间,减少了系统的开销,第二点是使用单例可以减少new操作的次数,减少了GC线程回收内存的压力
。
对于单例bean的创建方式,主要看DefaultSingletonBeanRegistry 的 getSingleton() 方法:
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
/** 保存单例Objects的缓存集合ConcurrentHashMap,key:beanName --> value:bean实例 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
//检查缓存中是否有实例,如果缓存中有实例,直接返回
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
//省略...
try {
//通过singletonFactory获取单例
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
//省略...
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
//返回实例
return singletonObject;
}
}
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
3、模板模式(Template Pattern)
模板模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
模版模式的特点:从头至尾,各个属性的位置都是固定的,是一个大而全的东西,固定了流程
,按照模版来就行。
策略模式和模板模式有一个最重要的区别,即模板模式一般只针对一套算法
,注重对同一个算法的不同细节进行抽象提供不同的实现。而策略模式注重多套算法多套实现
,在算法中间不应该有交集,因此算法和算法只间一般不会有冗余代码!
比如spring框架中调用refresh方法完成上下文的启动,即模板方法。
又比如refresh方法中的onRefresh方法,它也是一个模板方法。没有任何实现,留给子类进行扩展。
4、策略模式(Strategy Pattern)
在策略模式中,一个类的行为或其算法可以在运行时更改。
比如spring在加载bean定义信息的时候,来源可能是xml,可能是注解,也可能是properties等等。而spring都是通过BeanDefinitionReader这个接口来解析的。这种不用考虑具体来源,就可以完成即系的方式就是策略模式。
5、装饰器模式(Decorator Pattern)
装饰器模式可以动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
Spring中配置DataSource时 ,DataSource可以是不同的数据库和数据源.为了在少修改原有类的代码下动态切换不同的数据源,这时就用到了装饰器模式。
Spring中含有Wrapper和含有Decorator的类都用到了装饰器模式,都是动态地给一个对象添加一些额外的属性或者功能。
6、观察者模式(Observer Pattern)
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。
Spring 事件驱动模型
就是观察者模式很经典的一个应用。
1、事件角色
在Spring事件驱动模型中,首先有事件角色ApplicationEvent,这是一个抽象类,抽象类下有四个实现类代表四种事件。
- ContextStartedEvent:ApplicationContext启动后触发的事件
- ContextStoppedEvent:ApplicationContext停止后触发的事件
- ContextRefreshedEvent:ApplicationContext初始化或刷新完成后触发的事件
- ContextClosedEvent:ApplicationContext关闭后触发的事件
2、事件发布者:
有了事件之后,需要有个发布者发布事件,发布者对应的类是ApplicationEventPublisher。
@FunctionalInterface
public interface ApplicationEventPublisher {
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
void publishEvent(Object event);
}
@FunctionalInterface表示这是一个函数式接口,函数式接口只有一个抽象方法。ApplicationContext类又继承了ApplicationEventPublisher类,所以我们可以使用ApplicationContext发布事件。
3、事件监听者:
发布事件后需要有事件的监听者,事件监听者通过实现接口ApplicationListener来定义,这是一个函数式接口,并且带有泛型,要求E参数是ApplicationEvent的子类。
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E event);
}
4、演示使用示例
首先继承抽象类ApplicationEvent定义一个事件角色PayApplicationEvent:
public class PayApplicationEvent extends ApplicationEvent {
private String message;
public PayApplicationEvent(Object source, String message) {
super(source);
this.message = message;
}
public String getMessage() {
return message;
}
}
接着定义一个PayApplicationEvent事件的监听者PayListener:
@Component
public class PayListener implements ApplicationListener<PayApplicationEvent> {
@Override
public void onApplicationEvent(PayApplicationEvent event) {
String message = event.getMessage();
System.out.println("监听到PayApplicationEvent事件,消息为:" + message);
}
}
最后我们使用ApplicationContext发布事件:
@SpringBootApplication
public class SpringmvcApplication {
public static void main(String[] args) throws Exception {
ApplicationContext applicationContext = SpringApplication.run(SpringmvcApplication.class, args);
applicationContext.publishEvent(new PayApplicationEvent(applicationContext,"成功支付100元!"));
}
}
启动之后我们可以看到控制台打印:
7、代理模式(Proxy Pattern)
Spring AOP实现的关键在于动态代理,主要有两种方式,JDK动态代理和CGLIB动态代理。
我们看DefaultAopProxyFactory的createAopProxy()方法,Spring通过此方法创建动态代理类:
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
}
8、适配器模式(Adapter Pattern)与责任链模式(Chain of Responsibility Pattern)
适配器模式:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
责任链模式:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
在SpringAOP中有一个很重要的功能就是使用的 Advice(通知) 来增强被代理类的功能,Advice主要有MethodBeforeAdvice、AfterReturningAdvice、ThrowsAdvice这几种。每个Advice都有对应的拦截器,如下所示:
Spring需要将每个 Advice 都封装成对应的拦截器类型返回给容器,所以需要使用适配器模式对 Advice 进行转换
。对应的就有三个适配器,我们看个类图:
那适配器在Spring中是怎么把通知类转换为拦截类的呢?
适配器的接口定义了两个方法:分别是supportsAdvice()和getInterceptor():
public interface AdvisorAdapter {
//判断通知类是否匹配
boolean supportsAdvice(Advice advice);
//传入通知类,返回对应的拦截类
MethodInterceptor getInterceptor(Advisor advisor);
}
可以看出转换的方法就是getInterceptor(),通过supportsAdvice()进行判断。比如前置通知的适配器的实现类MethodBeforeAdviceAdapter:
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
//判断是否匹配MethodBeforeAdvice通知类
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof MethodBeforeAdvice);
}
//传入MethodBeforeAdvice,转换为MethodBeforeAdviceInterceptor拦截类
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
}
在上面的getInterceptor()方法中,传入通知类advice作为参数,调用了对应的拦截类的构造器(MethodBeforeAdviceInterceptor)创建对应的拦截器返回。
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
//成员变量,通知类
private MethodBeforeAdvice advice;
//定义了有参构造器,外部通过有参构造器创建MethodBeforeAdviceInterceptor
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
//当调用拦截器的invoke方法时,就调用通知类的before()方法,实现前置通知
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
//调用通知类的before()方法,实现前置通知
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
return mi.proceed();
}
}
那么在哪里初始化这些适配器呢?可以看下DefaultAdvisorAdapterRegistry():
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
private final List<AdvisorAdapter> adapters = new ArrayList<>(3);
public DefaultAdvisorAdapterRegistry() {
//初始化适配器,添加到adapters集合,也就是注册
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
@Override
public void registerAdvisorAdapter(AdvisorAdapter adapter) {
this.adapters.add(adapter);
}
//获取所有的拦截器
@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<>(3);
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
//遍历adapters集合
for (AdvisorAdapter adapter : this.adapters) {
//调用supportsAdvice()方法,判断入参的advisor是否有匹配的适配器
if (adapter.supportsAdvice(advice)) {
//如果匹配,则调用getInterceptor()转换成对应的拦截器,添加到interceptors集合中
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
//返回拦截器集合
return interceptors.toArray(new MethodInterceptor[0]);
}
}
适配器模式在这里就是把通知类转为拦截类,转为拦截类之后,就添加到拦截器集合中。添加到拦截器集合之后,就用到了责任链模式
,在ReflectiveMethodInvocation类被调用,我们看JDK动态代理JdkDynamicAopProxy的invoke()方法:
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
//这里就是获取拦截器集合,最后就会调用到上文说的getInterceptors()
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
//省略...
}else {
//创建一个MethodInvocation
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
//调用proceed()方法,底层会通过指针遍历拦截器集合,然后实现前置通知等功能
retVal = invocation.proceed();
}
//省略...
}
最后就在ReflectiveMethodInvocation里调用proceed()方法,proceed()方法是一个递归的方法,通过指针控制递归的结束。这是很典型的责任链模式
。
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
protected final List<?> interceptorsAndDynamicMethodMatchers;
//指针
private int currentInterceptorIndex = -1;
protected ReflectiveMethodInvocation(Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments, @Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
//省略...
//拦截器的集合
this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
}
@Override
@Nullable
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
//递归结束
return invokeJoinpoint();
}
//获取拦截器,并且当前的指针+1
Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
//匹配失败,跳过,递归下一个
return proceed();
}
}
else {
//匹配拦截器,强转为拦截器,然后执行invoke()方法,然后就会调用拦截器里的成员变量的before(),afterReturning()等等,实现前置通知,后置通知,异常通知
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
}
关于适配器模式和责任链模式这一块,如果完全没看过spring的aop的过程,这一块看的肯定很懵,建议网上先看下相关视频,或者自己debug以下,会清楚很多。