一、浅谈控制反转(IOC)与依赖注入(DI)

IOC(Inversion of Control)是Spring中一个非常重要的概念,它不是什么技术,而是一种解耦的设计思想。它主要的额目的是借助于第三方(Spring中的IOC容器)实现具有依赖关系的的对象之间的解耦(IOC容易管理对象,你只管使用即可),从而降低代码之间的耦合度。它不是一个模式,而是一种设计原则,但以下模式(但不限于)实现了IOC的设计原则。

补充:对控制反转的理解:

举个例子“对象A依赖了对象B,当对象A需要使用对象B的时候必须自己去创建。但是当系统引入了IOC容器后,对象A和对象B之前就失去了直接的联系。这个时候,当对象A需要使用对象B的时候,我们可以指定IOC容器去创建一个对象B注入到对象A中”。对象A获得对象B的过程,由主动行为变成了被动行为,控制权实现了反转,这就是控制反转名字的由来。DI(Dependency Inject)依赖注入实现控制反转的的一种实现方式,依赖注入就是将实例变量传入到一个对象中去。

二、Spring框架中的设计模式

1)工厂设计模式(简单工厂和工厂方法)

Spring使用工厂模式可以通过BeanFactory或ApplicationContext创建bean对象。

两者对比:

  • BeanFactory :延迟注入(使用到某个 bean 的时候才会注入),相比于BeanFactory来说会占用更少的内存,程序启动速度更快。
  • ApplicationContext :容器启动的时候,不管你用没用到,一次性创建所有 bean 。BeanFactory 仅提供了最基本的依赖注入支持,ApplicationContext 扩展了 BeanFactory ,除了有BeanFactory的功能还有额外更多功能,所以一般开发人员使用ApplicationContext会更多。

2)单例设计模式

Spring中bean的默认作用域就是singleton。除了singleton作用域,Spring bean还有下面几种作用域:

  • prototype : 每次请求都会创建一个新的 bean 实例。
  • request : 每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。
  • session : 每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效。
  • global-session: 全局session作用域,仅仅在基于portlet的web应用中才有意义,Spring5已经没有了。Portlet是能够生成语义代码(例如:HTML)片段的小型Java Web插件。它们基于portlet容器,可以像servlet一样处理HTTP请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。

Spring实现单例的方式:

xml格式:<bean id="userService" class="top.snailclimb.UserService" scope="singleton"/>
注解:@Scope(value = "singleton")

Spring通过ConcurrentHashMap实现单例注册表的特殊方式实现单例模式。Spring实现单例的核心代码如下:

// 通过 ConcurrentHashMap(线程安全) 实现单例注册表
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);
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) {  //...省略了很多代码  try {  singletonObject = singletonFactory.getObject();  }  //...省略了很多代码  // 如果实例对象在不存在,我们注册到单例注册表中。  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));  }  }
} 

3)代理设计模式

Spring AOP就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用JDK Proxy去进行代理了,这时候Spring AOP会使用Cglib,这时候Spring AOP会使用Cglib生成一个被代理对象的子类来作为代理。如下图所示:

当然你也可以使用AspectJ,Spring AOP已经继承了AspectJ,AspectJ应该算的上是java生态系统中最完整的AOP框架了。

Spring AOP和AspectJ AOP有什么区别?

Spring AOP属于运行时增强,而AspectJ是编译时增强。Spring AOP基于代理,而AspectJ基于字节码操作。

Spring AOP已经集成了AspectJ,AsectJ应该算的上是Java生态系统中最完整的AOP框架了。AspectJ相比于Spring AOP功能更加强大,但是Spring AOP相对来说更简单,如果我们的切面比较少,那么两者的性能差异不大。但是当切面太多的话,最好选择AspectJ,它比Spring AOP快很多。

4)模板方法设计模式

模板方法模式是一种行为设计模式,它定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变一个算法的结构即可重定义该算法的默写特定步骤的实现方式。例如:

public abstract class Template {  //这是我们的模板方法  public final void TemplateMethod(){  PrimitiveOperation1();    PrimitiveOperation2();  PrimitiveOperation3();  }  protected void  PrimitiveOperation1(){  //当前类实现  }  //被子类实现的方法  protected abstract void PrimitiveOperation2();  protected abstract void PrimitiveOperation3();
}
public class TemplateImpl extends Template {  @Override  public void PrimitiveOperation2() {  //当前类实现  }  @Override  public void PrimitiveOperation3() {  //当前类实现  }
} 

Spring中jdbcTemplate、hibernateTemplate等以Template结尾的对数据库操作的类,它们就使用到模板模式。一般情况下,我们都是使用继承的方式来实现模板模式,但是Spring并没有使用这种方式,而是使用Callback模式与模板方法配合,既达到了代码复用的效果,同时增加了灵活性。

5)观察者设计模式

观察者设计模式是一种对象行为模式。它表示的是一种对象与对象之间具有依赖关系,当一个对象发生改变时,这个对象锁依赖的对象也会做出反应。Spring事件驱动模型就是观察者模式很经典的应用。

事件角色:ApplicationEvent(org.springframework.context包下)充当事件的角色,这是一个抽象类。

事件监听者角色:ApplicationListener充当了事件监听者的角色,它是一个接口,里面只定义了一个onApplicationEvent()方法来处理ApplicationEvent。

事件发布者角色:ApplicationEventPublisher充当了事件的发布者,它也是个接口。

Spring事件流程总结:

  1. 定义一个事件: 实现一个继承自 ApplicationEvent,并且写相应的构造函数;
  2. 定义一个事件监听者:实现 ApplicationListener 接口,重写 onApplicationEvent() 方法;
  3. 使用事件发布者发布消息: 可以通过 ApplicationEventPublisher 的 publishEvent() 方法发布消息。

例如:

// 定义一个事件,继承自ApplicationEvent并且写相应的构造函数
public class DemoEvent extends ApplicationEvent{  private static final long serialVersionUID = 1L;  private String message;  public DemoEvent(Object source,String message){  super(source);  this.message = message;  }  public String getMessage() {  return message;  }
// 定义一个事件监听者,实现ApplicationListener接口,重写 onApplicationEvent() 方法;
@Component
public class DemoListener implements ApplicationListener<DemoEvent>{  //使用onApplicationEvent接收消息  @Override  public void onApplicationEvent(DemoEvent event) {  String msg = event.getMessage();  System.out.println("接收到的信息是:"+msg);  }
}
// 发布事件,可以通过ApplicationEventPublisher  的 publishEvent() 方法发布消息。
@Component
public class DemoPublisher {  @Autowired  ApplicationContext applicationContext;  public void publish(String message){  //发布事件  applicationContext.publishEvent(new DemoEvent(this, message));  }
} 

6)适配器设计模式

适配器设计模式将一个接口转换成客户希望的另一个接口,适配器模式使得接口不兼容的那些类可以一起工作,其别名为包装器。在Spring MVC中,DispatcherServlet根据请求信息调用HandlerMapping,解析请求对应的Handler,解析到对应的Handler(也就是我们常说的Controller控制器)后,开始由HandlerAdapter适配器处理。为什么要在Spring MVC中使用适配器模式?Spring MVC中的Controller种类众多不同类型的Controller通过不同的方法来对请求进行处理,有利于代码的维护拓展。

7)装饰者设计模式

装饰者设计模式可以动态地给对象增加些额外的属性或行为。相比于使用继承,装饰者模式更加灵活。Spring 中配置DataSource的时候,DataSource可能是不同的数据库和数据源。我们能否根据客户的需求在少修改原有类的代码下切换不同的数据源?这个时候据需要用到装饰者模式。

8)策略设计模式

Spring 框架的资源访问接口就是基于策略设计模式实现的。该接口提供了更强的资源访问能力,Spring框架本身大量使用了Resource接口来访问底层资源。Resource接口本身没有提供访问任何底层资源的实现逻辑,针对不同的额底层资源,Spring将会提供不同的Resource实现类,不同的实现类负责不同的资源访问类型。

Spring 为 Resource 接口提供了如下实现类: 
UrlResource:访问网络资源的实现类。
ClassPathResource:访问类加载路径里资源的实现类。
FileSystemResource:访问文件系统里资源的实现类。
ServletContextResource:访问相对于 ServletContext 路径里的资源的实现类.
InputStreamResource:访问输入流资源的实现类。
ByteArrayResource:访问字节数组资源的实现类。 
这些 Resource 实现类,针对不同的的底层资源,提供了相应的资源访问逻辑,并提供便捷的包装,以利于客户端程序的资源访问。
参考文档:

https://blog.csdn.net/caoxiaohong1005/article/details/80039656

http://developer.51cto.com/art/201905/597181.htm

Spring框架中常用的设计模式详解相关推荐

  1. Spring框架中 自动装配的详解 属性值的详解

    手动装配实现属性注入 <bean id="studentDao" class="com.xz.dao.impl.StudentDaoImpl">&l ...

  2. Javascript常用的设计模式详解

    Javascript常用的设计模式详解 阅读目录 一:理解工厂模式 二:理解单体模式 三:理解模块模式 四:理解代理模式 五:理解职责链模式 六:命令模式的理解: 七:模板方法模式 八:理解javas ...

  3. iOS中MVC等设计模式详解

    iOS中MVC等设计模式详解 在iOS编程,利用设计模式可以大大提高你的开发效率,虽然在编写代码之初你需要花费较大时间把各种业务逻辑封装起来.(事实证明这是值得的!) 模型-视图-控制器(MVC)设计 ...

  4. Spring AOP中定义切点PointCut详解

    1.AOP是什么? 软件工程有一个基本原则叫做"关注点分离"(Concern Separation),通俗的理解就是不同的问题交给不同的部分去解决,每部分专注于解决自己的问题.这年 ...

  5. 计算机中常用软件列表,详解win10中常用软件列表不要在任务栏显示的方法

    我们在win10系统的使用中,在win10的界面中我们经常使用软件在电脑任务栏中会在电脑中显示,那很多的小伙伴在电脑中是不想要显示的遇到这个问题我们怎么取消这个常用的软件在任务栏一直显示的情况呢,今天 ...

  6. angular4 php,Angular4中常用管道实例详解

    通常我们需要使用管道实现对数据的格式化,Angular4中的管道和之前有了一些变化.本文主要介绍Angular4中常用管道,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧, ...

  7. python orm框架sqlalchemy_python orm 框架中sqlalchemy用法实例详解

    本文实例讲述了python orm 框架中sqlalchemy用法.分享给大家供大家参考,具体如下: 一.ORM简介 1. ORM(Object-Relational Mapping,对象关系映射): ...

  8. Spring配置文件中关于约束配置详解

    一.Spring配置文件常见的配置头 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns= ...

  9. Spring AOP中@Pointcut切入点表达式详解

    目录 一.瞅一眼标准的AspectJ Aop的pointcut的表达式 二.SpringAop的十一种AOP表达式 三.演示使用 1.execution: 2.within: 3.this: 4.ta ...

最新文章

  1. Fragment使用小技巧
  2. android 线程信号量,iOS开发 多线程的高级应用-信号量semaphore
  3. java集合框架图(一)
  4. java上传+限制单文件,VereMVC 之 单文件上传
  5. 如何看你的信息有没有泄露
  6. 深入理解C++对象模型-对象的内存布局,vptr,vtable
  7. 【渝粤题库】广东开放大学 秘书理论与实务 形成性考核
  8. linux堆上的内存可执行吗,pwn的艺术浅谈(二):linux堆相关
  9. adb命令检测apk启动时间、内存、CPU使用情况、流量、电池电量等——常用的adb命令...
  10. 王道考研 计算机网络6 OSI参考模型和各层作用
  11. 【codeforces 507E】Breaking Good
  12. java semaphore 原理_Java并发编程原理与实战二十八:信号量Semaphore
  13. 软件工程专业学习路线
  14. 假期无聊 就来试试用Python做一个智能识别 包教会哦 多图预警:配置Pyqt5超详细解说(designer.exe和pyuic.exe)以及项目:Python实现百度智能识别,识别各种实物
  15. 系统架构设计笔记(80)—— .NET
  16. Codeforces Round #459 (Div. 1) B. MADMAX(dp+博弈)
  17. matlab产生泊松分布
  18. 学生党白嫖服务器-不会吧不会吧,你还在买学生机吗?
  19. 如何成为一名IC验证工程师——IC修真院直播
  20. MyBatis:万能Map和模糊查询(狂神)

热门文章

  1. idea+spring boot把本地jar打包war(阿里短信服务相关)
  2. OpenFlow1.3交换机
  3. python有 5 个人坐在一起,问第五个人多少岁?他说比第 4 个人大 2 岁。问第 4 个人岁数,他说比第 3 个人大 2 岁。问第三个人,又说比第 2 人大两岁。问第 2 个人,说比第一个人大两
  4. Linux系统中的文件类型(Linux应用编程篇)
  5. decode函数用法解析
  6. 运营实操|如何利用微信后台数据优化微信运营
  7. 影响神经网络训练速度的因素使得神经网络训练速度加快的方法
  8. 不同的神经网络训练函数training function的比较
  9. [转载]空姐飞行日记 - 好爱老婆的德国乘务长
  10. js获取classname值_用原生JS获取CLASS对象(很简单实用)