Spring系列(2):Spring框架

1、Spring定义

Spring是一个开放源代码的设计层面框架,它解决的是业务逻辑层和其余各层的松耦合问题,所以它将面向接口的编程思想贯穿整个系统应用。css

Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson建立。简单来讲,Spring是一个分层的JavaSE/EE full-stack(一栈式) 轻量级开源框架。html

Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架。java

目的:解决企业应用开发的复杂性
功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能
范围:任何Java应用

优势:
    1.低侵入式设计,代码污染极低,【Spring设计为非侵入式的,意味着你的逻辑代码不依赖与框架自己。】
    2.独立于各类应用服务器,基于Spring框架的应用,能够真正实现Write Once,Run Anywhere的承诺
    3.Spring的DI机制下降了业务对象替换的复杂性,提升了组件之间的解耦【方便解耦,简化开发】
    4.Spring的AOP支持容许将一些通用任务如安全、事务、日志等进行集中式管理,从而提供了更好的复用【AOP编程的支持,声明式事务的支持】
    5.Spring的ORM和DAO提供了与第三方持久层框架的良好整合,并简化了底层的数据库访问
    6.Spring并不强制应用彻底依赖于Spring,开发者可自由选用Spring框架的部分或所有
    7.方便程序的测试,Spring对Junit4支持,能够经过注解方便的测试Spring程序。
    8.方便集成各类优秀框架。
  • 不使用事务APIs写代码就让一个方法有事务处理功能
  • 不使用remote APIs就可让本地方法访问远程程序
  • 不使用JMX APIs就可让一个本地方法管理操做
  • 不使用JMS APIs就可让本地代码处理消息
特色:
  • Core technologies: dependency injection, events, resources, i18n, validation, data binding, type conversion, SpEL, AOP.
  • Testing: mock objects, TestContext framework, Spring MVC Test, WebTestClient.
  • Data Access: transactions, DAO support, JDBC, ORM, Marshalling XML.
  • Spring MVC and Spring WebFlux web frameworks.
  • Integration: remoting, JMS, JCA, JMX, email, tasks, scheduling, cache.
  • Languages: Kotlin, Groovy, dynamic languages.

 

 排疑react

  JMX(Java Management Extensions,即Java管理扩展)是一个为应用程序、设备、系统等植入管理功能的框架。JMX能够跨越一系列异构操做系统平台、系统体系结构和网络传输协议,灵活的开发无缝集成的系统、网络和服务管理应用。git

  JMS(Java Message Service,即Java消息服务)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通讯。Java消息服务是一个与具体平台无关的API。github

  JCA (J2EE 链接器架构,Java Connector Architecture)是对J2EE标准集的重要补充。由于它注重的是将Java程序链接到非Java程序和软件包中间件的开发。链接器特指基于Java链接器架构的源适配器web

2、Spring框架特色

   Spring是一个开源框架,它由Rod Johnson建立。它是为了解决企业应用开发的复杂性而建立的。Spring使用基本的JavaBean来完成之前只可能由EJB完成的事情。然而,Spring的用途不只限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用均可以从Spring中受益。
   Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
   轻量——从 大小与开销两方面而言Spring都是轻量的。完整的Spring框架能够在一个大小只有1MB多的JAR文件里发布。而且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。
   控制反转——Spring经过一种称做控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会经过被动的方式传递进来,而不是这个对象本身建立或者查找依赖对象。你能够认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。 【工厂模式】
   面向切面——Spring提供了面向切面编程的丰富支持,容许经过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该作的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。 【动态代理】
   容器——Spring 包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你能够配置你的每一个bean如何被建立——基于一个可配置原型(prototype),你的bean能够建立一个单独的实例或者每次须要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不该该被混同于传统的重量级的EJB容器,它们常常是庞大与笨重的,难以使用。
   框架——Spring能够将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了不少基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。    
   MVC——Spring的做用是整合,但不只仅限于整合,Spring 框架能够被看作是一个企业解决方案级别的框架。客户端发送请求,服务器控制器(由DispatcherServlet实现的)完成请求的转发,控制器调用一个用于映射的类HandlerMapping,该类用于将请求映射到对应的处理器来处理请求。HandlerMapping 将请求映射到对应的处理器Controller(至关于Action)在Spring 当中若是写一些处理器组件,通常实现Controller 接口,在Controller 中就能够调用一些Service 或DAO 来进行数据操做 ModelAndView 用于存放从DAO 中取出的数据,还能够存放响应视图的一些数据。 若是想将处理结果返回给用户,那么在Spring 框架中还提供一个视图组件ViewResolver,该组件根据Controller 返回的标示,找到对应的视图,将响应response 返回给用户。
  全部Spring的这些特征使你可以编写更干净、更可管理、而且更易于测试的代码。它们也为Spring中的各类模块提供了基础支持。
 

3、Spring框架

4.x以前spring

 

Spring 框架是一个分层架构,由 7 个定义良好的模块组成。

Spring 模块构建在核心容器之上,核心容器定义了建立、配置和管理 bean 的方式,组成Spring框架的每一个模块(或组件)均可以单独存在,或者与其余一个或多个模块联合实现。每一个模块的功能以下:
    1、Spring Core:核心容器提供 Spring 框架的基本功能(Spring Core)。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转(IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。它的BeanFactory消除了应用对Singleton和Factory的依赖。 2、Spring Context:Spring 上下文是一个配置文件,向 Spring框架提供上下文信息。Spring 上下文包括企业服务,例如JNDI、EJB、电子邮件、国际化、校验和调度功能。 3、Spring AOP:经过配置管理特性,Spring AOP 模块直接将面向切面的编程功能集成到了 Spring 框架中。因此,能够很容易地使 Spring 框架管理的任何对象支持AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。经过使用 Spring AOP,不用依赖 EJB 组件,就能够将声明性事务管理集成到应用程序中。 4、Spring DAO:JDBC DAO抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不一样数据库供应商抛出的错误消息。异常层次结构简化了错误处理,而且极大地下降了须要编写的异常代码数量(例如打开和关闭链接)。Spring DAO 的面向 JDBC 的异常听从通用的 DAO 异常层次结构。 5、Spring ORM:Spring 框架插入了若干个ORM框架,从而提供了 ORM 的对象关系工具,其中包括JDO、Hibernate和iBatisSQL Map。全部这些都听从 Spring 的通用事务和 DAO 异常层次结构。 6、Spring Web 模块:Web 上下文模块创建在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。因此,Spring框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工做。提供了面向Web的综合特性,如使用Servlet监听器的Context初始化、文件上传等功能。此外它也用于同其他Web框架的集成。 七、Spring MVC 框架:MVC框架是一个全功能的构建 Web应用程序的 MVC 实现。经过策略接口,MVC框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI模型由javabean构成,存放于Map;视图是一个接口,负责显示模型;控制器表示逻辑代码,是Controller的实现。Spring框架的功能能够用在任何J2EE服务器中,大多数功能也适用于不受管理的环境。Spring 的核心要点是:支持不绑定到特定 J2EE服务的可重用业务和数据访问对象。毫无疑问,这样的对象能够在不一样J2EE 环境(Web 或EJB)、独立应用程序、测试环境之间重用。

 

下面这张图来自spring4.x的文档。目前最新的5.x版本中右面的portlet组件已经被废弃掉,同时增长了用于异步响应式处理的WebFlux组件。数据库

  依赖关系以下:express

  

 

1 核心容器
  核心容器由spring-core、spring-beans、spring-context、spring-context和spring-expression 5个模块构成。
  spring-core和spring-beans模块为框架提供最基本的功能,包括IoC和依赖注入。BeanFactory是一个工厂的实现类【工厂模式】。它能够免除用户手动建立单例类而且对象之间解耦。
  context(spring-core)模块基于spring-beans和BeanFactory两个模块,容许以框架方式访问对象,这相似于JNDI。Context模块继承了Beans模块,并支持国际化、事件传播、资源加载等。Context模块支持Java EE特性,如EJB、JMX、远程访问。spring-context接口是Contet模块的重点。spring-context-support提供将第三方库集成到Spring的功能,如缓存(EhCache,JCache)和任务调度(CommonJ,Quartz)等。
  spring-expression模块提供强有力的在运行时查询和操做对象的语言。这种语言支持获取和设置属性、方法执行、获取数组或集合中的对象、逻辑计算、命名变量,在Spring的IoC容器中得到对象。
2 AOP 和 Instrumentation
  spring-aop模块提供切面编程的实现。能够自定义方法拦截和切入点。
  spring-aspects模块提供与AspectJ的集成。
  spring-instrument模块为特定的服务器提供类加载服务。spring-instrument模块是集成了Tomcat。
3 消息
  Spring4提供了spring-messaging模块,主要类有Message,MessageChannel,MessageHandler。这个模块还包含一些映射消息到方法的注解,相似于Spring MVC基于编程模式的注解。
4 数据访问/集成
  这一层由JDBC、ORM、OXM、JMS、和事物模块组成。
  spring-jdbc模块,主要为了解决数据库繁多的问题,应用此可不须要关注使用的数据库。
  spring-tx模块提供编程式或声明式事务处理。
  spring-orm模块提供流行的对象关系映射的APIs,包含JPA和Hibernate.
  spring-oxm模块提供对Object/XML映射的支持,例如JAXB,Castor,JiBX和XStream。
  spring-jms模块(Java消息服务)包含生成和消费消息的功能。在Spring4.1之后,它集成了spring-messaging模块。
5 Web
  Web层包含spring-web、spring-webmvc和spring-websocket 3个模块。
  spring-web模块提供面向Web方法的集成特性,例如多部分文件上传、经过监听初始化IoC容器和面向Web的Context,还包含HTTP客户端和对远程的支持。
  spring-webmvc模块(也被称做Web-Servlet模块)包含Spring MVC框架。
  spring-websocket模块提供对socket的全面支持6 测试
  spring-test模块经过JUnit或者TestNG来对Spring的模块进行单元测试和集成测试。它提供一致的Spring 的ApplicationContexts 和context的缓存。它还提供mock对象让你测试你的代码。

 

4、Spring机制与实现

  http://www.javashuo.com/article/p-waxabopz-kw.html

4.1 AOP

  AOP:AOP的实现是经过代理模式,在调用对象的某个方法时,执行插入的切面逻辑。实现的方式有动态代理也叫运行时加强,好比jdk代理、CGLIB静态代理是在编译时进行织入或类加载时进行织入,好比AspectJ。关于AOP还须要了解一下对应的Aspect、pointcut、advice等注解和具体使用方式。 

Advice(通知、切面): 某个链接点所采用的处理逻辑,也就是向链接点注入的代码, AOP在特定的切入点上执行的加强处理。
  1.1 @Before: 标识一个前置加强方法,至关于BeforeAdvice的功能.
  1.2 @After: final加强,无论是抛出异常或者正常退出都会执行.
  1.3 @AfterReturning: 后置加强,似于AfterReturningAdvice, 方法正常退出时执行.
  1.4 @AfterThrowing: 异常抛出加强,至关于ThrowsAdvice.
  1.5 @Around: 环绕加强,至关于MethodInterceptor.
JointPoint(链接点):程序运行中的某个阶段点,好比方法的调用、异常的抛出等。
Pointcut(切入点): JoinPoint的集合,是程序中须要注入Advice的位置的集合,指明Advice要在什么样的条件下才能被触发,在程序中主要体现为书写切入点表达式。
Advisor(加强): 是PointCut和Advice的综合体,完整描述了一个advice将会在pointcut所定义的位置被触发。
@Aspect(切面): 一般是一个类的注解,里面能够定义切入点和通知
AOP Proxy:AOP框架建立的对象,代理就是目标对象的增强。Spring中的AOP代理可使JDK动态代理,也能够是CGLIB代理,前者基于接口,后者基于子类。

 

4.2 placeHolder动态替换

  placeHolder动态替换主要须要了解替换发生的时间,是在bean definition建立完成后,bean初始化以前,是经过实现BeanFactoryPostProcessor接口实现的。主要实现方式有PropertyPlaceholderConfigurer和PropertySourcesPlaceholderConfigurer。这两个类实现逻辑不同,spring boot使用PropertySourcesPlaceholderConfigurer实现。

  它们和应用的逻辑无关,只和当前环境、当前系统用户相关。(不能硬编码)      

  • 数据库服务器IP地址、端口、用户名;
  • 用来保存上传资料的目录。
  • 一些参数,诸如是否打开cache、加密所用的密钥名称等等。

4.3 事务

事务须要了解spring 中对事务规定的隔离类型和事务传播类型。要知道事务的隔离级别是由具体的数据库来实现的。事务的传播类型,能够重点了解最经常使用的REQUIRED和SUPPORTS类型。

1. 两大事务管理方式

  spring支持编程式事务管理声明式事务管理两种方式。

        编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。

        声明式事务管理创建在AOP之上的。其本质是对方法先后进行拦截,而后在目标方法开始以前建立或者加入一个事务,在执行完目标方法以后根据执行状况提交或者回滚事务。声明式事务最大的优势就是不须要经过编程的方式管理事务,这样就不须要在业务逻辑代码中掺琐事务管理的代码,只需在配置文件中作相关的事务规则声明(或经过基于@Transactional注解的方式),即可以将事务规则应用到业务逻辑中。

       显然声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式。声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就能够得到彻底的事务支持。和编程式事务相比,声明式事务惟一不足地方是,后者的最细粒度只能做用到方法级别,没法作到像编程式事务那样能够做用到代码块级别。可是即使有这样的需求,也存在不少变通的方法,好比,能够将须要进行事务管理的代码块独立为方法等等。

        声明式事务管理也有两种经常使用的方式,一种是基于tx和aop名字空间的xml配置文件,另外一种就是基于@Transactional注解。显然基于注解的方式更简单易用,更清爽。

 

Spring配置声明式事务:
    * 配置DataSource
    * 配置事务管理器
    * 事务的传播特性
    * 那些类那些方法使用事务

Spring配置文件中关于事务配置老是由三个组成部分,分别是DataSource、TransactionManager和代理机制这三部分,不管哪一种配置方式,通常变化的只是代理机制这部分。

    DataSource、TransactionManager这两部分只是会根据数据访问方式有所变化,好比使用Hibernate进行数据访问 时,DataSource实际为SessionFactory,TransactionManager的实现为 HibernateTransactionManager。

根据代理机制的不一样,Spring事务的配置又有几种不一样的方式:
    第一种方式:每一个Bean都有一个代理
    第二种方式:全部Bean共享一个代理基类
    第三种方式:使用拦截器
    第四种方式:使用tx标签配置的拦截器
    第五种方式:全注解

 

  


2. 五大隔离级别

  1. ISOLATION_DEFAULT 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.另外四个与JDBC的隔离级别相对应【默认】
  2. ISOLATION_READ_UNCOMMITTED 这是事务最低的隔离级别,它充许别外一个事务能够看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读【隔离级别最低,并发性能高 】
  3. ISOLATION_READ_COMMITTED 保证一个事务修改的数据提交后才能被另一个事务读取。另一个事务不能读取该事务未提交的数据。这种事务隔离级别能够避免脏读出现,可是可能会出现不可重复读和幻像读。【锁定正在读取的行】
  4. ISOLATION_REPEATABLE_READ 这种事务隔离级别能够防止脏读,不可重复读。可是可能出现幻像读。它除了保证一个事务不能读取另外一个事务未提交的数据外,还保证了避免下面的状况产生(不可重复读)。【锁定所读取的全部行】
  5. ISOLATION_SERIALIZABLE 这是花费最高代价可是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。【锁表】

3. 七大事务传播类型

  1. PROPAGATION_REQUIRED 若是存在一个事务,则支持当前事务。若是没有事务则开启一个新的事务。【默认】
  2. PROPAGATION_SUPPORTS 若是存在一个事务,支持当前事务。若是没有事务,则非事务的执行。可是对于事务同步的事务管理器,PROPAGATION_SUPPORTS与不使用事务有少量不一样。
  3. PROPAGATION_MANDATORY 若是已经存在一个事务,支持当前事务。若是没有一个活动的事务,则抛出异常。
  4. PROPAGATION_REQUIRES_NEW 老是开启一个新的事务。若是一个事务已经存在,则将这个存在的事务挂起。
  5. PROPAGATION_NOT_SUPPORTED 老是非事务地执行,并挂起任何存在的事务。
  6. PROPAGATION_NEVER 老是非事务地执行,若是存在一个活动事务,则抛出异常
  7. PROPAGATION_NESTED若是一个活动的事务存在,则运行在一个嵌套的事务中. 若是没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行
若是子事务回滚,父事务会回滚到进入子事务前创建的save point,而后尝试其余的事务或者其余的业务逻辑,父事务以前的操做不会受到影响,更不会自动回滚。
若是父事务回滚,子事务也会跟着回滚。由于父事务结束以前,子事务是不会提交的,由于子事务是父事务的一部分。
事务的提交:子事务先提交,父事务再提交。
子事务是父事务的一部分,由父事务统一提交。

4. 事务超时

      所谓事务超时,就是指一个事务所容许执行的最长时间,若是超过该时间限制但事务尚未完成,则自动回滚事务

  在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。

  默认设置为底层事务系统的超时值,若是底层数据库事务系统没有设置超时值,那么就是none,没有超时限制。

 

5. 事务只读属性

      只读事务用于客户代码只读但不修改数据的情形,只读事务用于特定情景下的优化,好比使用Hibernate的时候。默认为读写事务。

  “只读事务”仅仅是一个性能优化的推荐配置而已,并不是强制你要这样作不可

  “只读事务”并非一个强制选项,它只是一个“暗示”,提示数据库驱动程序和数据库系统,这个事务并不包含更改数据的操做,那么JDBC驱动程序和数据库就有可能根据这种状况对该事务进行一些特定的优化,比方说不安排相应的数据库锁,以减轻事务对数据库的压力,毕竟事务也是要消耗数据库的资源的。 可是你非要在“只读事务”里面修改数据,也并不是不能够,只不过对于数据一致性的保护不像“读写事务”那样保险而已。 

6. spring事务回滚规则

   Spring、EJB的声明式事务默认状况下都是在抛出unchecked exception后才会触发事务的回滚

   unchecked异常,即运行时异常runntimeException 回滚事务;

   checked异常,即Exception可try{}捕获的不会回滚.固然也可配置spring参数让其回滚. 

指示spring事务管理器回滚一个事务的推荐方法是在当前事务的上下文内抛出异常。

spring事务管理器会捕捉任何未处理的异常,而后依据规则决定是否回滚抛出异常的事务。
默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会致使事务回滚),而抛出checked异常则不会致使事务回滚
能够明确的配置在抛出那些异常时回滚事务,包括checked异常。 也能够明肯定义那些异常抛出时不回滚事务。 还能够编程性的经过setRollbackOnly()方法来指示一个事务必须回滚,在调用完setRollbackOnly()后你所能执行的惟一操做就是回滚。

让Exception异常也进行回滚操做,在调用该方法前加上: @Transactional(rollbackFor = Exception.class)
让RuntimeException不进行回滚操做,在调用该方法前加上: @Transactional(rollbackFor = RuntimeException.class)
在整个方法运行前就不会开启事务: @Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true),这样就作成一个只读事务,能够提升效率

 

4.4 4大核心接口/类

  1. ApplicationContext保存了ioc的整个应用上下文,能够经过其中的beanfactory获取到任意到bean;
  2. BeanFactory主要的做用是根据bean definition来建立具体的bean;
  3. BeanWrapper是对Bean的包装,通常状况下是在spring ioc内部使用,提供了访问bean的属性值、属性编辑器注册、类型转换等功能,方便ioc容器用统一的方式来访问bean的属性;
  4. FactoryBean经过getObject方法返回实际的bean对象,例如motan框架中referer对service的动态代理就是经过FactoryBean来实现的。

 

4.5 7种Scope

Scopebean的scope是指bean的做用域,request、session、global-session是在web服务中使用的scope

  1. singleton默认状况下是单例模式,这也是使用最多的一种方式;
  2. prototype多例模式,即每次从beanFactory中获取bean都会建立一个新的bean。
  3. request每次请求都建立一个实例,
  4. session是在一个会话周期内保证只有一个实例。
  5. global-session在5.x版本中已经不在使用,
  6. Application保证在一个ServletContext中只建立一个实例。
  7. Websocket保证在一个WebSocket中只建立一个实例。

4.6 5大事件机制

一、基本概念

    1)事件驱动模型

    当事件被触发的时候,将事件加入一个事件队列,而后经过主程序不断轮训事件队列,处理目标函数。常见的事件驱动如鼠标点击事件、IO事件等,观察者设计模式就是事件驱动的一个很好实现。

    2)消息驱动模型/发布订阅模型

    本质上讲,事件驱动和消息驱动至关,只是各自应用在不一样的场景下。事件模式耦合高,同模块内好用;消息模式耦合低,跨模块好用。

二、五大标准事件

 

  https://blog.csdn.net/u014746965/article/details/78480159

 在spring中提供的标准事件:

    1)ContextRefreshEvent,当ApplicationContext容器初始化完成或者被刷新的时候,就会发布该事件。

    2)ContextStartedEvent,当ApplicationContext启动的时候发布事件,即调用ConfigurableApplicationContext接口的start方法的时候

    3)ContextStoppedEvent,当ApplicationContext容器中止的时候发布事件,即调用ConfigurableApplicationContext的close方法的时候

    4)ContextClosedEvent,当ApplicationContext关闭的时候发布事件,即调用ConfigurableApplicationContext的close方法的时候,关闭指的是全部的单例Bean都被销毁。

    5)equestHandledEvent,只能用于DispatcherServlet的web应用,Spring处理用户请求结束后,系统会触发该事件。

 

三、Spring事件机制实现

    事件,ApplicationEvent,继承自EventObject。

    事件监听器,ApplicationListener,是一个接口,继承自EventListener,实际中须要实现其onApplicationEvent方法。

    事件发布,ApplicationEventPublisher,是一个接口,包含publishEvent()方法,ApplicationContext继承了该接口,在AbstractApplicationContext中实现里事件的发布接口。

 Spring是如何经过事件找到对应的监听器的呢?Spring利用反射机制经过getBeansOfType获取全部继承了ApplicationListener接口的监听器,而后把监听器放到注册表中

 

五.Spring应用

5.1 经常使用注释

a.类型类注释:

@Component 是一个泛化的概念,仅仅表示一个组件 (Bean) ,能够做用在任何层次。

@Service 标注业务层组件,可是目前该功能与 @Component 相同。自动根据bean的类名实例化一个首写字母为小写的bean,例如Chinese实例化为chinese,若是须要本身更名字则:@Service("你本身改的bean名")。  

@Constroller 标注控制层组件,可是目前该功能与 @Component 相同。

@Repository 标注持久层组件,用于标注数据访问组件,即DAO组件,标识为 Spring Bean。

@Configuration 用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,至关于把该类做为spring的xml配置文件中的<beans>,做用为:配置spring容器(应用上下文)

@Bean 标注在方法上(返回某个实例的方法),等价于spring的xml配置文件中的<bean>,做用为:注册bean对象

1. 在目前的 Spring 版本中,@Constroller,@Service ,@Repository这 3 个注释和 @Component 是等效的,可是从注释类的命名上,很容易看出这 3 个注释分别和持久层、业务层和控制层(Web 层)相对应。
2. 为了让 Spring 可以扫描类路径中的类并识别出注解,须要在 XML 配置文件中启用Bean 的自动扫描功能,这能够经过<context:component-scan/>实现。
3. @Configuration注解的配置类有以下要求:
    @Configuration不能够是final类型;
    @Configuration不能够是匿名类;
    嵌套的configuration必须是静态类。
4. 其中component和bean注解的区别以下:
    @Component注解在类上使用代表这个类是个组件类,须要Spring为这个类建立bean。 @Bean注解使用在方法上,告诉Spring这个方法将会返回一个Bean对象,须要把返回的对象注册到Spring的应用上下文中 @Configuration。

b.设置类注解

@Require 注解做用于Bean的 setter 方法上,用于检查一个Bean的属性的值在配置期间是否被赋予或设置(populated),不然,容器会抛出一个BeanInitializationException异常。

@Autowire和@Resource都是Spring支持的注解方式动态装配bean。做用范围在字段上,均无需在写setter方法

@Autowire默认按照类型(by-type)装配,默认状况下要求依赖对象必须存在。若是使用按照名称(by-name)装配,需结合@Qualifier注解使用,即

@Scope注解是springIoc容器中的一个做用域

1. @Autowire默认按照类型(by-type)装配,默认状况下要求依赖对象必须存在。
    若是容许依赖对象为null,需设置required属性为false,即
    @Autowire(required=false)
    private InjectionBean beanName;

    若是使用按照名称(by-name)装配,需结合@Qualifier注解使用,即
    @Autowire @Qualifier("beanName")
    private InjectionBean beanName;

    说明
    @Autowire按照名称(by-name)装配,则
    @Autowire + @qualifier("") = @Resource(name="")

2. @Resource
  @Resource默认按照名称(by-name)装配,名称能够经过name属性指定。若是没有指定name:1.当注解在字段上时,默认取name=字段名称装配。2.当注解在setter方法上时,默认取name=属性名称装配。当按照名称(by-name)装配未匹配时,按照类型(by-type)装配。当显示指定name属性后,只能按照名称(by-name)装配。
  @Resoure装配顺序
    1. 若是同时指定name和type属性,则找到惟一匹配的bean装配,未找到则抛异常;
    2. 若是指定name属性,则按照名称(by-name)装配,未找到则抛异常;
    3. 若是指定type属性,则按照类型(by-type)装配,未找到或者找到多个则抛异常;
    4. 既未指定name属性,又未指定type属性,则按照名称(by-name)装配;若是未找到,则按照类型(by-type)装配。
  

  https://blog.csdn.net/xxliuboy/article/details/86441832

3. @Scope a.singleton单例模式 -- 全局有且仅有一个实例【默认】 b.prototype原型模式 -- 每次获取Bean的时候会有一个新的实例 c.request -- request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效 d.session -- session做用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效 e.globalsession -- global session做用域相似于标准的HTTP Session做用域,不过它仅仅在基于portlet的web应用中才有意义
  
   @Scope(value = "prototype")

 

c.web类注解

路径匹配注解

@GetMapping:用于将Http Get 请求映射到特定处理程序方法的注释。具体来讲就是:@GetMapping是一个做为快捷方式的组合注释 @RequestMapping(method = RequestMethod.GET)。

@PostMapping:用于将Http Post 请求映射到特定处理程序方法的注释。具体来讲就是:@PostMapping是一个做为快捷方式的组合注释@RequestMapping(method = RequestMethod.POST)。

@RequestMapping:通常状况下都是用@RequestMapping(method = RequestMethod),由于@RequestMapping能够直接替代以上两个注解,可是以上两个注解并不能替代@RequestMapping。

相似组合注解还有:@PutMapping、@DeleteMapping、@PatchMapping

总结下来就是@PostMapping和@GetMapping均可以用@RequestMapping代替,通常能够统一写成@RequestMapping,可是不利于其余人对代码的阅读和理解!仍是建议分开写。

参数获取注解

@PathVaribale 获取url中的数据

@RequestParam 获取请求参数的值

@ResponseBody: responseBody表示服务器返回的时候以一种什么样的方式进行返回, 将内容或对象做为 HTTP 响应正文返回,值有不少,通常设定为json

@RequestBody:通常是post请求的时候才会使用这个请求,把参数丢在requestbody里面

@RequestMapping("/hello/{id}")
    public String getDetails(@PathVariable(value="id") String id,
    @RequestParam(value="param1", required=true) String param1,
    @RequestParam(value="param2", required=false) String param2){
.......
}
 
@PathParam:这个注解是和spring的pathVariable是同样的,也是基于模板的,可是这个是jboss包下面的一个实现,上面的是spring的一个实现,都要导包
@QueryParam:@QueryParam 是 JAX-RS 原本就提供的,和Spring的RequestParam做用一致

 

d.功能类注解

引用配置

@Import注解是引入带有@Configuration的java类。

@ImportResource是引入spring配置文件.xml

自动扫描注解

@ComponentScan: 扫描指定包下的Component(@Componment,@Configuration,@Service 等等)

缓存

@EnableCaching: 管理Cache对象注解是spring framework中的注解驱动的缓存管理功能。自spring版本3.1起加入了该注解。若是你使用了这个注解,那么你就不须要在XML文件中配置cache manager了,等价于 <cache:annotation-driven/>

@Cacheable 的做用 主要针对方法配置,可以根据方法的请求参数对其结果进行缓存。@Cacheable能够标记在一个方法上(该方法是支持缓存的),也能够标记在一个类上(该类全部的方法都是支持缓存的)。

事务
@Transactional能够在service类或方法前加上@Transactional,在service类上声明@Transactional,service全部方法须要事务管理。每个业务方法开始时都会打开一个事务。

AOP

@Aspect(切面): 一般是一个类的注解,里面能够定义切入点和通知

@Pointcut(切入点): JoinPoint的集合,是程序中须要注入Advice的位置的集合,指明Advice要在什么样的条件下才能被触发,在程序中主要体现为书写切入点表达式。

定时任务
@Scheduled:定时任务

 

@ComponentScan
  扫描com.jdon.springboot2的整个父树。@ComponentScan(“com.jdon.springboot2”)   
  使用数组定义两个特定的组件扫描。@ComponentScan({“com.jdon.springboot2.abc”,”com.jdon.springboot2.efg”})

@Transactional

 

@Transactional 能够做用于接口、接口方法、类以及类方法上。看成用于类上时,该类的全部 public 方法将都具备该类型的事务属性,也能够在方法级别使用该标注来覆盖类级别的定义。

 虽然 @Transactional 注解能够做用于接口、接口方法、类以及类方法上,可是 Spring 建议不要在接口或者接口方法上使用该注解,由于这只有在使用基于接口的代理时它才会生效。

@Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。若是你在 protected、private 或者默承认见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。

 默认状况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其余方法并不会引发事务行为,即便被调用方法使用@Transactional注解进行修饰。

@Aspect

Advice(通知、切面): 某个链接点所采用的处理逻辑,也就是向链接点注入的代码, AOP在特定的切入点上执行的加强处理。
  1.1 @Before: 标识一个前置加强方法,至关于BeforeAdvice的功能.   1.2 @After: final加强,无论是抛出异常或者正常退出都会执行.   1.3 @AfterReturning: 后置加强,似于AfterReturningAdvice, 方法正常退出时执行.   1.4 @AfterThrowing: 异常抛出加强,至关于ThrowsAdvice.   1.5 @Around: 环绕加强,至关于MethodInterceptor. JointPoint(链接点):程序运行中的某个阶段点,好比方法的调用、异常的抛出等。 Pointcut(切入点): JoinPoint的集合,是程序中须要注入Advice的位置的集合,指明Advice要在什么样的条件下才能被触发,在程序中主要体现为书写切入点表达式。 Advisor(加强): 是PointCut和Advice的综合体,完整描述了一个advice将会在pointcut所定义的位置被触发。 @Aspect(切面): 一般是一个类的注解,里面能够定义切入点和通知 AOP Proxy:AOP框架建立的对象,代理就是目标对象的增强。Spring中的AOP代理可使JDK动态代理,也能够是CGLIB代理,前者基于接口,后者基于子类。

 

@Scheduled
  在启动类上面加上 @EnableScheduling 注解便可开启定时任务
  @EnableScheduling
  @SpringBootApplication
    public class SchedulingApplication {

        public static void main(String[] args) {
            SpringApplication.run(SchedulingApplication.class, args);
        }
    }
     

    @Scheduled(fixedDelay = 1000 * 10,initialDelay=1000*15)
    public void Task() { 
     
    }

    @Scheduled(fixedRate=2000):上一次开始执行时间点后2秒再次执行;
    @Scheduled(fixedDelay=2000):上一次执行完毕时间点后2秒再次执行;
    @Scheduled(initialDelay=1000, fixedDelay=2000):第一次延迟1秒执行,而后在上一次执行完毕时间点后2秒再次执行;
    @Scheduled(cron="* * * * * ?"):按cron规则执行。


    "0 0 10,14,16 * * ?" 天天上午10点,下午2点,4点 
    "0 0/30 9-17 * * ?"   朝九晚五工做时间内每半小时
    "0 0 12 ? * WED" 表示每一个星期三中午12点
    "0 0 12 * * ?" 天天中午12点触发
    "0 * 14 * * ?" 在天天下午2点到下午2:59期间的每1分钟触发
    "0 0/5 14 * * ?" 在天天下午2点到下午2:55期间的每5分钟触发
    "0 0/5 14,18 * * ?" 在天天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
    "0 0-5 14 * * ?" 在天天下午2点到下午2:05期间的每1分钟触发
    "0 10,44 14 ? 3 WED" 每一年三月的星期三的下午2:10和2:44触发
    "0 15 10 ? * MON-FRI" 周一至周五的上午10:15触发
    "0 15 10 15 * ?" 每个月15日上午10:15触发
    "0 15 10 L * ?" 每个月最后一日的上午10:15触发
    "0 15 10 ? * 6L" 每个月的最后一个星期五上午10:15触发
    "0 15 10 ? * 6L 20014-20018" 2014年至2018年的每个月的最后一个星期五上午10:15触发
    "0 15 10 ? * 6#3" 每个月的第三个星期五上午10:15触发
    "0 15 10 ? * *" 天天上午10:15触发
    "0 15 10 * * ?" 天天上午10:15触发
    "0 15 10 * * ? *" 天天上午10:15触发
    "0 15 10 * * ? 2017" 2017年的天天上午10:15触发
    
    原文连接:https://blog.csdn.net/LDY1016/article/details/84326199

 

5.2 配置方式

spring的三种方式,

  1. xml文件配置、

  2. 注解配置:隐式的bean发现机制和自动装配(@Component @Resource @Autowire @ComponentScan)和使用

  3. Java代码装配bean(@Configuration, @Bean)进行配置。

1、Explicit configuration in XML:显示的XML配置。
    优势:
         1)XML配置方式进一步下降了耦合,使得应用更加容易扩展,即便对配置文件进一步修改也不须要工程进行修改和从新编译。
         2)在处理大的业务量的时候,用XML配置应该更加好一些。
    缺点:
         1)配置文件读取和解析须要花费必定的时间,配置文件过多的时候难以管理。
         2)没法对配置的正确性进行校验,增长了测试难度。
    举个例子:
        1、配置application.xml文件(名字随意)
        二、声明命名空间   xmlns="http://www.springframework.org/schema/beans 
        3、配置bean
        <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
         
            <bean id="user" class="ioc.User"/>
            
        </beans>
 

2、Explicit configuration in Java:显示的JavaConfig,基于java类配置。
    JavaConfig is the preferred option for explicit configuration
because it’s more powerful, type-safe, and refactor-friendly.

    优势:
        1)在class文件中,下降维护成本。
        2)不须要第三方解析工具。
        3)编辑期就能够检验正确性,提升开发效率。

    缺点:
        1)配置代码过多时,直接影响代码质量,对于代码的简洁度有影响。
        2)业务类之间的关系不如XML配置那样容易把握。
        3)若是须要修改配置,则要从新编译整个工程。
    
    举个例子:
         1)在标注了@Configuration的java类中,经过在类方法标注@Bean定义一个Bean。
        2)经过在成员变量或者方法入参处标注@Autowired按类型匹配注入,也可使用@Qualifier按名称配置注入。
         
         @Configuration 
          public class Conf {   
              @Scope(“prototype”)   
              @Bean(“loginUserDao”)   
              public LoginUserDao loginUserDao() {   
                return new LoginUserDao();   
             }   
        }   

3、Implicit bean discovery and automatic wiring:隐式的bean扫描,基于java注解配置,自动注入。
   
    优势:
        1)在class文件中,下降维护成本。
        2)不须要第三方解析工具,利用java反射机制。
        3)编辑期就能够检验正确性,提升开发效率。
    
    缺点:
        1)若是须要对annotation进行修改,那么要从新编译整个工程。
        2)业务类之间的关系不如XML配置那样容易把握。
        3)若是在程序中annotation比较多,直接影响代码质量,对于代码的简洁度有影响。
        4)符合条件的多个bean注入时,spring不知道如何选择,会有异常NoUniqueBeanDefinitionException。

    举个例子:
        1)@Component:标注一个普通的Spring Bean类
        2)在方法处经过@Autowired使方法入参绑定Bean,而后在方法中经过代码进行注入。

        @Scope(“prototype”)   
        @Lazy(true)  
        @Component(“loginUserDao”)  
        public class LoginUserDao {  }   

ps:
这三种方式均可以将bean交给Spring管理,那么应该如何选择呢? 

     根据不一样方式的优缺点,如今的企业开发通常采用以下方式:

     一、自定义声明的类(非第三方),采用注解的方式。

     二、对于第三方类,采用XML或者JavaConfig的方式。

    因为SpringBoot的出现,在无配置化的趋势下,XML配置逐渐被JavaConfig所取代,由于咱们在建立类的同时可能还要作不少事情,这是XML不发知足的。SpringBoot推荐使用JavaConfig配置。

 

5.3 自动装配

spring从两个角度来实现自动化装配:

  1.组件扫描(component scanning):spring会自动发现应用上下文所建立的bean。

  2.自动装配(autowiring):spring自动知足spring之间的依赖。

Spring提供了 五种自动装配的类型

  ①no:显示指明不使用Spring的自动装配功能

  ②byName:根据属性和组件的名称匹配关系来实现bean的自动装配

  ③byType:根据属性和组件的类型匹配关系来实现bean的自动装配,有多个适合类型的对象时装配失败

  ④constructor:与byType相似是根据类型自动装配,可是要求待装配的bean有相应的构造函数

  ⑤autodetect: 自动检测,利用Spring的自省机制判断使用byType或是constructor装配

3种方式:

  1. 使用XML方式进行装配

  2. 使用注解的方式进行装配:隐式的bean发现机制和自动装配(@Component @Resource @Autowire @ComponentScan)和使用

    @Resource 根据byName进行装配

    @Autowire经过byType进行装配

  3. Java代码装配bean(@Configuration, @Bean)进行配置。

 

5.4 四种依赖注入方式

     一、set注入(一般也叫属性注入):(userDao注入到UserServiceImpl中)

     二、构造函数注入

     三、接口注入(这个如今基本不用)

     四、注解注入(@Autowire) (@Component,@Service,@Controller等直接@Autowire

 

5.5 集合属性配置方式

集合的注入都是给<property>添加子标签

数组:<array>
List:<list>
Set:<set>
Map:<map> ,map存放k/v 键值对,使用<entry>描述
Properties:<props>  <prop key=""></prop>  

普通数据:<value>
引用数据:<ref>
http://www.javashuo.com/article/p-oanjlpvh-cs.html

 

5.6 内部Bean

1. 当一个bean仅被用做另外一个bean的属性时,它能被声明为一个内部bean,只能经过该类实例化。
2. 为了定义inner bean,在Spring 的 基于XML的 配置元数据中,能够在 <property/><constructor-arg/> 元素内使用<bean/> 元素,
3. 内部bean一般是匿名的,它们的Scope通常是prototype。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="person2" class="com.itdjx.spring.dependency.injection.Person">
        <property name="name" value="李玉"/>
        <property name="age" value="23"/>
        <property name="sex" value="女"/>
        <property name="car" >
            <bean class="com.itdjx.spring.dependency.injection.Car">
                <constructor-arg value="Ferrari" index="0"/>
                <constructor-arg value="Italy" index="1"/>
                <constructor-arg value="22500000" type="double"/>
            </bean>
        </property>
    </bean>
</beans>

参考:
https://www.jianshu.com/p/3ce23a7b096a
Spring中的内部Bean

 

六. Spring Context初始化流程

 

https://zhuanlan.zhihu.com/p/59327709

  图中左上角是三种类型的context,xml配置方式的context、springboot的context和web服务的context。

  不论哪一种context,建立后都会调用到AbstractApplicationContext类的refresh方法,这个方法是咱们要重点分析的。

  refresh方法中,操做共分13步:

  1. prepareRefresh(); 对刷新进行准备,包括设置开始时间,设置激活状态,初始化Context中的占位符,子类根据其需求执行具体准备工做,然后再由父类验证必要参数
  2. obtianFreshBeanFactory(); 刷新并获取内部的BeanFactory对象
  3. prepareBeanFactory(beanFactory); 对BeanFactory进行准备工做,包括设置类加载器和后置处理器,配置不能自动装配的类型,注册默认的环境Bean
  4. postProcessBeanFactory(beanFactory); 为Context的子类提供后置处理BeanFactory的扩展能力,如想在bean定义加载完成后,开始初始化上下文以前进行逻辑操做,可重写这个方法
  5. invokeBeanFactoryPostProcessors(beanFactory); 执行Context中注册的BeanFactory后置处理器,有两张处理器,一种是能够注册Bean的后置处理器,一种的针对BeanFactory的后置处理器,执行顺序是先按优先级执行注册Bean的后置处理器,然后再按优先级执行针对BeanFactory的后置处理器SpringBoot中会进行注解Bean的解析,由ConfigurationClassPostProcessor触发,由ClassPathDefinitionScanner解析,并注册到BeanFactory
  6. registerBeanFactoryProcessor(beanFactory(); 按优先级顺序在BeanFactory中注册Bean的后置处理器,Bean处理器可在Bean的初始化先后处理
  7. initMessageSource();初始化消息源,消息源用于支持消息的国际化
  8. initApplicationEventMuticaster();初始化应用事件广播器,用于向ApplicationListener通知各类应用产生的事件,标准的观察者模型
  9. onRefresh(); 用于子类的扩展步骤,用于特定的Context子类初始化其余的Bean
  10. registerListeners(); 把实现了ApplicationListener的类注册到广播器,并对广播其中早期没有广播的事件进行通知
  11. finishBeanFactoryInitialization(beanFactory); 冻结全部Bean描述信息的修改,实例化非延迟加载的单例Bean
  12. finishRefresh(); 完成上下文的刷新工做,调用LifecycleProcessor.onRefresh(),以及发布ContextRefreshedEvent事件
  13. resetCommonCaches(); 在finally中执行该步骤,重置公共的缓存,如ReflectionUtils中的缓存,AnnotationUtils等

   更详细可见:SpringBoot源码分析之Spring容器的refresh过程

 

七. Spring中bean的生命周期

Spring中bean的生命周期

第1步:调用bean的构造方法建立bean;

第2步:经过反射调用setter方法进行属性的依赖注入;

第3步:若是实现BeanNameAware接口的话,会设置bean的name;

第4步:若是实现了BeanFactoryAware,会把bean factory设置给bean;

第5步:若是实现了ApplicationContextAware,会给bean设置ApplictionContext;

第6步:若是实现了BeanPostProcessor接口,则执行前置处理方法;

第7步:实现了InitializingBean接口的话,执行afterPropertiesSet方法;

第8步:执行自定义的init方法;

第9步:执行BeanPostProcessor接口的后置处理方法。

这时,就完成了bean的建立过程。

在使用完bean须要销毁时,会先执行DisposableBean接口的destroy方法,而后在执行自定义的destroy方法。

这部分也建议阅读源码加深理解。

 

八. Spring扩展接口

 

对spring进行定制化功能扩展时,能够选择以下一些扩展点:

▌1.BeanFactoryPostProcessor

是beanFactory后置处理器,支持在bean factory标准初始化完成后,对bean factory进行一些额外处理。在讲context初始化流程时介绍过,这时全部的bean的描述信息已经加载完毕,可是尚未进行bean初始化。例如前面提到的PropertyPlaceholderConfigurer,就是在这个扩展点上对bean属性中的占位符进行替换。

▌2.BeanDefinitionRegistryPostProcessor

它扩展自BeanFactoryPostProcessor,在执行BeanFactoryPostProcessor的功能前,提供了能够添加bean definition的能力,容许在初始化通常bean前,注册额外的bean。例如能够在这里根据bean的scope建立一个新的代理bean。

▌3.BeanPostProcessor

提供了在bean初始化以前和以后插入自定义逻辑的能力。与BeanFactoryPostProcessor的区别是处理的对象不一样,BeanFactoryPostProcessor是对beanfactory进行处理,BeanPostProcessor是对bean进行处理。

注:上面这三个扩展点,能够经过实现Ordered和PriorityOrdered接口来指定执行顺序。实现PriorityOrdered接口的processor会先于实现Ordered接口的执行。

▌4.ApplicationContextAware

能够得到ApplicationContext及其中的bean,当须要在代码中动态获取bean时,能够经过实现这个接口来实现。

▌5.InitializingBean

能够在bean初始化完成,全部属性设置完成后执行特定逻辑,例如对自动装配对属性进行验证等等。

▌6.DisposableBean

用于在bean被销毁前执行特定的逻辑,例如作一些回收工做等。

▌7.ApplicationListener

用来监听spring的标准应用事件或者自定义事件。

 

参考网址

  1. 官网:https://spring.io/projects/spring-framework
  2. 百度百科:https://baike.baidu.com/item/spring/85061?fr=aladdin#7
  3. Spring中文文档-第一部分
  4. 几种placeholder替换项目参数的方法比较
  5. SpringBoot源码分析之Spring容器的refresh过程
相关文章
相关标签/搜索