Spring学习笔记

82 阅读14分钟

1. 为什么会有Spring

1.1 引言

  Spring的出现是为了解耦!在面向接口编程中,我们每次使用都要实例化一下,如下图。可以看出,每一个方法中都需要进行实例化我们需要用到的接口的实现类,这就会存在大量的实例化对象,并且他们的生命周期可能就是从方法的调用开始到方法的调用结束为止,加大了GC回收的压力!

image.png

  这时候我们可能会想到使用单例模式,以此来避免大量重复的创建对象。但是这样我们就要考虑到众多这种对象的创建,都需要改成单例模式,这样子做事非常耗时、耗力的。

  对于这个系统来说,如果都把这种面向接口的对象实现类转换为单例模式的方式的话,大概也要写十几个或者上百个这种单例模式代码,而对于一个单利模式的写法来说,往往是模板式的代码,以静态内部类的方式实现代理模式如下:

20210708105107.png 可以看出,这种方式有两个问题:

(1)业务代码与单利模式的模板代码放在一个类里,耦合性较高; (2)大量重复的单利模式的模板代码;

  从上述可以看出,使用的单利模式虽然从性能上有所提高,但是却加重了我们的开发成本。因此只会小规模的使用,例如我们操作JDBC的Utils对象等。

1.2 Spring的诞生背景

  从上面代码的演变我们看出,我是需要一个单例的对象来避免大量的创建和销毁,但是我们又要避免大量的重复无用的模板代码和代码耦合。

  于是,我们想到了“数据库连接池”,假设里面装的是接口实现类的对象,每个对象都不一样,那么不久相当于每个对象都是单例的了吗?既可以避免大量对象的创建,也可以避免出现重复性的模板代码。

  现在我们需要考虑的是:哪些对象放这个池子?通过什么样的方式放进去?放进去后怎么管理?如何获取池子中的每一个对象的生命周期是怎么样的等等...

  这时候伟大的Spring就出现了!

为什么会有Spring?

2. 什么是Spring

  Spring的核心功能是轻量级容器,帮我们管理业务对象、对象的生命周期、对象和对象之间的关系,他有两个核心组件,就是IOC(控制反转)和AOP(面向切面编程)

轻量级:所提供的服务都是允许定制的;

2.1 控制反转(IOC):

  传统的程序是在类内部主动创建依赖对象,从而导致类与类之间高耦合。

  Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而IOC容器技术,帮我们自动管理依赖的对象,不需要我们自己创建和管理依赖对象,从而实现层与层之间的解耦。重点是解耦!

2.2 面向切面编程(AOP):

  在面向对象中,我们将事物纵向抽象成一个个对象。

  而在AOP(面向切面编程)中,我们将一个个对象某些类似方面横向抽象成一个切面,对这个切面进行一些权限认证、事务管理、记录日志等公用操作处理的过程就是面向切面编程的思想。AOP方便我们将一些非核心业务逻辑抽离,从而实现核心业务和非核心业务的解耦,比如添加一个商品信息,那么核心业务就是做添加商品信息记录这个操作,非核心业务比如,事务的管理,日志,性能检测,读写分离的实现等等。

3. 理解Spring

  上面我们说了传统Java SE程序设计,我们直接在对象内部通过new进行创建对象或者getInstance等直接或者间接调用构造方法创建一个对象。

  而在Spring开发模式中,Spring容器使用了工厂模式为我们创建了所需要的对象(这个过程就是DI,DI通过setter方法在配置中注入对象,setter方法名(默认)跟bean里面的properties name对应),我们使用时不需要自己去创建,直接调用Spring为我们提供的对象即可,这就是控制反转的思想。

实例化一个java对象有三种方式:

①使用类构造器,②使用静态工厂方法,③使用实例工厂方法。

  当使用spring时我们就不需要关心通过何种方式实例化一个对象,spring通过控制反转机制自动为我们实例化一个对象。

4. 怎么使用Spring

4.1 Spring配置bean实例化有哪些方式。

  1. 构造方式实例化:XML配置使用bean构造器
  2. 静态工厂实例化:XML配置+factory类,使用静态工厂方法实例化,即我们的bean通过指定Class(我们创建的工厂类)的静态方法进行实例化,用factory-method为对应的实例化静态方法。
  3. 实例工厂实例化:有时候我们的bean可能是需要通过某个对象进行实例化的,这个时候我们可以通过factory-bean指定用来实例化该bean的对应对象,通过factory-method指定factory-bean中用来实例化该bean的方法。factory-bean必须也是属于ApplicationContext中的一个bean。

最常用的是第一种!!!

Spring 配置bean实例化有哪些方式

4.2 关于spring的几种注入方式

www.cnblogs.com/liu-ya/p/95…

5. Spring的优点

  1. 非侵入式:

    非侵入式设计,代码的污染极低。

    Spring并没有”侵入“到我们的代码里面,即不继承Spring框架给我们的类,而是通过配置完成依赖注入就可以使用。

  2. 轻量:

    spring给用户提供的服务完全有用户自己决定,spring想用什么服务自己开启使用。

    但是重量级的都是只要你用就把所有的服务都给你,不能自己定制。

  3. 依赖注入:

    DI——Dependency Injection,控制反转(IOC)最经典的实现。

    DI机制将对象之间的依赖关系交由框架处理,减低组件的耦合性。

  4. 面向切面编程:

    Aspect Oriented Programming——AOP。

    AOP技术,支持将一些通用任务,如安全、事务、日志、权限等进行集中式管理,从而提供更好的复用

    总的来说就是把应用业务逻辑和系统服务分开。

  5. 容器:

    Spring是一个容器,因为它包含并管理应用对象的生命周期。

  6. 组件化:

    Spring使用一个简单的配置组合成一个复杂的应用。在Spring中可以使用XML和Java注解组合这些对象。

  7. 事务管理:Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)。

  8. 异常处理:Spring 提供方便的API把具体技术相关的异常(比如由JDBC,Hibernate or JDO抛出的)转化为一致的unchecked 异常。

  9. MVC框架:Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品。

  10. Spring对主流的应用框架提供了集成支持,如hibernate,Struts2,JPA。

Spring 侵入式和非侵入式的解释

6. Spring IOC

  1. IOC就是控制反转,指创建对象的控制权转移给Spring框架进行管理,并由Spring根据配置文件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,也利于功能的复用。DI依赖注入,和控制反转是同一个概念的不同角度的描述,即 应用程序在运行时依赖IoC容器来动态注入对象需要的外部依赖。

  2. 最直观的表达就是,以前创建对象的主动权和时机都是由自己把控的,IOC让对象的创建不用去new了,可以由spring自动生产,使用java的反射机制,根据配置文件在运行时动态的去创建对象以及管理对象,并调用对象的方法的。

  3. Spring的IOC有三种注入方式 :构造器注入、setter方法注入、根据注解注入。

7. Spring AOP

  面向对象程序设计(Object Oriented Programming),允许开发者定义纵向的关系,但并不适用于定义横向的关系,会导致大量代码的重复,而不利于各个模块的重用。

  AOP:一般称为面向切面,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),实现公共业务的重复利用。减少系统中的重复代码,降低了模块间的耦合度,提高系统的可维护性。可用于权限认证、日志、事务处理。

  AOP实现的关键在于代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。

代理的概念:

  为某个对象提供一个代理,以控制对这个对象的访问。 代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代。 代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理。

           image.png

7.2 Spring AOP 和 AspectJ 之间的差别

AOP现有两个主要的流行框架,即Spring AOP和Spring+AspectJ

  • SpringAOP 是Spring支持的面向切面AOP 编程。
  • AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。

image.png 1、织入的时期不同

  Spring Aop采用的动态织入,而Aspectj是静态织入。静态织入:指在编译时期就织入,即:编译出来的class文件,字节码就已经被织入了。动态织入又分静动两种,静则指织入过程只在第一次调用时执行;动则指根据代码动态运行的中间状态来决定如何操作,每次调用Target的时候都执行。

2、使用对象不同

。。。。。

Spring AOP 和 AspectJ 之间的差别

7.3 静态代理和动态代理两者的区别

静态代理:

  AspectJ是静态代理,也称为编译时增强,AOP框架会在编译阶段生成AOP代理类,并将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。

静态代理类优缺点

优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性。这是代理的共有优点。

缺点:

①代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍 大时就无法胜任了。

②如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度

动态代理

  Spring AOP使用的动态代理,动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,就是说AOP框架不会去修改字节码,即不存在代理类的字节码问题。而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。

总结:

AspectJ之所以是静态的,是因为它不会自动生成动态代理类

动态代理和静态代理的区别

7.4 动态代理的两种方式

  Spring AOP中的动态代理主要有两种方式,JDK动态代理CGLIB动态代理

7.4.1 JDK动态代理

  JDK动态代理只提供接口的代理,不支持类的代理,要求被代理类实现接口。JDK动态代理的核心是InvocationHandler接口Proxy类,在获取代理对象时,使用Proxy类来动态创建目标类的代理类(即最终真正的代理类,这个类继承自Proxy并实现了我们定义的接口),当代理对象调用真实对象的方法时, InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;

7.4.2 CGLIB动态代理

  如果被代理类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

7.5 Spring AOP里面的几个名词的概念:

1、连接点(Join point):指程序运行过程中所执行的方法,在Spring AOP中,一个连接点总代表一个方法的执行。

2、切面(Aspect):被抽取出来的公共模块,可以用来会横切多个对象。Aspect切面可以看成 Pointcut切点 和 Advice通知 的结合,一 个切面可以由多个切点和通知组成。==在Spring AOP中,切面可以在类上使用 @AspectJ 注解来实现。==

3、切点(Pointcut):切点用于定义要对哪些Join point进行拦截

切点分为execution方式和annotation方式。execution方式可以用路径表达式指定对哪些方法拦截,比如指定拦 截add 、search。annotation方式可以指定==被哪些注解修饰的代码进行拦截。==

4、通知(Advice):指要在连接点(Join Point)上执行的动作,即增强的逻辑,比如权限校验和、日志记录等。通知有各种类型,包 括Around、Before、After、After returning、After throwing。

5、目标对象:包含连接点的对象,也称作被通知(Advice)的对象。 由于Spring AOP是通过动态代理实现的,所以这个对象永远是一个 代理对象。

6、织入:通过动态代理,在目标对象(Target)的方法(即连接点Join point)中执行增强逻辑(Advice)的过程

7、引入:添加额外的方法或者字段到被通知的类。Spring允许引入新的接口(以及对应的实现)到任何被代理的对象。例如,你可以使 用一个引入来使bean实现 IsModified 接口,以便简化缓存机制。

image.png

image.png

7.6 Spring通知(Advice)有哪些类型?

(1)前置通知(Before Advice):在连接点(Join point)之前执行的通知。

(2)后置通知(After Advice):当连接点退出的时候执行的通知(不论是正常返回还是异常退出)。

(3)环绕通知(Around Advice):包围一个连接点的通知,这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也可以选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。

(4)返回后通知(AfterReturning Advice):在连接点正常完成后执行的通知(如果连接点抛出异常,则不执行)

(5)抛出异常后通知(AfterThrowing advice):在方法抛出异常退出时执行的通知

image.png