1-25续
四、单例设计模式(Singleton Pattern)
4.1 介绍
单例模式是一种创建型模式,单例模式提供一个创建对象的接口,但是多次调用该接口返回的是同一个实例的引用,目的是为了保证只有一个实例,并且提供一个访问这个实例的统一接口。
4.2 Spring中单例bean的创建
Spring中默认配置的bean的scope为singleton,也就是单例作用域。那么看看它是如何做到的。
在AbstractBeanFactory类里面的doGetBean方法:
protected Object doGetBean( final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { final String beanName = transformedBeanName(name); Object bean = null; // 解决set循环依赖 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { ... } else { ... // 创建单件bean. if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, new ObjectFactory() { public Object getObject() throws BeansException { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { ... throw ex; } } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } //创建原型bean else if (mbd.isPrototype()) { ... } //创建request作用域bean else { ... } } ... return bean;}
getSingleton代码:
public Object getSingleton(String beanName, ObjectFactory singletonFactory) { Assert.notNull(beanName, "'beanName' must not be null"); synchronized (this.singletonObjects) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { ... beforeSingletonCreation(beanName); ... try { singletonObject = singletonFactory.getObject(); } catch (BeanCreationException ex) { ... } finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } afterSingletonCreation(beanName); } addSingleton(beanName, singletonObject); } return (singletonObject != NULL_OBJECT ? singletonObject : null); }}protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT)); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); }}private final Map singletonObjects = CollectionFactory.createConcurrentMapIfPossible(16);
可知Spring内部四通过一个ConcurrentMap来管理单件bean的。获取bean时候会先看看singletonObjects中是否有,有则直接返回,没有则创建后放入。
看个时序图:
Spring的bean工厂管理的单例模式管理的是多个bean实例的单例,是工厂模式管理所有的bean,而每个bean的创建又使用了单例模式。
4.4 使用场景
同一个jvm应用的不同模块需要使用同一个对象实例进行信息共享。
需要同一个实例来生成全局统一的序列号
五、原型设计模式(Prototype Pattern)
5.1 介绍
相比单例设计模式,原型模式是每次创建一个对象,下面看下spring是如何使用原型模式的
5.2 Spring中原型bean的创建
创建原型bean需要在xml特别说明:
protected T doGetBean( final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { final String beanName = transformedBeanName(name); Object bean; // Eagerly check singleton cache for manually registered singletons. Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { ... } else { ... try { ... // Create bean instance. if (mbd.isSingleton()) { ... } //创建原型bean else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { ... } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; } }... return (T) bean;}
createBean函数里面则是根据bean定义创建新bean,感兴趣的可以看看。
5.3 使用场景
当有业务场景使用某个bean时候需要使用自己的一个拷贝的时候使用。
特别推荐一个Java架构交流学习群:688583154
1、具有1-5工作经验的,面对目前流行的技术不知从何下手,需要突破技术瓶颈的可以加群。
2、在公司待久了,过得很安逸,但跳槽时面试碰壁。需要在短时间内进修、跳槽拿高薪的可以加群。
3、如果没有工作经验,但基础非常扎实,对java工作机制,常用设计思想,常用java开发框架掌握熟练的,可以加群。
4、觉得自己很牛B,一般需求都能搞定。但是所学的知识点没有系统化,很难在技术领域继续突破的可以加群。
5.阿里Java架构师,分享知识,多年工作经验的梳理和总结,带着大家全面、科学地建立自己的技术体系和技术认知
六、 策略模式(Strategy Pattern)
6.1 介绍
策略模式属于行为性模式,它定义一系列的算法对象,使用时候可以使它们相互替换。
6.2 Spring中bean实例化策略
首先看下类图:
从图知道:接口InstantiationStrategy是实例化策略接口类,它定义了三个实例化接口,然后SimpleInstantiationStrategy实现了该策略,它主要做一些简单的根据构造函数实例号bean的工作,然后CglibSubclassingInstantiationStrategy又继承了SimpleInstantiationStrategy新增了方法注入方式根据cglib生成代理类实例化方法。
在AbstractAutowireCapableBeanFactory中管理了该策略的一个对象,默认是CglibSubclassingInstantiationStrategy策略,运行时候可以通过setInstantiationStrategy改变实例化策略,如果你自己写个个策略的话。
6.3 Spring中Aop代理策略
首先看AopProxyFactory接口类提供了createAopProxy接口,这个是策略模式的接口方法。然后DefaultAopProxyFactory实现了该接口作为策略的实现者。然后ProxyCreatorSupport里面引用了AopProxyFactory,并且提供了get,set方法用来运行时改变策略,这里Spring只实现了DefaultAopProxyFactory这一个策略,如果需要自己也可以写个。
DefaultAopProxyFactory里面的createAopProxy的逻辑如下,可以在运行时根据参数决定用Cglib策略还是JDK动态代理策略生成代理类:
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { //如果XML打开了优化开关,或者设置为了代理目标类,或者目前类没有接口 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."); } //如果有接口,或者通过Proxy.newProxyInstance生成的,则使用jdk动态代理 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } //使用cglib return new ObjenesisCglibAopProxy(config); } else { //使用jdk动态代理 return new JdkDynamicAopProxy(config); } }
另外AopProxy也是一个策略接口类,具体实现的策略为JdkDynamicAopProxy,CglibAopProxy,ObjenesisCglibAopProxy
6.4 Tomcat中Digester解析server.xml
tomcat中的Digester是为了解析server.xml的,其中每个元素都有一个解析规则就是Rule ,类图如下:
DigestER一开始先指定不同的解析策略(Rule),然后在具体解析Server.xml时候根据节点不同使用不同解析策略来解析节点。
如图在解析每个节点时候会先找到该节点对应的解析策略,然后循环去调用所有解析策略的方法去处理
6.5 使用场景
运行时根据条件的不同使用不同的策略处理一个事情,与责任链不同在于,责任链是一个链条,一个事情可以被责任链里面所有节点处理,而 策略模式则是只有有一个对象来处理。
七、 门面模式(Facade Pattern)
7.1 介绍
门面模式是一种结构性模式,它通过新增一个门面类对外暴露系统提供的一部分功能,或者屏蔽了内部系统的复杂性,对外部仅仅暴露一个简单的接口,或者通过调用不同的服务对外提供统一的接口,让使用者对这些内部服务透明化。
7.2 模板引擎Velocity中门面模式使用
Velocity里面的VelocityEngine和Velocity类都是RuntimeInstance类的门面,后者提供了模板渲染的所有功能,前两者则是内部维护RuntimeInstance的实例,具体工作还是委托给RuntimeInstance来实现。
关于Veloctiy可以参考:https://www.atatech.org/articles/78435
如图 RuntimeInstance提供了Velocity引擎的所用功能,VelocityEngine内部直接引用了RuntimeInstance的一个实例,VelocityEngine对外暴露的服务都是委托RuntimeInstance实现,并且每次new一个VelocityEngine内部都会有RuntimeInstance的一个实例被创建。而Velocity类调用了单例模式类RuntimeSingleton里面的方法,RuntimeSingleton又是RuntimeInstance的一个单例模式。
7.3 使用场景
当需要对外屏蔽一个系统的复杂性时候可以考虑使用门面模式对外提供简单可读性高的接口类
当需要对外部暴露系统一部分权限的接口时候可以考虑使用门面模式减少系统权限。
当系统需要调用不同服务汇总后在对外提供服务时候可以考虑使用门面模式对外屏蔽细节,之暴露一个接口。
八、装饰器模式(Decorator Pattern)
8.1 介绍
装饰器模式是一种结构性模式,它作用是对对象已有功能进行增强,但是不改变原有对象结构。这避免了通过继承方式进行功能扩充导致的类体系臃肿。
8.2 Spring中BeanDefinitionDecorator
先看下类图:
如图ScopedProxyBeanDefinitionDecorator实现了decorate方法用来对scope作用域为request的bean定义进行包装。
具体时序图为:
class ScopedProxyBeanDefinitionDecorator implements BeanDefinitionDecorator { private static final String PROXY_TARGET_CLASS = "proxy-target-class"; @Override public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) { boolean proxyTargetClass = true; if (node instanceof Element) { Element ele = (Element) node; if (ele.hasAttribute(PROXY_TARGET_CLASS)) { proxyTargetClass = Boolean.valueOf(ele.getAttribute(PROXY_TARGET_CLASS)); } } // 创建scoped的代理类,并注册到容器 BeanDefinitionHolder holder = ScopedProxyUtils.createScopedProxy(definition, parserContext.getRegistry(), proxyTargetClass); String targetBeanName = ScopedProxyUtils.getTargetBeanName(definition.getBeanName()); parserContext.getReaderContext().fireComponentRegistered( new BeanComponentDefinition(definition.getBeanDefinition(), targetBeanName)); return holder; }}
关于ScopedProxyBeanDefinitionDecorator干啥用的那:
其实就是处理
的,具体作用是包装lavaPvgInfo的bean定义为ScopedProxyFactoryBean,作用是实现request作用域bean.
8.3 commons-collections包中ListUtils
如图
ListUtils中的四个方法分别依赖list的四种装饰器类对List功能进行扩充和限制。
其中FixedSizeList类通过禁止add/remove操作保证list的大小固定,但是可以修改元素内容
其中UnmodifiableList类通过禁用add,clear,remove,set,保证list的内容不被修改
其中SynchronizedList类通过使用Lock 来保证add,set,get,remove等的同步安全
其中LazyList类则当调用get方法发现list里面不存在对象时候,自动使用factory创建对象.
8.4 使用场景
在不改变原有类结构基础上,新增或者限制或者改造功能时候。如果你在学习Java的过程中或者在工作中遇到什么问题都可以来群里提问,阿里Java高级大牛直播讲解知识点,分享知识,多年工作经验的梳理和总结,带着大家全面、科学地建立自己的技术体系和技术认知!JAVA学习交流QQ群:288351179可以加群找我要课堂链接 注意:是免费的 没有开发经验误入哦! 非喜勿入
网友评论