目录

  • Spring介绍
    • 简介
    • 背景
    • 框架特征
    • 特性
    • 特点
    • 好处
    • 作用
    • 基本框架
    • 下载
    • 组件
    • 容器
  • IoC/DI
    • Maven搭建Spring项目
    • 基于xml配置文件方式操作bean
      • setter方法注入
      • 有参构造方法注入
      • p名称空间注入
      • 特殊处理
      • MVC模式:用spring创建对象、注入属性
      • Spring创建对象;注入属性;内部bean
      • 一对多
        • 属性注入、赋值
        • 级联赋值
          • 写法一
          • 写法二
      • 注入集合类型属性
        • 注入数组类型属性
        • 注入List集合类型属性
        • 注入Set集合类型属性
        • 注入Map集合类型属性
      • 在集合里面设置对象类型值
      • 提取List类型属性注入
      • IoC操作FactoryBean
      • bean的作用域
      • bean的生命周期
      • 自动装配
      • 引入外部属性文件配置数据库连接池
    • 基于注解方式操作bean
      • 组件扫描方式
      • 完全注解方式
      • 基于注解方式进行属性注入
  • AOP
    • 底层原理
    • 使用JDK动态代理
    • AOP术语
    • AOP操作
      • 切入点表达式
      • AOP操作
        • AspectJ注解
        • AOP操作(AspectJ配置文件)
  • JdbcTemplate
    • 基本操作
      • 添加操作
      • 修改操作
      • 删除操作
      • 查询操作
        • 返回结果为值类型
        • 返回结果为对象类型
        • 返回结果为List集合类型
    • 批量操作
      • 批量添加操作
      • 批量修改操作
      • 批量删除操作
  • 事务
    • 事务管理
      • 基于注解方式
      • 声明式事务管理参数配置
        • propagation:事务传播行为
        • ioslation:事务隔离级别
        • timeout:超时时间
        • readOnly:是否只读
        • rollbackFor:回滚

Spring介绍

官网地址:https://spring.io/
下载地址:https://repo.spring.io/release/org/springframework/spring/

Spring框架是一个开放源代码的J2EE应用程序框架,由Rod Johnson发起,是针对bean的生命周期进行管理的轻量级容器(lightweight container)。 Spring解决了开发者在J2EE开发中遇到的许多常见的问题,提供了功能强大的IOC、AOP及Web MVC等功能。Spring可以单独应用于构筑应用程序,也可以和Struts、Webwork、Tapestry等众多Web框架组合使用,并且可以与 Swing等桌面应用程序AP组合。因此, Spring不仅仅能应用于J2EE应用程序之中,也可以应用于桌面应用程序以及小应用程序之中。Spring框架主要由七部分组成,分别是 Spring Core、Spring AOP、Spring ORM、Spring DAO、Spring Context、Spring Web和Spring Web MVC。

Spring是一个轻量级框架

简介

Spring是Java EE编程领域的一个轻量级开源框架,该框架由一个叫Rod Johnson的程序员在 2002 年最早提出并随后创建,是为了解决企业级编程开发中的复杂性,实现敏捷开发的应用型框架 。Spring是一个开源容器框架,它集成各类型的工具,通过核心的Bean factory实现了底层的类的实例化和生命周期的管理。在整个框架中,各类型的功能被抽象成一个个的 Bean,这样就可以实现各种功能的管理,包括动态加载和切面编程。Spring是独特的,因为若干个原因:
它定位的领域是许多其他流行的framework没有的。Spring致力于提供一种方法管理你的业务对象。
Spring是全面的和模块化的。Spring有分层的体系结构,这意味着你能选择使用它孤立的任何部分,它的架构仍然是内在稳定的。例如,你可能选择仅仅使用Spring来简单化JDBC的使用,或用来管理所有的业务对象。
它的设计从底部帮助你编写易于测试的代码。Spring是用于测试驱动工程的理想的framework。
Spring对你的工程来说,它不需要一个以上的framework。Spring是潜在地一站式解决方案,定位于与典型应用相关的大部分基础结构。它也涉及到其他framework没有考虑到的内容。

背景

Rod Johnson在2002年编著的《Expert one on one J2EE design and development》一书中,对Java EE 系统框架臃肿、低效、脱离现实的种种现状提出了质疑,并积极寻求探索革新之道。以此书为指导思想,他编写了interface21框架,这是一个力图冲破J2EE传统开发的困境,从实际需求出发,着眼于轻便、灵巧,易于开发、测试和部署的轻量级开发框架。Spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日,发布了1.0正式版。同年他又推出了一部堪称经典的力作《Expert one-on-one J2EE Development without EJB》,该书在Java世界掀起了轩然大波,不断改变着Java开发者程序设计和开发的思考方式。在该书中,作者根据自己多年丰富的实践经验,对EJB的各种笨重臃肿的结构进行了逐一的分析和否定,并分别以简洁实用的方式替换之。至此一战功成,Rod Johnson成为一个改变Java世界的大师级人物。
传统J2EE应用的开发效率低,应用服务器厂商对各种技术的支持并没有真正统一,导致J2EE的应用没有真正实现Write Once及Run Anywhere的承诺。Spring作为开源的中间件,独立于各种应用服务器,甚至无须应用服务器的支持,也能提供应用服务器的功能,如声明式事务、事务处理等。
Spring致力于J2EE应用的各层的解决方案,而不是仅仅专注于某一层的方案。可以说Spring是企业应用开发的“一站式”选择,并贯穿表现层、业务层及持久层。然而,Spring并不想取代那些已有的框架,而是与它们无缝地整合。

框架特征

轻量——从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。

控制反转——Spring通过一种称作控制反转(IoC)的技术促进了低耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。它的底层设计模式采用了工厂模式,所有的 Bean 都需要注册到Bean工厂中,将其初始化和生命周期的监控交由工厂实现管理。程序员只需要按照规定的格式进行Bean开发,然后利用XML文件进行bean 的定义和参数配置,其他的动态生成和监控就不需要调用者完成,而是统一交给了平台进行管理。控制反转是软件设计大师 Martin Fowler在 2004 年发表的”Inversion of Control Containers and the Dependency Injection pattern”提出的。这篇文章系统阐述了控制反转的思想,提出了控制反转有依赖查找和依赖注入实现方式。控制反转意味着在系统开发过程中,设计的类将交由容器去控制,而不是在类的内部去控制,类与类之间的关系将交由容器处理,一个类在需要调用另一个类时,只要调用另一个类在容器中注册的名字就可以得到这个类的实例,与传统的编程方式有了很大的不同,“不用你找,我来提供给你”,这就是控制反转的含义。

面向切面——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中的各种模块提供了基础支持。

特性

强大的基于 JavaBeans的采用控制反转(Inversion of Control,IoC)原则的配置管理,使得应用程序的组件更加快捷简易。一个可用于从 applet 到 Java EE 等不同运行环境的核心 Bean 工厂。
数据库事务的一般化抽象层,允许宣告式(Declarative)事务管理器,简化事务的划分使之与底层无关。
内建的针对 JTA 和 单个 JDBC 数据源的一般化策略,使 Spring 的事务支持不要求 Java EE 环境,这与一般的 JTA 或者 EJB CMT 相反。
JDBC 抽象层提供了有针对性的异常等级(不再从SQL异常中提取原始代码),简化了错误处理,大大减少了程序员的编码量。 再次利用JDBC时,你无需再写出另一个 ‘终止’ (finally) 模块。并且面向JDBC的异常与Spring 通用数据访问对象(Data Access Object) 异常等级相一致.
以资源容器,DAO 实现和事务策略等形式与 Hibernate,JDO 和 iBATIS SQL Maps 集成。利用众多的反转控制方便特性来全面支持, 解决了许多典型的Hibernate集成问题。所有这些全部遵从Spring通用事务处理和通用数据访问对象异常等级规范。
灵活的基于核心Spring 功能的 MVC网页应用程序框架。开发者通过策略接口将拥有对该框架的高度控制,因而该框架将适应于多种呈现(View)技术,例如 JSP,FreeMarker,Velocity,Tiles,iText 以及 POI。值得注意的是,Spring 中间层可以轻易地结合于任何基于 MVC 框架的网页层,例如 Struts,WebWork,或 Tapestry。

提供诸如事务管理等服务的面向切面编程(AOP)框架。

特点

1、便解耦,简化开发
通过Spring提供的IoC容器,我们可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。有了Spring,用户不必再为单实例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。

2、AOP编程的支持
通过Spring提供的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付。

3、声明式事务的支持
在Spring中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。

4、方便程序的测试
可以用非容器依赖的编程方式进行几乎所有的测试工作,在Spring里,测试不再是昂贵的操作,而是随手可做的事情。例如:Spring对Junit4支持,可以通过注解方便的测试Spring程序。

5.方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,相反,Spring可以降低各种框架的使用难度,Spring提供了对各种优秀框架(如Struts,Hibernate、Hessian、Quartz)等的直接支持。

6.降低Java EE API的使用难度
Spring对很多难用的Java EE API(如JDBC,JavaMail,远程调用等)提供了一个薄薄的封装层,通过Spring的简易封装,这些Java EE API的使用难度大为降低。

7、Java 源码是经典学习范例
Spring的源码设计精妙、结构清晰、匠心独运,处处体现着大师对Java设计模式灵活运用以及对Java技术的高深造诣。Spring框架源码无疑是Java技术的最佳实践范例。如果想在短时间内迅速提高自己的Java技术水平和应用开发水平,学习和研究Spring源码将会使你收到意想不到的效果。

好处

Spring能有效地组织你的中间层对象,无论你是否选择使用了EJB。如果你仅仅使用了Struts或其他的包含了J2EE特有API的framework,你会发现Spring关注了遗留下的问题。Spring能消除在许多工程上对Singleton的过多使用。根据我的经验,这是一个主要的问题,它减少了系统的可测试性和面向对象特性。

Spring能消除使用各种各样格式的属性定制文件的需要,在整个应用和工程中,可通过一种一致的方法来进行配置。曾经我们可能对类是否有某个属性会感到迷惑,因此我们不得不去看它的javadoc或源码。自从有了Spring,你可很简单地看到类的JavaBean属性。反转控制的使用(在下面讨论)帮助完成这种简化。

Spring能通过接口而不是类促进好的编程习惯,减少编程代价到几乎为零。

Spring被设计为让使用它创建的应用尽可能少的依赖于他的APIs。在Spring应用中的大多数业务对象没有依赖于Spring。

使用Spring构建的应用程序易于单元测试。

Spring能使EJB的使用成为一个实现选择,而不是应用架构的必然选择。你能选择用POJOs或local EJBs来实现业务接口,却不会影响调用代码。

Spring帮助你解决许多问题而无需使用EJB。Spring能提供一种EJB的替换物,它们适于许多web应用。例如,Spring能使用AOP提供声明性事务而不通过使用EJB容器,如果你仅仅需要与单个的数据库打交道,甚至不需要JTA实现。
Spring为数据存取提供了一致的框架,不论是使用JDBC或O/R mapping产品(如Hibernate)。
Spring确实使你能通过最简单可行的解决办法解决你的问题。这些特性是有很大价值的。

总结起来,Spring有如下优点:
1、低侵入式设计,代码污染极低。
2、独立于各种应用服务器,基于Spring框架的应用,可以真正实现Write Once,Run Anywhere的承诺。
3、Spring的DI机制降低了业务对象替换的复杂性,提高了组件之间的解耦。
4、Spring的AOP支持允许将一些通用任务如安全、事务、日志等进行集中式管理,从而提供了更好的复用。
5、Spring的ORM和DAO提供了与第三方持久层框架的良好整合,并简化了底层的数据库访问。
6、Spring并不强制应用完全依赖于Spring,开发者可自由选用Spring框架的部分或全部。

作用

Spring提供许多功能,在此我将快速地依次展示其各个主要方面。
首先,让我们明确Spring范围。尽管Spring覆盖了许多方面,但我们已经有清楚的概念,它什么应该涉及和什么不应该涉及。
Spring的主要目的是使JavaEE易用和促进好编程习惯。
Spring不重新开发已有的东西。因此,在Spring中你将发现没有日志记录的包,没有连接池,没有分布事务调度。这些均有开源项目提供(例如Commons Logging 用来做所有的日志输出,或Commons DBCP用来作数据连接池),或由你的应用程序服务器提供。因为同样的的原因,我们没有提供O/R mapping层,对此,已有友好的解决办法如Hibernate和JDO。Spring的目标是使已存在的技术更加易用。
例如,尽管我们没有底层事务协调处理,但我们提供了一个抽象层覆盖了JTA或任何其他的事务策略。
Spring没有直接和其他的开源项目竞争,除非我们感到我们能提供一些新的东西。例如,像许多开发人员,我们从来没有为Struts高兴过,并且感到在MVC web framework中还有改进的余地。在某些领域,例如轻量级的IoC容器和AOP框架,Spring有直接的竞争,但是在这些领域还没有已经较为流行的解决方案。(Spring在这些区域是开路先锋。)
Spring也得益于内在的一致性。
所有的开发者都在唱同样的的赞歌,基础想法依然是Expert One-on-One J2EE设计与开发的那些。
并且我们已经能够使用一些主要的概念,例如倒置控制,来处理多个领域。
Spring在应用服务器之间是可移植的。
当然保证可移植性总是一次挑战,但是我们避免任何特定平台或非标准化,并且支持在WebLogic,Tomcat,Resin,JBoss,WebSphere和其他的应用服务器上的用户。

基本框架

Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式。
组成Spring框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:
1、核心容器:核心容器提供 Spring 框架的基本功能(Spring Core)。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转(IoC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
2、Spring 上下文: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:负责框架中对象关系映射,提供相关ORM 接入框架的关系对象管理工具。Spring 框架插入了若干个ORM框架,从而提供了 ORM 的对象关系工具,其中包括JDO、Hibernate和iBatisSQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
6、Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
7、Spring MVC 框架:MVC框架是一个全功能的构建 Web应用程序的 MVC 实现。通过策略接口,MVC框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。模型由javabean构成,存放于Map;视图是一个接口,负责显示模型;控制器表示逻辑代码,是Controller的实现。Spring框架的功能可以用在任何J2EE服务器中,大多数功能也适用于不受管理的环境。Spring 的核心要点是:支持不绑定到特定 J2EE服务的可重用业务和数据访问对象。毫无疑问,这样的对象可以在不同J2EE 环境(Web 或EJB)、独立应用程序、测试环境之间重用。

下载

下载Spring请按如下步骤进行。
1、登录站点,下载Spring的最新稳定版本。
下载的压缩包:spring-5.2.6.RELEASE-dist.zip,解压后的文件夹(spring-framework-5.2.6.RELEASE)目录介绍:
docs:该文件下包含Spring的相关文档,包括API参考文档、开发手册。
libs:该文件夹下存放Spring各个模块的jar文件,每个模块均提供开发所需的jar文件、以“-javadoc”后缀表示的API和以“-sources”后缀表示的源文件三项内容。
schema:配置Spring的某些功能时需要用到的schema文件,对于已经继承了Spring的IDE环境(如MyEclipse),这些文件不需要专门引入。
2、将spring.jar复制到项目的CLASSPATH路径下,对于Web应用,将spring.jar文件复制到WEB-INF/lib路径下,该应用即可以利用Spring框架了。
3、通常Spring的框架还依赖于其他一些jar文件,因此还须将lib下对应的包复制到WEB-INF/lib路径下,具体要复制哪些jar文件,取决于应用所需要使用的项目。通常需要复制cglib,dom4j,jakarta-commons,log4j等文件夹下的jar文件。
4、为了编译java文件,可以找到Spring的基础类,将spring.jar文件的路径添加到环境变量CLASSPATH中。当然,也可以使用ANT工具,但无须添加环境变量。如果使用Eclipse或者NetBeans等IDE时,也不需要设置环境变量。
Spring MVC

传统的web架构的view 表现层使用struts作为表现层。但是如果试用下spring自带的MVC,会发现spring 在一般场合完全可以取代struts。从某些角度来说,spring的mvc设计的更加合理,有兴趣的话不妨尝试下单个的spring的MVC。

组件

Spring确实使你能通过最简单可行的解决办法来解决你的问题,有很大实用的价值。同时他的源代码的设计理念也受到很多程序员的追捧,简洁,易用。
1、Spring中的事务处理
2、IoC容器在Web容器中的启动
3、Spring JDBC
4、Spring MVC
5、Spring AOP获取Proxy
6、Spring声明式事务处理
7、Spring AOP中对拦截器调用的实现
8、Spring驱动Hibernate的实现
9、Spring Acegi框架鉴权的实现

IOC和AOP
控制反转模式(也称作依赖性注入)的基本概念是:不创建对象,但是描述创建它们的方式。在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务。容器 (在 Spring 框架中是 IOC 容器) 负责将这些联系在一起。在典型的 IOC 场景中,容器创建了所有对象,并设置必要的属性将它们连接在一起,决定什么时间调用方法。下表列出了 IOC 的一个实现模式。
类型 1
服务需要实现专门的接口,通过接口,由对象提供这些服务,可以从对象查询依赖性(例如,需要的附加服务)【接口注入】。
类型 2
通过JavaBean的属性(例如 setter 方法)分配依赖性【setter方法注入】。
类型 3
依赖性以构造函数的形式提供,不以 JavaBean 属性的形式公开【构造器注入】。
Spring 框架的 IOC 容器采用类型 2 和类型3 实现。

面向切面的编程,即 AOP,是一种编程技术,它允许程序员对横切关注点或横切典型的职责分界线的行为(例如日志和事务管理)进行模块化。AOP 的核心构造是方面,它将那些影响多个类的行为封装到可重用的模块中。
AOP 和 IOC 是补充性的技术,它们都运用模块化方式解决企业应用程序开发中的复杂问题。在典型的面向对象开发方式中,可能要将日志记录语句放在所有方法和 Java 类中才能实现日志功能。在 AOP 方式中,可以反过来将日志服务模块化,并以声明的方式将它们应用到需要日志的组件上。当然,优势就是 Java 类不需要知道日志服务的存在,也不需要考虑相关的代码。所以,用 Spring AOP 编写的应用程序代码是松散耦合的。
AOP 的功能完全集成到了 Spring事务管理、日志和其他各种特性的上下文中。
AOP 编程方面, Spring 提供了很多特性,例如 PointCut, Advice, Advisor, 粗略来说就是事务管理、日志和其他各种特性的切入地点。

容器

Spring 设计的核心是 org.springframework.beans 包,它的设计目标是与 JavaBean 组件一起使用。这个包通常不是由用户直接使用,而是由服务器将其用作其他多数功能的底层中介。下一个最高级抽象是BeanFactory接口,它是工厂设计模式的实现,允许通过名称创建和检索对象。BeanFactory 也可以管理对象之间的关系。Bean Factory 支持两个对象模型:
1、单态模型提供了具有特定名称的对象的共享实例,可以在查询时对其进行检索。Singleton是默认的也是最常用的对象模型。对于无状态服务对象很理想。
2、原型模型确保每次检索都会创建单独的对象。在每个用户都需要自己的对象时,原型模型最适合。bean 工厂的概念是 Spring 作为 IOC 容器的基础。IOC 将处理事情的责任从应用程序代码转移到框架。

IoC/DI

Maven搭建Spring项目

创建Maven项目,添加如下依赖。

 <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>5.3.21</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.6.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>5.3.21</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.3.21</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.3.21</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.3.21</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>5.3.21</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-orm</artifactId><version>5.3.21</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-expression</artifactId><version>5.3.21</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.3.21</version><scope>test</scope></dependency><!-- 以下不是Spring的jar --><!-- MySQL数据库驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.29</version></dependency><!-- druid数据库连接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.11</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.18.0</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.18.0</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>2.0.0-alpha7</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId><version>2.18.0</version><scope>test</scope></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>com.springsource.org.aspectj.weaver</artifactId><version>1.6.4.RELEASE</version></dependency><dependency><groupId>org.aopalliance</groupId><artifactId>com.springsource.org.aopalliance</artifactId><version>1.0.0</version></dependency><dependency><groupId>net.sourceforge.cglib</groupId><artifactId>com.springsource.net.sf.cglib</artifactId><version>2.2.0</version></dependency></dependencies>

控制反转(Inversion of Control,IoC)也称为依赖注入(Dependency Injection,DI),是面向对象编程中的一种设计理念,用来降低程序代码之间的耦合度。

IOC底层原理:工厂模式:

1、IoC思想基于IoC容器完成,IOC容器底层就是对象工厂。
2、Spring提供的IOC容器的两种实现方式:(两个接口)
(1)BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供开发人员使用。
加载配置文件时不会创建对象,在获取对象(使用)时才去创建对象。
(2)ApplicationContext:BeanFactory接口的子接口,提供了更多更强大的功能,一般由开发人员进行使用。
加载配置文件时就会把在配置文件中的对象进行创建。

eclipse中快捷键F4或Ctrl+T弹出如下图类的继承图:

什么是bean管理?
bean管理指的是两个操作:
1、Spring创建对象
2、Spirng注入属性

bean管理的操作有两种方式:
1、基于xml配置文件方式实现
2、基于注解方式实现

创建bean,User.java

package com.jack.spring.spring_demo.bean;public class User {public void add() {System.out.println("add");}}

创建xml文件,配置具体bean

<!--配置Bean;name属性和id属性一样,区别是name属性值可以使用特殊字符--><bean id="user" class="com.jack.spring.spring_demo.bean.User" />

1、在 spring 配置文件中,使用 bean 标签,标签里面添加对应属性,就可以实现对象的创建。
2、在 bean 标签有很多属性,介绍常用的属性
id 属性:唯一标识
class 属性:类全路径
3、创建对象的时候,默认也是执行无参构造方法完成对象的创建。

 @Testpublic void testUser() {/** Spring提供实现供IOC容器的两种方式:(两个接口)* 1、BeanFactory:IOC 容器基本实现,是 Spring 内部的使用接口,不提供开发人员使用* 加载配置文件的时候不会创建对象,在获取对象(使用)时才去创建对象* 2、ApplicationContext:BeanFactory 接口的子接口,提供更多更强大的功能,一般由开发人员进行使用,* 加载配置文件的时候就会把配置文件中的对象进行创建*///加载spring配置文件AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\spring_demo\\xml\\user1.xml");//获取bean对象User user = applicationContext.getBean("user", User.class);System.out.println(user);user.add();applicationContext.close();}

创建日志文件log4j2.xml

<?xml version="1.0" encoding="UTF-8"?><!--日志级别以及优先级排序: OFF>FATAL>ERROR>warn>INFO>DEBUG>TRACE>ALL--><!--Configuration后面的status用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,可以看到log4j2内部各种详细输出-->
<configuration status="info"><!--先定义所有的appender--><appenders><!--输出日志信息到控制台--><console name="Console" target="SYSTEM_OUT"><!--控制日志输出的格式--><PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36}-%msg%n"/></console></appenders><!--然后定义logger,只有定义logger并引入appender,appender才会生效--><!--root:用于指定项目的根日志,如果没有单独指定Logger,则会使用root作为默认的日志输出--><loggers><root level="info"><appender-ref ref= "Console"/></root></loggers></configuration>

基于xml配置文件方式操作bean

DI(依赖注入),就是注入属性。

setter方法注入

public void setName(String name) {this.name = name;
}
User user = new User();
user.setName("宋江");

1、创建类,定义属性和对应的 set 方法

/**
* 演示使用 set 方法进行注入属性
*/
public class Book {//创建属性private String  bname;private String  bauthor;//创建属性对应的 set 方法public void setBname(String bname) {this. bname = bname;}public void setBauthor(String bauthor) {this. bauthor = bauthor;}
}

2、在 spring 配置文件中配置对象创建,配置属性注入。

<!--2 set 方法注入属性-->
< bean  id= "book"  class= "com.jack.spring.Book"><!--使用 property 完成属性注入name:类里面属性名称value:向属性注入的值-->< property  name= "bname"  value="水浒传"/>< property  name= "bauthor"  value="施耐庵"/>
</ bean>

有参构造方法注入

1、创建类,定义属性,创建属性对应有参数构造方法。

/**
* 使用有参数构造注入
*/
public class Orders {//属性private String  oname;private String  address;//有参数构造public Orders(String oname,String address) {this. oname = oname;this. ad dress = address;}}

2、在 spring 配置文件中进行配置

<!--3 有参数构造注入属性-->
< bean  id= "orders"  class= "com.jack.spring.Orders">< constructor-arg  name= "oname"  value="电脑"/>< constructor-arg  name= "address"  value= "China"/>
</ bean>
User user = new User(1, "张三");
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--配置bean;name属性和id属性一样,区别是name属性值可以使用特殊字符--><bean id="user" class="com.jack.spring.spring_demo.bean.User" /><!--如何设置单实例还是多实例1、在spring配置文件bean标签里面有属性(scope)用于设置单实例还是多实例2、scope属性值(1)默认值,singleton,表示是单实例对象(2)prototype,表示是多实例对象singleton和prototype的区别1、singleton:单实例,prototype:多实例2、设置scope值是singleton时,加载spring配置文件时就会创建单实例对象设置scope值是prototype时,不是在加载spring配置文件时创建对象,在调用getBean方法时创建多实例对象--><!--set方法注入属性--><bean id="book" class="com.jack.spring.spring_demo.bean.Book" scope="prototype"> <!--prototype ['prəʊtətaɪp] n.原型;范例;雏形--><!--使用property完成属性注入--><property name="name" value="三国演义" /><property name="author" value="罗贯中" /><!--给属性赋值null--><!-- <property name="address" ><null/></property>--><!--属性值中包括特殊字符方式一:把<>进行转义;&lt &gt方式二:把带特殊符号内容写到CDATA中--><property name="address" >  <value><![CDATA[<<南京>>]]></value></property></bean><!--默认是无参构造方法注入;使用constructor-arg标签使用有参构造方法注入--><bean id="order" class="com.jack.spring.spring_demo.bean.Order"><constructor-arg name="name" value="computer" /><constructor-arg name="address" value="China" /><!--<constructor-arg index="0" value="computer"/>也可以使用index通过索引注入--></bean><!--p名称标签xmlns:p="http://www.springframework.org/schema/p"<bean id="book" class="com.jack.spring.Book"p:name="施耐庵"p:author="水浒传" />--></beans>
package com.jack.spring.spring_demo.bean;import lombok.AllArgsConstructor;import lombok.NoArgsConstructor;//@Data //set方法注入
@AllArgsConstructor //有参构造方法注入
@NoArgsConstructor
public class Book {private String name;private String author;private String address;public void testDemo(){System.out.println(name + "\n" + author + "\n" + address);}public void setName(String name) {this.name = name;}public void setAuthor(String author) {this.author = author;}public void setAddress(String address) {this.address = address;}public String getName() {return name;}public String getAuthor() {return author;}public String getAddress() {return address;}}
@Testpublic void testBook(){//加载spring配置文件AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\spring_demo\\xml\\user1.xml");//获取bean对象Book book = applicationContext.getBean("book", Book.class);Book book1 = applicationContext.getBean("book", Book.class);System.out.println(book.hashCode());System.out.println(book1.hashCode());System.out.println(book);System.out.println(book1);book.testDemo();applicationContext.close();}

p名称空间注入

使用p名称空间注入属性,可以简化基于xml配置方式。

第一步:在配置文件中添加p名称空间。

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

第二步:进行属性注入。

<bean id="user2" class="com.jack.spring.spring_demo.bean.User" p:id="2" p:username="卢俊义" p:password="lujunyi" />

特殊处理

1 、字面量
(1)属性值为null

<property  name= "password"><null/>
</property>

(2)属性值包含特殊符号
1、把<>进行转义 &lt; &gt;
2、把带特殊符号的内容写到CDATA。

<property  name= "address"><value><![CDATA[<<南京>>]]></value>
</property>

MVC模式:用spring创建对象、注入属性

创建User实体类User.java

package com.jack.spring.spring_demo.bean;public class User {private int id;private String username;private String password; public User() {}public User(int id, String username, String password) {this.id = id;this.username = username;this.password = password;}public void setId(int id) {this.id = id;}public void setUsername(String username) {this.username = username;}public void setPassword(String password) {this.password = password;}public void showInformation() {System.out.println(id + "\t" + username + "\t" + password);}@Overridepublic String toString() {return "User [id=" + id + ", username=" + username + ", password=" + password + "]";}}

创建接口UserDao.java

package com.jack.spring.spring_demo.dao;public interface UserDao {void update();
}

创建接口UserDao的实现类UserDaoImpl.java

package com.jack.spring.spring_demo.dao;public class UserDaoImpl implements UserDao{@Overridepublic void update() {System.out.println("接口UserDao的实现类UserDaoImpl里的update方法!");}}

创建UserService.java

package com.jack.spring.spring_demo.service;import com.jack.spring.spring_demo.dao.UserDao;public class UserService {//UserDao类型属性private UserDao userDao;public void setUserDao(UserDao userDao) {this.userDao = userDao;}public void add() {System.out.println("UserService类里的add方法!");//创建UserDao对象;原始方式//UserDao userDao = new UserDaoImpl();userDao.update();}}

创建配置文件

<?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"><!--service和dao对象创建--><bean id="userService" class="com.jack.spring.spring_demo.service.UserService"><!--注入userDao对象name属性:类里面的属性名称ref属性:创建userDao对象bean标签的id值--><property name="userDao" ref="userDaoImpl1" /></bean><bean id="userDaoImpl1" class="com.jack.spring.spring_demo.dao.UserDaoImpl"/></beans>

test

@Testpublic void testUser1() {AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext("com/jack/spring/spring_demo/xml/user.xml");UserService userService = applicationContext.getBean("userService", UserService.class);userService.add();applicationContext.close();}

print

UserService类里的add方法!
接口UserDao的实现类UserDaoImpl里的update方法!

Spring创建对象;注入属性;内部bean

一对多

属性注入、赋值

1、一对多关系:部门和员工
一个部门有多个员工,一个员工属于一个部门
部门是一,员工是多
2、在实体类之间表示一对多关系,员工表示所属部门,使用对象类型属性进行表示

创建bean
Department.java

package com.jack.spring.spring_demo.bean;public class Department {private String departmentName;public void setDepartmentName(String departmentName) {this.departmentName = departmentName;} public void departmentShowInformation() {System.out.println("类Department中的departmentShowInformation方法" + ": departmentName="+ departmentName);}@Overridepublic String toString() {return "Department [departmentName=" + departmentName + "]";}}

Employee.java

package com.jack.spring.spring_demo.bean;public class Employee {private String employeeName;private String gender;private Department department; //员工属于某一个部门;使用对象的形式表示public void setEmployeeName(String employeeName) {this.employeeName = employeeName;}public void setGender(String gender) {this.gender = gender;}public void setDepartment(Department department) {this.department = department;}public void employeeShowInformation() {//System.out.println(employeeName + "\t" + gender + "\t" + department.getDepartmentName());System.out.println(employeeName + "\t" + gender + "\t" + department);}}

employee.xml

<?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 --><bean id="employee" class="com.jack.spring.spring_demo.bean.Employee"><property name="employeeName" value="宋江" /><property name="gender" value="男" /><!-- 设置对象类型属性 --><property name="department"><bean class="com.jack.spring.spring_demo.bean.Department"><property name="departmentName" value="保安部"/></bean></property></bean></beans>

test

@Testpublic void testEmployee() {AbstractApplicationContext abstractApplicationContext = new ClassPathXmlApplicationContext("com/jack/spring/spring_demo/xml/employee.xml");Employee employee = abstractApplicationContext.getBean("employee", Employee.class);abstractApplicationContext.close();employee.employeeShowInformation();}

级联赋值

写法一
<?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="employee" class="com.jack.spring.spring_demo.bean.Employee"><property name="employeeName" value="卢俊义" /><property name="gender" value="男" /><!--<property name="dept"><bean class="com.jack.spring.spring_demo.bean.Department" ><property name="departmentName" value="保安部"/></bean></property>--><property name="department" ref="department"/></bean><bean id="department" class="com.jack.spring.spring_demo.bean.Department"><property name="departmentName" value="财务部" /></bean></beans>

test

@Testpublic void testEmployee1() {AbstractApplicationContext abstractApplicationContext = new ClassPathXmlApplicationContext("com/jack/spring/spring_demo/xml/employee1.xml");Employee employee = abstractApplicationContext.getBean("employee", Employee.class);abstractApplicationContext.close();employee.employeeShowInformation();}

print

卢俊义  男   Department [departmentName=财务部]
写法二

在Employee.java中添加department的get方法

public Department getDepartment() {return department;}

创建employee2.xml

<?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="employee" class="com.jack.spring.spring_demo.bean.Employee"><property name="employeeName" value="吴用" /><property name="gender" value="男" /><!--<property name="dept"  ><bean class="com.jack.spring.bean.Department" ><property name="departName" value="保安部"/></bean></property>--><property name="department" ref="department"/><property name="department.departmentName" value="技术部" /></bean><bean id="department" class="com.jack.spring.spring_demo.bean.Department"><!-- <property name="departmentName" value="财务部" /> --></bean></beans>

test

@Testpublic void testEmployee2() {AbstractApplicationContext abstractApplicationContext = new ClassPathXmlApplicationContext("com/jack/spring/spring_demo/xml/employee2.xml");Employee employee = abstractApplicationContext.getBean("employee", Employee.class);abstractApplicationContext.close();employee.employeeShowInformation();}

print

吴用   男   Department [departmentName=技术部]

注入集合类型属性

创建实体类Student.java

package com.jack.spring.collection.bean;import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;import com.jack.spring.factory_bean.bean.Course;public class Student {//数组类型属性private String[] courses;//List集合类型属性private List<String> list;//Set集合类型属性private Set<String> set;//map集合类型属性private Map<String, String> map;//学生所学的多门课程private List<Course> listCourse;public void setCourses(String[] courses) {this.courses = courses;}public void setList(List<String> list) {this.list = list;}public void setSet(Set<String> set) {this.set = set;}public void setMap(Map<String, String> map) {this.map = map;}public void setListCourse(List<Course> listCourse) {this.listCourse = listCourse;}public void print() {System.out.println(Arrays.toString(courses));System.out.println(list);System.out.println(set);System.out.println(map);System.out.println(listCourse);}}

创建实体类Course.java

package com.jack.spring.collection.bean;//课程类
public class Course {private String courseName; //课程名称public void setCourseName(String courseName) {this.courseName = courseName;}@Overridepublic String toString() {return "Course [courseName=" + courseName + "]";}}

创建配置文件student.xml

<?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"></beans>

注入数组类型属性

    <bean id="student" class="com.jack.spring.collection.bean.Student"><!-- 数组类型属性注入 --><property name="courses"><array><value>Java</value><value>MySQL</value><value>oracle</value></array><!-- 数组类型注入属性也可以使用list标签 --><!-- <list><value>Java</value><value>MySQL</value><value>oracle</value></list> --></property></bean>

test

@Testpublic void testStudent() {AbstractApplicationContext abstractApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\collection\\xml\\student.xml");Student student = abstractApplicationContext.getBean("student", Student.class);abstractApplicationContext.close();student.print();}

注入List集合类型属性

    <bean id="student" class="com.jack.spring.collection.bean.Student"><!--list类型属性注入--><property name="list"><list><value>宋江</value><value>李逵</value><value>吴用</value></list></property></bean>

注入Set集合类型属性

 <bean id="student" class="com.jack.spring.collection.bean.Student"><!--set类型属性注入--><property name="set" ><set><value>MySQL</value><value>Redis</value><value>Java</value></set></property></bean>

注入Map集合类型属性

 <bean id="student" class="com.jack.spring.collection.bean.Student"><!--map类型属性注入--><property name="map"><map><entry key="JavaKey" value="JavaValue"/><entry key="redisKey" value="redisValue"/><entry key="oracleKey" value="oracleValue"/></map></property></bean>

在集合里面设置对象类型值

 <bean id="student" class="com.jack.spring.collection.bean.Student"><!--注入List类型属性,但是集合中的value是对象--><property name="listCourse"><list><ref bean="course" /><ref bean="course1" /><ref bean="course2" /></list></property></bean><!--创建course对象--><bean id="course" class="com.jack.spring.collection.bean.Course"><property name="courseName" value="Java" /></bean><bean id="course1" class="com.jack.spring.collection.bean.Course"><property name="courseName" value="maria" /></bean><bean id="course2" class="com.jack.spring.collection.bean.Course"><property name="courseName" value="MyBatis" /></bean>

完整的xml文件(student.xml)

<?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="student" class="com.jack.spring.collection.bean.Student"><!-- 数组类型属性注入 --><property name="courses"><array><value>Java</value><value>MySQL</value><value>oracle</value></array><!-- 数组类型注入属性也可以使用list标签 --><!-- <list><value>Java</value><value>MySQL</value><value>oracle</value></list> --></property><!--list类型属性注入--><property name="list"><list><value>宋江</value><value>李逵</value><value>吴用</value></list></property><!--set类型属性注入--><property name="set" ><set><value>MySQL</value><value>Redis</value><value>Java</value></set></property><!--map类型属性注入--><property name="map"><map><entry key="JavaKey" value="JavaValue"/><entry key="redisKey" value="redisValue"/><entry key="oracleKey" value="oracleValue"/></map></property><!--注入List类型属性,但是集合中的value是对象--><property name="listCourse"><list><ref bean="course" /><ref bean="course1" /><ref bean="course2" /></list></property></bean><!--创建course对象--><bean id="course" class="com.jack.spring.collection.bean.Course"><property name="courseName" value="Java" /></bean><bean id="course1" class="com.jack.spring.collection.bean.Course"><property name="courseName" value="maria" /></bean><bean id="course2" class="com.jack.spring.collection.bean.Course"><property name="courseName" value="MyBatis" /></bean></beans>

提取List类型属性注入

在spring配置文件中引入名称空间util。
beans标签添加属性:
xmlns:util=“http://www.springframework.org/schema/util”
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd

创建student1.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:util="http://www.springframework.org/schema/util"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"><!--提取List类型属性注入--><util:list id="studentList"><value>宋江</value><value>卢俊义</value><value>吴用</value></util:list><bean id="student" class="com.jack.spring.collection.bean.Student"><property name="list" ref="studentList"/></bean></beans>

test

 @Testpublic void testStudent1() {AbstractApplicationContext abstractApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\collection\\xml\\student1.xml");Student student = abstractApplicationContext.getBean("student", Student.class);abstractApplicationContext.close();student.print();}

IoC操作FactoryBean

Spring有两种类型bean,一种普通bean,另外一种工厂bean(FactoryBean )。

普通bean:在配置文件中定义bean类型就是返回类型。

工厂bean:在配置文件定义bean类型可以和返回类型不一样。
第一步:创建类,让这个类作为工厂bean,实现接口FactoryBean。
第二步:实现接口里面的方法,在实现的方法中定义返回的bean类型。

创建Course.java

package com.jack.spring.factory_bean.bean;//课程
public class Course {private String courseName; //课程名称public void setCourseName(String courseName) {this.courseName = courseName;}@Overridepublic String toString() {return "Course [courseName=" + courseName + "]";}}

创建类MyBean.java,让这个类作为工厂bean,实现接口FactoryBean。

package com.jack.spring.factory_bean.bean;import org.springframework.beans.factory.FactoryBean;public class MyBean implements FactoryBean<Course> {@Overridepublic Course getObject() {Course course = new Course();course.setCourseName("java");return course;}@Overridepublic Class<?> getObjectType() {return null;}@Overridepublic boolean isSingleton() {return false;}}

创建配置文件bean.xml

<?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="myBean" class="com.jack.spring.factory_bean.bean.MyBean"/></beans>

test

@Testpublic void testBean(){AbstractApplicationContext abstractApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\factory_bean\\xml\\bean.xml");Course course = abstractApplicationContext.getBean("myBean", Course.class);abstractApplicationContext.close();System.out.println(course);}

bean的作用域

在Spring里,默认bean是单实例对象。

如何设置单实例与多实例?
1、在spring配置文件bean标签里有属性(scope)用于设置单实例还是多实例。
2、scope属性值
第一个值:默认值,singleton,表示是单实例对象。
第二个值:prototype,表示是多实例对象。

singleton和prototype的区别?
1、singleton单实例,prototype多实例。
2、设置scope值是singleton时,加载spring配置文件时就会创建单实例对象。
设置scope值是prototype时,不是在加载spring配置文件的时候创建对象,而是在调用getBean方法时创建多实例对象。

 <!--set方法注入属性--><bean id="book" class="com.jack.spring.spring_demo.bean.Book" scope="singleton"> <!--prototype ['prəʊtətaɪp] n.原型;范例;雏形--><!--使用property完成属性注入--><property name="name" value="三国演义" /><property name="author" value="罗贯中" /><!--给属性赋值null--><!-- <property name="address" ><null/></property>--><!--属性值中包括特殊字符方式一:把<>进行转义;&lt &gt方式二:把带特殊符号内容写到CDATA中--><property name="address" >  <value><![CDATA[<<南京>>]]></value></property></bean>
@Testpublic void testBook(){//加载spring配置文件AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\spring_demo\\xml\\user1.xml");//获取bean对象Book book = applicationContext.getBean("book", Book.class);Book book1 = applicationContext.getBean("book", Book.class);System.out.println(book.hashCode());System.out.println(book1.hashCode());System.out.println(book);System.out.println(book1);book.testDemo();applicationContext.close();}

print:

22069592
22069592
com.jack.spring.spring_demo.bean.Book@150c158
com.jack.spring.spring_demo.bean.Book@150c158
三国演义
罗贯中
<<南京>>

当设置scope="singleton"时,输出结果:

22069592
1160003871
com.jack.spring.spring_demo.bean.Book@150c158
com.jack.spring.spring_demo.bean.Book@4524411f
三国演义
罗贯中
<<南京>>

bean的生命周期

1、生命周期:从对象创建到对象销毁的过程。
2、bean的生命周期,共有五步:
(1)通过无参数构造方法创建bean实例。
(2)调用set方法为bean实例的属性设置值和对其他bean引用。
(3)调用bean的初始化的方法(需要进行配置初始化的方法)。
(4)使用bean对象(对象获取到了)。
(5)当容器关闭的时候,调用bean的销毁方法(需要进行配置销毁的方法)

bean的后置处理器,bean生命周期有七步:
(1)通过无参数构造方法创建bean实例。
(2)调用set方法为bean实例的属性设置值和对其他bean引用。
(3)把bean实例传递bean后置处理器的方法postProcessBeforeInitialization
(4)调用bean的初始化的方法(需要进行配置初始化的方法)。
(5)把bean实例传递bean后置处理器的方法postProcessAfterInitialization
(6)使用bean对象(对象获取到了)。
(7)当容器关闭的时候,调用bean的销毁方法(需要进行配置销毁的方法)

创建User.java

package com.jack.spring.bean_lifecycle.bean;public class User {private String userName;//无参数构造器public User(){System.out.println("bean生命周期:第一步:执行无参数构造方法创建bean实例");}public void setUserName(String userName){this.userName = userName;System.out.println("bean生命周期:第二步:调用set()设置属性值");}//创建执行的初始化的方法public void initializeMethod() {System.out.println("bean生命周期:第三步:执行初始化方法");}//创建执行的销毁的方法public void destroyMethod() {System.out.println("bean的生命周期:第五步:执行销毁方法");}@Overridepublic String toString() {return "User [name=" + userName + "]";}}

创建MyBeanPostProcessor.java
类MyBeanPostProcessor实现BeanPostProcessor接口

package com.jack.spring.bean_lifecycle.bean;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;//后置处理器
public class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("在初始化执行之前执行的方法");return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("在初始化执行之后执行的方法");return bean;}}

创建bean.xml配置文件

<?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="com.jack.spring.bean_lifecycle.bean.User" init-method="initializeMethod" destroy-method="destroyMethod"><property name="userName" value="phone"/></bean><!--配置后置处理器--><bean id="myBeanPostProcessor" class="com.jack.spring.bean_lifecycle.bean.MyBeanPostProcessor"/></beans>

test

@Testpublic void testBeanLifeCycle(){//加载spring配置文件ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\bean_lifecycle\\xml\\bean.xml");//获取bean对象User user = classPathXmlApplicationContext.getBean("user", User.class);System.out.println("bean生命周期:第四步:获取bean创建的实例对象:" + user);//手动销毁bean实例classPathXmlApplicationContext.close();}

自动装配

自动装配:根据指定的装配规则(属性名称或属性类型),Spring自动将匹配的属性值进行注入

创建Department.java

package com.jack.spring.automated_assembly.bean;public class Department {}

创建Employee.java

package com.jack.spring.automated_assembly.bean;public class Employee {private Department department;public void setDepartment(Department department) {this.department = department;}public void testMethod(){System.out.println(department);}@Overridepublic String toString() {return "Employee [department=" + department + "]";}}

创建bean.xml配置文件

<?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"><!-- setter手动注入 --><bean id="employee" class="com.jack.spring.automated_assembly.bean.Employee"><property name="department" ref="department"/></bean><!--配置自动装配bean标签属性:autowireautowire属性常用值:byName:根据属性名称注入,注入值的bean的id值和类属性名称一样byType:根据属性类型注入--><bean id="department" class="com.jack.spring.automated_assembly.bean.Department"/><bean id="employee1" class="com.jack.spring.automated_assembly.bean.Employee" autowire="byType"><!-- <property name="department" ref="department"/> --></bean><bean id="employee2" class="com.jack.spring.automated_assembly.bean.Employee" autowire="byName"><!-- <property name="department" ref="department"/> --></bean></beans>

test

package com.jack.spring.automated_assembly.text;import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;import com.jack.spring.automated_assembly.bean.Employee;public class TestAutomatedAssembly {@Testpublic void testAutomatedAssembly() {ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\automated_assembly\\xml\\bean.xml");Employee employee = classPathXmlApplicationContext.getBean("employee2", Employee.class);classPathXmlApplicationContext.close();System.out.println(employee);}}

引入外部属性文件配置数据库连接池

配置Druid(德鲁伊)数据库连接池

引入Druid数据库连接池jar包。

在配置文件中直接配置连接池

<!--直接配置连接池<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/test_jack"/><property name="username" value="root"/><property name="password" value="root"/></bean>-->

引入外部属性文件配置数据库连接池

创建外部属性文件jdbc.properties

jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test_jack
jdbc.username=root
jdbc.password=root

引入context名称空间
xmlns:context=“http://www.springframework.org/schema/context”
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd

创建druid.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!--直接配置连接池<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/test_jack"/><property name="username" value="root"/><property name="password" value="root"/></bean>--><!--引入外部属性文件--><context:property-placeholder location="classpath:jdbc.properties"/><!--配置连接池--><bean id="dataSource3" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${jdbc.driverClass}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></bean></beans>

基于注解方式操作bean

Spring 针对Bean管理中创建对象提供的注解:
1、@Component
2、@Service
3、@Controller
4、@Repository

上面四个注解的功能是一样的,都可以用来创建bean实例。

组件扫描方式

创建bean.xml配置文件:
添加:
xmlns:context=“http://www.springframework.org/schema/context”
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!--开启组件扫描1、如果扫描多个包,多个包使用逗号隔开2、扫描包上层目录--><context:component-scan base-package="com.jack.spring.annotation_bean"/></bean>

创建接口UserDao

package com.jack.spring.annotation_bean.dao;public interface UserDao {void add();}

创建类UserDaoImpl,实现UserDao接口。

package com.jack.spring.annotation_bean.dao;import org.springframework.stereotype.Service;@Service(value = "userDaoImpl")
public class UserDaoImpl implements UserDao {@Overridepublic void add() {System.out.println("类UserDaoImpl实现的UserDao中的add方法");}}

创建类UserService

package com.jack.spring.annotation_bean.service;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;import com.jack.spring.annotation_bean.dao.UserDao;import javax.annotation.Resource;//@Component(value="userService") //相当于spring配置文件中的<bean id="userService" class="com.jack.spring.annotation_bean.service.UserService"/>
@Service
//@Controller
//@Repository
public class UserService {//    @Autowired //根据类型注入
//    @Qualifier(value = "userDaoImpl1") //根据名称注入,要和@Autowired一起使用
//    private UserDao userDao;//@Resource //根据类型注入//private UserDao userDao;@Resource(name = "userDaoImpl") //根据名称注入private UserDao userDao;@Value(value = "这是类UserService里属性username的值")private String username;public void add() {System.out.println("类UserService的add方法" + "======" + username);userDao.add();}}

test

@Testpublic void testAnnotation(){ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\annotation_bean\\xml\\bean.xml");UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);classPathXmlApplicationContext.close();System.out.println(userService);userService.add();}

完全注解方式

创建类SpringConfig

package com.jack.spring.annotation_bean.config;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;@Configuration //作为配置类,替代xml配置文件
@ComponentScan(basePackages = {"com.jack.spring.annotation_bean"})
public class SpringConfig {}

test

@Testpublic void testSpringConfig(){AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);UserService userService = annotationConfigApplicationContext.getBean("userService", UserService.class);annotationConfigApplicationContext.close();System.out.println(userService);userService.add();}

基于注解方式进行属性注入

1、@Autowired:根据属性类型进行自动装配
第一步:创建service和dao对象,在service和dao实现类UserDaoImpl上添加创建对象注解。
第二步:在service中注入dao对象,在service类中添加dao类型属性,在属性上面使用注解@Service

@Service
public class UserService {//定义 dao 类型属性//不需要添加 set 方法//添加注入属性注解@Autowiredprivate  UserDao  userDao; ;public void add() {System. out .println( "service add.......");userDao.add();}}

2、@Qualifier:根据名称进行注入。
@Qualifier注解和上面@Autowired 一起使用。

//定义dao类型属性
//不需要添加set方法
//添加注入属性注解
@Autowired //根据类型进行注入
@Qualifier(value =  "userDaoImpl1")  //根据名称进行注入
private UserDao  userDao;

3、@Resource:可以根据类型注入,可以根据名称注入

//@Resource //根据类型进行注入
@Resource(name =  "userDaoImpl1") //根据名称进行注入
private UserDao  userDao;

4、@Value:注入普通类型属性

@Value(value =  "abc")
private String  name;

AOP

AOP(Aspect Oriented Programming,面向切面编程)是一种设计思想,是软件设计领域中的面向切面编程,它是OOP(Object Oriented Programming,面向对象编程)的一种补充和完善。它以通过预编译方式和运行期动态代理方式,实现在不修改源代码的情况下给程序动态统一添加额外功能的一种技术。

oriented ['ɔːrɪəntɪd] adj.以…为方向的;以…为目的的

什么是AOP?
面向切面(方面)编程,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高开发的效率。

底层原理

AOP底层使用动态代理,有两种方式:
1、使用JDK动态代理
创建接口实现类代理对象,增强类的方法。
2、使用CGLIB动态代理
创建子类的代理对象,增强类的方法。

使用JDK动态代理

使用Proxy类里面的方法创建代理对象。

java.lang.reflect Class Proxy
public class Proxy extends Object implements Serializable

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。参数loader - 类加载器来定义代理类interfaces - 代理类实现的接口列表;增强方法所在的类,这个类实现的接口,支持多个接口。h - 调度方法调用的调用处理函数;实现这个接口InvocationHandler,创建代理对象,写增强的部分。结果:具有由指定的类加载器定义并实现指定接口的代理类的指定调用处理程序的代理实例

创建接口

package com.jack.spring.aop.proxy.dao;public interface UserDao {int add(int number, int numberOther);String update(String id);
}

创建接口实现类

package com.jack.spring.aop.proxy.dao;public class UserDaoImpl implements UserDao {@Overridepublic int add(int number, int numberOther) {//System.out.println("a");System.out.println("类UserDaoImpl里的add(int number, int numberOther)方法执行了");//System.out.println("b");return number + numberOther;}@Overridepublic String update(String id) {System.out.println("类UserDaoImpl里的update(String id)方法执行了");return id;}}

创建代理对象

package com.jack.spring.aop.proxy.invocation_handler;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;public class MyInvocationHandler implements InvocationHandler {private final Object object;public MyInvocationHandler(Object object) {System.out.println("构造方法被调用!");this.object = object;}private int count = 0;@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {++count ;System.out.println("增强的业务,方法执行前!");System.out.println(method.getName());System.out.println(Arrays.toString(args)); //传递的参数Object resultObject = method.invoke(object, args); //被增强的方法System.out.println("增强的业务,方法执行后!");System.out.println("count:" + count);System.out.println(object);return resultObject;}}

使用Proxy类创建接口代理对象

package com.jack.spring.aop.proxy.jdk_proxy;import java.lang.reflect.Proxy;import com.jack.spring.aop.proxy.dao.UserDao;
import com.jack.spring.aop.proxy.dao.UserDaoImpl;
import com.jack.spring.aop.proxy.invocation_handler.MyInvocationHandler;/*** @author Jack* @see com.jack.spring.aop.proxy.jdk_proxy* @since JDK1.8*/
//JDK动态代理
public class JDKProxy {public static void main(String[] args) {/*public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。参数loader - 类加载器来定义代理类interfaces - 代理类实现的接口列表h - 调度方法调用的调用处理函数结果具有由指定的类加载器定义并实现指定接口的代理类的指定调用处理程序的代理实例*///创建接口实现类的代理对象Class<?>[] interfaces = {UserDao.class};/*Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {return null;}});*/UserDao userDao = new UserDaoImpl();UserDao userDao1 = (UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new MyInvocationHandler(userDao));int result = userDao1.add(1, 2);System.out.println("result:" + result);}}

创建接口

package com.jack.spring.proxy.demo_001.dao;public interface Target {int sum(int number, int otherNumber);String getName(String name);}

创建接口实现类

package com.jack.spring.proxy.demo_001.dao;public class TargetImpl implements Target{@Overridepublic int sum(int number, int otherNumber) {System.out.println("两个数的和是:");return number + otherNumber;}@Overridepublic String getName(String name) {return name;}}

创建通知代码

package com.jack.spring.proxy.demo_001.advice;public class Advice {public void before() {System.out.println("前置方法执行!");}    public void after() {System.out.println("后置方法执行!");}}

test

package com.jack.spring.proxy.demo_001.text;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;import org.junit.Test;import com.jack.spring.proxy.demo_001.advice.Advice;
import com.jack.spring.proxy.demo_001.dao.Target;
import com.jack.spring.proxy.demo_001.dao.TargetImpl;public class TestProxy {@Testpublic void testTarget() {TargetImpl targetImpl = new TargetImpl();Advice advice = new Advice();Target target = (Target)Proxy.newProxyInstance(targetImpl.getClass().getClassLoader(),targetImpl.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("参数:" + Arrays.asList(args));System.out.println("方法名称" + method.getName());advice.before();Object object = method.invoke(targetImpl, args);advice.after();System.out.println("参数:" + Arrays.asList(args));System.out.println("方法名称" + method.getName());return object;}});int sum = target.sum(1, 2);System.out.println(sum);System.out.println("================");String name = target.getName("宋江");System.out.println(name);}}

AOP术语

1、连接点:类里面哪些方法可以被增强,这些方法称为连接点。
2、Pointcut(切入点):实际被真正增强的方法,称为切入点。目标对象中,已经被增强的方法。调用这几个方法之前、之后或者抛出异常时干点什么,那么就用切入点来定义这几个方法。
3、Advice(通知/增强):实际增强的逻辑部分称为通知(增强)。增强方法的代码、想要的功能。
4、Target(目标对象):被代理对象,被通知的对象,被增强的类对象。
5、Weaving(织入):将通知应用到连接点形成切入点的过程。
6、Proxy(代理):将通知织入到目标对象之后形成的代理对象。
7、aspect(切面):切入点+通知。通知(Advice)说明了干什么的内容(即方法体代码)和什么时候干(什么时候通过方法名中的before,after,around等就能知道),二切入点说明了在哪干。

通知的类型:
前置通知
后置通知
环绕通知
异常通知
最终通知

4、切面:把通知应用到切入点的过程。

AOP操作

Spring框架一般都是基于AspectJ 实现AOP。

AspectJ不是Spring组成部分,独立 AOP 框架,一般把AspectJ和Spirng框架一起使用,进行AOP操作。

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

基于AspectJ实现AOP操作的两种方式:
1、基于xml配置文件实现。
2、基于注解方式实现。

在项目工程里面引入 AOP的相关依赖

切入点表达式

切入点表达式作用:指定对哪个类里面的哪个方法进行增强。
语法结构:

execution([权限修饰符] [返回类型] [类全路径] [方法名称]([参数列表]))

举例1:对com.company.dao.UserDao类里面的add方法进行增强。

execution(* com.company.dao.UserDao.add(..))

举例2:对 com.company.dao.UserDao类里面的所有的方法进行增强。

execution(* com.company.dao.UserDao.*(..))

举例3:对com.company.dao包里所有类,类里面所有方法进行增强。

execution(* com.company.dao.*.*(..))

AOP操作

AspectJ注解

1、创建类,在类里面定义方法。
User.java

2、创建增强类(编写增强逻辑)。
在增强类里面,创建方法,让不同方法代表不同通知类型。

3、(1)进行通知的配置:在 spring 配置文件中,开启注解扫描。
(2)使用注解创建 User 和 UserProxy 对象
(3)在增强类上面添加注解@Aspect

4、配置不同类型的通知:在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置。
5、相同的切入点抽取

 //相同切入点抽取@Pointcut(value = "execution(* com.jack.spring.aop.proxy_annotation.User.add(..))")public void point(){}

6、有多个增强类对同一个方法进行增强,可以设置增强类的优先级。
在增强类上面添加注解 @Order(数字类型值),数字类型值越小优先级越高。

package com.jack.spring.aop.proxy_annotation;import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;@Component
@Aspect
@Order(1)
public class UserProxy1 {//前置通知@Before(value = "execution(* com.jack.spring.aop.proxy_annotation.User.add(..))")public void before() {System.out.println("UserProxy1:前置通知:@Before");}}

创建类,在类里面定义方法。

package com.jack.spring.aop.proxy_annotation;import org.springframework.stereotype.Component;//被增强的类
@Component
public class User {public void add() {//int i = 1/0; //演示异常通知System.out.println("add");}}

创建增强类(编写增强逻辑)。
在增强类里面,创建方法,让不同方法代表不同通知类型。

package com.jack.spring.aop.proxy_annotation;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;//增强类
@Component //创建对象
@Aspect //表示生成代理对象
@Order(3)
public class UserProxy {//相同切入点抽取@Pointcut(value = "execution(* com.jack.spring.aop.proxy_annotation.User.add(..))")public void point(){}//前置通知@Before(value = "point()")public void before() {System.out.println("前置通知:@Before");}//后置通知(返回通知)@AfterReturning(value = "point()")public void afterReturning() {System.out.println("后置通知:@AfterReturning");}//异常通知@AfterThrowing(value = "point()")public void afterThrowing() {System.out.println("异常通知:@AfterThrowing");}//最终通知@After(value = "point()")public void after() {System.out.println("最终通知:@After");}//环绕通知@Around(value = "point()")public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {System.out.println("环绕通知之前:@Around");//被增强的方法执行proceedingJoinPoint.proceed();System.out.println("环绕通知之后:@Around");return null;}}

配置文件:开启注解扫描。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:contetxt="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"><!--开启注解扫描--><contetxt:component-scan base-package="com.jack.spring.aop.proxy_annotation"/><!--开启Aspect生成代理对象--><aop:aspectj-autoproxy/></beans>

test

package com.jack.spring.aop.proxy_annotation.text;import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;import com.jack.spring.aop.proxy_annotation.User;public class TextProxyAnnotation {@Testpublic void testAOP() {ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\aop\\proxy_annotation\\xml\\bean.xml");User user = classPathXmlApplicationContext.getBean("user", User.class);classPathXmlApplicationContext.close();user.add();}}

完全使用注解开发:
创建配置类,不需要创建xml配置文件

@Configuration
@ComponentScan(basePackages = { "com.jack.spring.aop.proxy_annotation"})
@EnableAspectJAutoProxy(proxyTargetClass=true)
public class ConfigAop {}

AOP操作(AspectJ配置文件)

1、创建两个类,增强类和被增强类,创建方法。
2、在Spring配置文件中创建两个类对象

<!--创建对象-->
<bean id= "user" class="com.jack.spring.aop.proxy_annotation.User"></bean>
<bean id= "userProxy" class="com.jack.spring.aop.proxy_annotation.UserProxy"></bean>

3 、在Spring配置文件中配置切入点。

<!--配置AOP增强-->
<aop:config><!--切入点--><aop:pointcut id="p" expression="execution(* com.jack.spring.aop.proxy_annotation.User.add(..))"/><!--配置切面--><aop:aspect ref="UserProxy"><!--增强作用在具体的方法上--><aop:before method="before" pointcut-ref="p"/></aop:aspect></aop:config>
package com.jack.spring.aop.proxy_xml;import org.springframework.stereotype.Component;@Component
public class Book {public void buy() {System.out.println("buy");}
}
package com.jack.spring.aop.proxy_xml;import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;@Component
@Aspect
@Order(1)
public class BookProxy {public void before(){System.out.println("before");}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"><!--创建对象--><bean id="book2" class= "com.jack.spring.aop.proxy_xml.Book"/><bean id="bookProxy" class= "com.jack.spring.aop.proxy_xml.BookProxy"/><!--配置aop增强--><aop:config><!--切入点--><aop:pointcut id= "p" expression= "execution(* com.jack.spring.aop.proxy_xml.Book.buy(..))"/><!--配置切面--><aop:aspect ref="bookProxy"><!--增强作用在具体的方法上--><aop:before method="before" pointcut-ref="p"/></aop:aspect></aop:config></beans>
package com.jack.spring.aop.proxy_xml.text;import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;import com.jack.spring.aop.proxy_xml.Book;public class TextProxyXML {@Testpublic void testProxyXML(){ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\aop\\proxy_xml\\xml\\bean.xml");Book book = classPathXmlApplicationContext.getBean("book2", Book.class);classPathXmlApplicationContext.close();book.buy();}
}

JdbcTemplate

Spring框架对JDBC进行封装,使用JdbcTemplate方便实现对数据库操作

引入相关jar包

创建jdbc.properties外部属性文件。

jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test_jack
jdbc.username=root
jdbc.password=root

在Spring配置文件中引入jdbc.properties外部属性文件并配置数据库连接池。

 <!--引入外部属性文件--><context:property-placeholder location="classpath:jdbc.properties"/><!--配置数据库连接池--><!-- DruidDataSource dataSource = new DruidDataSource(); --><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"><!--dataSource.setDriverClassName("com.mysql.jdbc.Driver"); set方法注入--><property name="driverClassName" value="${jdbc.driverClass}" /><property name="url" value="${jdbc.url}" /><property name="username" value="${jdbc.username}" /><property name="password" value="${jdbc.password}" /></bean>

配置JdbcTemplate对象,注入DataSource。

<!--jdbcTemplate对象--><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><!--注入dataSource--><property name="dataSource" ref="dataSource"/></bean>

开启组件扫描。

<!--开启组件扫描;使用注解方法进行注入--><context:component-scan base-package="com.jack.spring.jdbc_template"/>

完整Spring配置xml文件。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!--引入外部属性文件--><context:property-placeholder location="classpath:jdbc.properties"/><!--配置数据库连接池--><!-- DruidDataSource dataSource = new DruidDataSource(); --><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"><!--dataSource.setDriverClassName("com.mysql.jdbc.Driver"); set方法注入--><property name="driverClassName" value="${jdbc.driverClass}" /><property name="url" value="${jdbc.url}" /><property name="username" value="${jdbc.username}" /><property name="password" value="${jdbc.password}" /></bean><!--jdbcTemplate对象--><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><!--注入dataSource--><property name="dataSource" ref="dataSource"/></bean><!--开启组件扫描;使用注解方法进行注入--><context:component-scan base-package="com.jack.spring.jdbc_template"/></beans>

创建实体类User.java

package com.jack.spring.jdbc_template.entity;import java.io.Serializable;public class User implements Serializable{private static final long serialVersionUID = 1L;private Integer id;private String username;private String password;private Integer age;private String email;public User() {super();}public User(String username, String password, Integer age, String email) {super();this.username = username;this.password = password;this.age = age;this.email = email;}public User(Integer id, String username, String password, Integer age, String email) {super();this.id = id;this.username = username;this.password = password;this.age = age;this.email = email;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}@Overridepublic String toString() {return "User [id=" + id + ", username=" + username + ", password=" + password + ", age=" + age + ", email=" + email + "]";}}

创建UserDao.java

public interface UserDao {}

创建UserDaoImpl.java,添加注解,注入JdbcTemplate。

@Repository
public class UserDaoImpl implements UserDao{//@Autowired@Resourceprivate JdbcTemplate jdbcTemplate;}

创建UserService.java,添加注解,注入UserDao。

@Service
public class UserService {//注入dao//@Autowired//@Qualifier(value = "BookDaoImpl")@Resourceprivate UserDao bookDao;}

基本操作


添加操作

int org.springframework.jdbc.core.JdbcTemplate.update(String sql, @Nullable Object... args) throws DataAccessException

UserDao.java

 //addint addUser(User user);

UserDaoImpl.java

 @Overridepublic int addUser(User user) {//调用JdbcTemplate中的update()可以对数据库表进行add,update,delete操作//第一个参数:sql语句;第二个参数:可变参数,设置 sql 语句值String sql = "insert into t_user values (null, ?, ?, ?, ?)";Object[] parameter = {user.getUsername(), user.getPassword(), user.getAge(), user.getEmail()};int result = jdbcTemplate.update(sql, parameter);System.out.println("受影响行数:" + result);return result;}

UserDaoService.java

 //addpublic int addUser(User user){int result = userDao.addUser(user);return result;}

test

@Testpublic void testJdbcTemplateAddUser(){ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\jdbc_template\\xml\\bean.xml");UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);User user = new User("宋江", "songjiang", 50, "9829021782qq.com");userService.addUser(user);classPathXmlApplicationContext.close();}

修改操作

int org.springframework.jdbc.core.JdbcTemplate.update(String sql, @Nullable Object... args) throws DataAccessException

UserDao.java

 //update;根据id进行修改int updateUserById(User user);

UserDaoImpl.java

 @Overridepublic int updateUserById(User user) {String sql = "update t_user set username=?, password=?, age=? where id=?";Object[] parameter = {user.getUsername(), user.getPassword(), user.getAge(), user.getId()};int result = jdbcTemplate.update(sql, parameter);System.out.println("受影响行数:" + result);return result;}

UserDaoService.java

 //updatepublic int updateUserById(User user) {int result = userDao.updateUserById(user);return result;}

test

 @Testpublic void testJdbcTemplateUpdateUserById(){ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\jdbc_template\\xml\\bean.xml");UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);User user = new User();user.setId(17);user.setUsername("卢俊义");user.setPassword("lujunyi");user.setAge(69);userService.updateUserById(user);classPathXmlApplicationContext.close();}

删除操作

int org.springframework.jdbc.core.JdbcTemplate.update(String sql, @Nullable Object... args) throws DataAccessException

UserDao.java

 //delete;根据id进行删除操作int deleteUserById(Integer id);

UserDaoImpl.java

 @Overridepublic int deleteUserById(Integer id) {String sql = "delete from t_user where id=?";int result = jdbcTemplate.update(sql, id);return result;}

UserDaoService.java

 public int deleteUserById(Integer id) {return userDao.deleteUserById(id);}

test

@Testpublic void testJdbcTemplateDeleteUserById(){ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\jdbc_template\\xml\\bean.xml");UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);int result = userService.deleteUserById(18);System.out.println("受影响行数:" + result);classPathXmlApplicationContext.close();}

查询操作

返回结果为值类型

<T> T org.springframework.jdbc.core.JdbcTemplate.queryForObject(String sql, Class<T> requiredType) throws DataAccessException

UserDao.java

 //查询总数int selectUserCount();

UserDaoImpl.java

 //查询记录数@Overridepublic int selectUserCount() {String sql = "select count(*) from t_user";/*Integer org.springframework.jdbc.core.JdbcTemplate.queryForObject(String sql, Class requiredType) throws DataAccessException第一个参数:sql语句第二个参数:返回类型的Class*/return jdbcTemplate.queryForObject(sql, Integer.class);}

UserDaoService.java

 //select;查询表中的记录数public int selectUserCount(){return userDao.selectUserCount();}

test

 @Testpublic void testJdbcTemplateFindCount() {ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\jdbc_template\\xml\\bean.xml");UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);int count = userService.selectUserCount();System.out.println("查询的记录总数:" + count);classPathXmlApplicationContext.close();}

返回结果为对象类型

<T> T org.springframework.jdbc.core.JdbcTemplate.queryForObject(String sql, RowMapper<T> rowMapper, @Nullable Object... args) throws DataAccessException

UserDao.java

 //根据id查询一条记录User selectUserById(Integer id);

UserDaoImpl.java

 /*第一个参数:sql语句第二个参数:RowMapper是接口,针对返回不同类型数据,使用这个接口里面实现类完成数据封装第三个参数:id*/@Overridepublic User selectUserById(Integer id) {String sql = "select * from t_user where id=?";RowMapper<User> rowMapper = new BeanPropertyRowMapper<>(User.class);return jdbcTemplate.queryForObject(sql, rowMapper, id);}

UserDaoService.java

 //根据id查询一条数据public User selectUserById(Integer id) {return userDao.selectUserById(id);}

test

 @Testpublic void testJdbcTemplateSelectUserById(){ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\jdbc_template\\xml\\bean.xml");UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);User user = userService.selectUserById(2);System.out.println(user);classPathXmlApplicationContext.close();}

返回结果为List集合类型

<T> List<T> org.springframework.jdbc.core.JdbcTemplate.query(String sql, RowMapper<T> rowMapper) throws DataAccessException

UserDao.java

 //查询所有记录List<User> selectUserAll();

UserDaoImpl.java

 //查询所有记录@Overridepublic List<User> selectUserAll() {String sql = "select * from t_user";RowMapper<User> rowMapper = new BeanPropertyRowMapper<>(User.class);return jdbcTemplate.query(sql, rowMapper);//return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(User.class));}

UserDaoService.java

 //查询所有记录public List<User> selectUserAll() {return userDao.selectUserAll();}

test

 @Testpublic void testJdbcTemplateSelectUserAll(){ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\jdbc_template\\xml\\bean.xml");UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);List<User> users = userService.selectUserAll();System.out.println(users);users.forEach(System.out::println);classPathXmlApplicationContext.close();}

批量操作

int[] org.springframework.jdbc.core.JdbcTemplate.batchUpdate(String sql, List<Object[]> batchArgs) throws DataAccessException

批量添加操作

UserDao.java

 int[] batchAddUser(List<Object[]> batchArgs);

UserDaoImpl.java

 //批量添加    @Overridepublic int[] batchAddUser(List<Object[]> batchArgs) {String sql = "insert into t_user values(null, ?, ?, ?, ?)";int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);return ints;}

UserDaoService.java

 //批量添加public int[] batchAdd(List<Object[]> batchArgs) {return userDao.batchAddUser(batchArgs);}

test

 //批量添加@Testpublic void testBatchAddUser() {ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\jdbc_template\\xml\\bean.xml");UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);List<Object[]> batchArgs = new ArrayList<>();Object[] user = {"宋江", "songjiang", 50, "982902178@qq.com"};Object[] user1 = {"卢俊义", "lujunyi", 51, "982902178@qq.com"};Object[] user2 = {"吴用", "wuyong", 52, "982902178@qq.com"};batchArgs.add(user);batchArgs.add(user1);batchArgs.add(user2);//调用批量添加方法int[] ints = userService.batchAdd(batchArgs);for(int i=0; i<ints.length; i++) {System.out.println(ints[i]);}System.out.println("***********");System.out.println(Arrays.toString(ints));classPathXmlApplicationContext.close();}

批量修改操作

UserDao.java

 int[] batchUpdateUser(List<Object[]> batchArgs);

UserDaoImpl.java

 //批量修改@Overridepublic int[] batchUpdateUser(List<Object[]> batchArgs) {String sql = "update t_user set username=?, password=?, age=? where id=?";int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);return ints;}

UserDaoService.java

 //批量修改public int[] batchUpdateUser(List<Object[]> batchArgs) {return userDao.batchUpdateUser(batchArgs);}

test

 //批量修改操作@Testpublic void testBatchUpdateUser() {ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\jdbc_template\\xml\\bean.xml");UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);List<Object[]> batchArgs = new ArrayList<>();Object[] user = {"宋江1", "songjiang1", 60, 19};Object[] user1 = {"卢俊义1", "lujunyi1", 61, 20};Object[] user2 = {"吴用1", "wuyong1", 62, 21};batchArgs.add(user);batchArgs.add(user1);batchArgs.add(user2);//调用批量修改方法int[] ints = userService.batchUpdateUser(batchArgs);System.out.println(Arrays.toString(ints));classPathXmlApplicationContext.close();}

批量删除操作

UserDao.java

 //批量删除操作int[] batchDeleteUser(List<Object[]> batchArgs);

UserDaoImpl.java

 //批量删除@Overridepublic int[] batchDeleteUser(List<Object[]> batchArgs) {String sql = "delete from t_user where id=?";int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);return ints;}

UserDaoService.java

 //批量删除public int[] batchDeleteUser(List<Object[]> batchArgs) {return userDao.batchDeleteUser(batchArgs);}

test

 //批量删除@Testpublic void testBatchDelete() {ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\jdbc_template\\xml\\bean.xml");     UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);List<Object[]> batchArgs = new ArrayList<>();Object[] object = {19};Object[] object1 = {20};Object[] object2 = {21};batchArgs.add(object);batchArgs.add(object1);batchArgs.add(object2);//调用批量修改方法int[] ints = userService.batchDeleteUser(batchArgs);System.out.println(Arrays.toString(ints));classPathXmlApplicationContext.close();}

完整代码
UserDao.java

package com.jack.spring.jdbc_template.dao;import java.util.List;import com.jack.spring.jdbc_template.entity.User;public interface UserDao {//addint addUser(User user);//update;根据id进行修改int updateUserById(User user);//delete;根据id进行删除操作int deleteUserById(Integer id);//查询总数int selectUserCount();//根据id查询一条记录User selectUserById(Integer id);//查询所有记录List<User> selectUserAll();//批量添加操作int[] batchAddUser(List<Object[]> batchArgs);//批量修改操作int[] batchUpdateUser(List<Object[]> batchArgs);//批量删除操作int[] batchDeleteUser(List<Object[]> batchArgs);}

UserDaoImpl.java

package com.jack.spring.jdbc_template.dao;import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;import com.jack.spring.jdbc_template.entity.User;import javax.annotation.Resource;
import java.util.List;@Repository
public class UserDaoImpl implements UserDao{//@Autowired@Resourceprivate JdbcTemplate jdbcTemplate;@Overridepublic int addUser(User user) {//调用JdbcTemplate中的update()可以对数据库表进行add,update,delete操作//第一个参数:sql语句;第二个参数:可变参数,设置 sql 语句值String sql = "insert into t_user values (null, ?, ?, ?, ?)";Object[] parameter = {user.getUsername(), user.getPassword(), user.getAge(), user.getEmail()};int result = jdbcTemplate.update(sql, parameter);System.out.println("受影响行数:" + result);return result;}@Overridepublic int updateUserById(User user) {String sql = "update t_user set username=?, password=?, age=? where id=?";Object[] parameter = {user.getUsername(), user.getPassword(), user.getAge(), user.getId()};int result = jdbcTemplate.update(sql, parameter);System.out.println("受影响行数:" + result);return result;}@Overridepublic int deleteUserById(Integer id) {String sql = "delete from t_user where id=?";int result = jdbcTemplate.update(sql, id);return result;}//查询记录数@Overridepublic int selectUserCount() {String sql = "select count(*) from t_user";/*Integer org.springframework.jdbc.core.JdbcTemplate.queryForObject(String sql, Class requiredType) throws DataAccessException第一个参数:sql语句第二个参数:返回类型的Class*/return jdbcTemplate.queryForObject(sql, Integer.class);}/*第一个参数:sql语句第二个参数:RowMapper是接口,针对返回不同类型数据,使用这个接口里面实现类完成数据封装第三个参数:id*/@Overridepublic User selectUserById(Integer id) {String sql = "select * from t_user where id=?";RowMapper<User> rowMapper = new BeanPropertyRowMapper<>(User.class);return jdbcTemplate.queryForObject(sql, rowMapper, id);}//查询所有记录@Overridepublic List<User> selectUserAll() {String sql = "select * from t_user";RowMapper<User> rowMapper = new BeanPropertyRowMapper<>(User.class);return jdbcTemplate.query(sql, rowMapper);//return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(User.class));}//批量添加    @Overridepublic int[] batchAddUser(List<Object[]> batchArgs) {String sql = "insert into t_user values(null, ?, ?, ?, ?)";int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);return ints;}//批量修改@Overridepublic int[] batchUpdateUser(List<Object[]> batchArgs) {String sql = "update t_user set username=?, password=?, age=? where id=?";int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);return ints;}//批量删除@Overridepublic int[] batchDeleteUser(List<Object[]> batchArgs) {String sql = "delete from t_user where id=?";int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);return ints;}}

UserService.java

package com.jack.spring.jdbc_template.service;import org.springframework.stereotype.Service;import com.jack.spring.jdbc_template.dao.UserDao;
import com.jack.spring.jdbc_template.entity.User;import javax.annotation.Resource;
import java.util.List;@Service
public class UserService {//注入dao//@Autowired//@Qualifier(value = "BookDaoImpl")@Resourceprivate UserDao userDao;//addpublic int addUser(User user){int result = userDao.addUser(user);return result;}//updatepublic int updateUserById(User user) {int result = userDao.updateUserById(user);return result;}//deletepublic int deleteUserById(Integer id) {return userDao.deleteUserById(id);}//select;查询表中的记录数public int selectUserCount(){return userDao.selectUserCount();}//根据id查询一条数据public User selectUserById(Integer id) {return userDao.selectUserById(id);}//查询所有记录public List<User> selectUserAll() {return userDao.selectUserAll();}//批量添加public int[] batchAdd(List<Object[]> batchArgs) {return userDao.batchAddUser(batchArgs);}//批量修改public int[] batchUpdateUser(List<Object[]> batchArgs) {return userDao.batchUpdateUser(batchArgs);}//批量删除public int[] batchDeleteUser(List<Object[]> batchArgs) {return userDao.batchDeleteUser(batchArgs);}}

test

package com.jack.spring.jdbc_template.test;import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;import com.jack.spring.jdbc_template.entity.User;
import com.jack.spring.jdbc_template.service.UserService;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;public class TestUser {@Testpublic void testJdbcTemplateAddUser() {ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\jdbc_template\\xml\\bean.xml");UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);User user = new User("宋江", "songjiang", 50, "9829021782qq.com");userService.addUser(user);classPathXmlApplicationContext.close();}@Testpublic void testJdbcTemplateUpdateUserById() {ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\jdbc_template\\xml\\bean.xml");UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);User user = new User();user.setId(17);user.setUsername("卢俊义");user.setPassword("lujunyi");user.setAge(69);userService.updateUserById(user);classPathXmlApplicationContext.close();}@Testpublic void testJdbcTemplateDeleteUserById() {ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\jdbc_template\\xml\\bean.xml");UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);int result = userService.deleteUserById(18);System.out.println("受影响行数:" + result);classPathXmlApplicationContext.close();}@Testpublic void testJdbcTemplateFindCount() {ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\jdbc_template\\xml\\bean.xml");UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);int count = userService.selectUserCount();System.out.println("查询的记录总数:" + count);classPathXmlApplicationContext.close();}@Testpublic void testJdbcTemplateSelectUserById(){ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\jdbc_template\\xml\\bean.xml");UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);User user = userService.selectUserById(2);System.out.println(user);classPathXmlApplicationContext.close();}@Testpublic void testJdbcTemplateSelectUserAll(){ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\jdbc_template\\xml\\bean.xml");UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);List<User> users = userService.selectUserAll();System.out.println(users);users.forEach(System.out::println);classPathXmlApplicationContext.close();}//批量添加@Testpublic void testBatchAddUser() {ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\jdbc_template\\xml\\bean.xml");UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);List<Object[]> batchArgs = new ArrayList<>();Object[] user = {"宋江", "songjiang", 50, "982902178@qq.com"};Object[] user1 = {"卢俊义", "lujunyi", 51, "982902178@qq.com"};Object[] user2 = {"吴用", "wuyong", 52, "982902178@qq.com"};batchArgs.add(user);batchArgs.add(user1);batchArgs.add(user2);//调用批量添加方法int[] ints = userService.batchAdd(batchArgs);for(int i=0; i<ints.length; i++) {System.out.println(ints[i]);}System.out.println("***********");System.out.println(Arrays.toString(ints));classPathXmlApplicationContext.close();}//批量修改操作@Testpublic void testBatchUpdateUser() {ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\jdbc_template\\xml\\bean.xml");UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);List<Object[]> batchArgs = new ArrayList<>();Object[] user = {"宋江1", "songjiang1", 60, 19};Object[] user1 = {"卢俊义1", "lujunyi1", 61, 20};Object[] user2 = {"吴用1", "wuyong1", 62, 21};batchArgs.add(user);batchArgs.add(user1);batchArgs.add(user2);//调用批量修改方法int[] ints = userService.batchUpdateUser(batchArgs);System.out.println(Arrays.toString(ints));classPathXmlApplicationContext.close();}//批量删除@Testpublic void testBatchDelete() {ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\jdbc_template\\xml\\bean.xml");     UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);List<Object[]> batchArgs = new ArrayList<>();Object[] object = {19};Object[] object1 = {20};Object[] object2 = {21};batchArgs.add(object);batchArgs.add(object1);batchArgs.add(object2);//调用批量修改方法int[] ints = userService.batchDeleteUser(batchArgs);System.out.println(Arrays.toString(ints));classPathXmlApplicationContext.close();}}

事务

事务的四个特性(ACID )
(1)原子性
(2)一致性
(3)隔离性
(4)持久性

创建表;表名:t_account

字段名称 类型 长度 备注
id bigint 20 主键自增
username varchar 255
money int 11

创建UserDao.java

package com.jack.spring.transaction.dao;public interface UserDao {//多钱int addMoney();//少钱int reduceMoney();}

创建UserDaoImpl.java

package com.jack.spring.transaction.dao;import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;import javax.annotation.Resource;@Repository
public class UserDaoImpl implements UserDao{@Resourceprivate JdbcTemplate jdbcTemplate;@Overridepublic int reduceMoney() {String sql = "update t_account set money=money-? where username=?";return jdbcTemplate.update(sql, 10, "宋江");}@Overridepublic void addMoney() {String sql = "update t_account set money=money+? where username=?";return jdbcTemplate.update(sql, 10, "卢俊义");}}

UserService.java

package com.jack.spring.transaction.service;import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;import com.jack.spring.transaction.dao.UserDao;import javax.annotation.Resource;@Service
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ) // 这个注解可以添加到类上面(表示类里所有的方法都开启事务),也可以添加到方法上面(只把此方法开启事务);开启事务,里面的值都是默认的
public class UserService {// 注入dao@Resourceprivate UserDao userDao;// 转账的方法public intaccountMoney() {int resultReduce = userDao.reduceMoney();//int i = 10/0; //执行了事务的回滚int resultAdd useDao.addMoney();return resultReduce + resultAdd;}}

test

 @Testpublic void testUserAccount() {ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("com\\jack\\spring\\transaction\\xml\\bean.xml");UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);userService.accountMoney();int result = userService.accountMoney();System.out.println(result);classPathXmlApplicationContext.close();}

异常处理:

// 转账的方法public int accountMoney() {try {//第一步:开启事务//第二步:进行业务操作int resultReduce = userDao.reduceMoney();//模拟异常int i = 10/0;int resultAdd = userDao.addMoney();//第三步:没有发生异常,提交事务System.out.println(i);return resultReduce + resultAdd;}catch (Exception e) {//第四步:出现异常,事务回滚return 0;}}

事务管理

在Spring中进行事务管理的操作有两种方式:编程式事务管理和声明式事务管理。

声明式事务管理的两种方式:基于注解方式、基于xml配置文件方式。

在Spring中进行声明式事务管理,底层使用AOP原理。

Spring事务管理的API
提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类。

基于注解方式

添加Spring事务管理:
1、创建事务管理器

 <!--创建事务管理器--><bean id="transactionManager" class= "org.springframework.jdbc.datasource.DataSourceTransactionManager"><!--注入数据源--><property name="dataSource" ref="dataSource"/></bean>

2、开启事务注解
引入tx标签
xmlns:tx=“http://www.springframework.org/schema/tx”
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd

 <!--开启事务注解--><tx:annotation-driven transaction-manager="transactionManager"/>

3、在UserService类上面或者UserService类里面的方法上面)添加事务注解@Transactional
(1)@Transactional,这个注解可以添加到类上面,也可以添加在方法上面。
(2)如果把这个注解添加在类上面,这个类里面所有的方法都添加事务管理。
(3)如果把这个注解添加在方法上面,为这个方法添加事务管理。

bean_annotation.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"><!--引入外部属性文件--><context:property-placeholder location="classpath:jdbc.properties"/><!-- 数据库连接池 --><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"><property name="driverClassName" value="${jdbc.driverClass}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/>      </bean><!--创建JdbcTemplate对象--><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><!--注入dataSource--><property name="dataSource" ref="dataSource"/></bean><!--开启组件扫描;使用注解方法进行注入--><context:component-scan base-package="com.jack.spring.transaction"/><!--创建事务管理器--><bean id="transactionManager" class= "org.springframework.jdbc.datasource.DataSourceTransactionManager"><!--注入数据源--><property name="dataSource" ref="dataSource"/></bean><!--开启事务注解--><tx:annotation-driven transaction-manager="transactionManager"/></beans>

声明式事务管理参数配置

在service层类上面添加注解@Transactional,在这个注解里面可以配置事务相关参数。

@AliasFor("transactionManager")
String value() default "";@AliasFor("value")
String transactionManager() default "";Propagation propagation() default Propagation.REQUIRED;Isolation isolation() default Isolation.DEFAULT;int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;boolean readOnly() default false;Class<? extends Throwable>[] rollbackFor() default {};String[] rollbackForClassName() default {};Class<? extends Throwable>[] noRollbackFor() default {};String[] noRollbackForClassName() default {};

propagation:事务传播行为

事务传播行为:多事务方法直接进行调用,这个过程中事务是如何进行管理的。
事务方法:对数据库表数据进行变化的操作。

事务的传播行为可以由传播属性指定。Spring定义了7种类传播行为。

REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED)
SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS)
MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY)
REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW)
NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED)
NEVER(TransactionDefinition.PROPAGATION_NEVER)
NESTED(TransactionDefinition.PROPAGATION_NESTED)
传播属性 描述
REQUIRED 如果有事务在运行,当前的方法就在这个事务内运行,否则,就启动一个新的事务,并在自己的事务内运行。
REQUIRES_NEW 当前的方法必须启动新事务,并在它自己的事务内运行。如果有事务正在运行,应该将它挂起。
SUPPORTS 如果有事务在运行,当前的方法就在这个事务内运行,否则它可以不运行在事务中。
NOT_SUPPORTED 当前的方法不应该运行在事务中。如果有运行的事务,将它挂起。
MANDATORY 当前的方法必须运行在事务内部,如果没有正在运行的事务,就抛出异常。
NEVER 当前的方法不应该运行在事务中,如果有运行的事务,就抛出异常。
NESTED 如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行。否则,就启动一个新的事务,并在它自己的事务内运行。

ioslation:事务隔离级别

timeout:超时时间

readOnly:是否只读

rollbackFor:回滚

Spring_00000相关推荐

最新文章

  1. 开发中内存溢出问题及解决
  2. springside3.3.4部署小结
  3. 蓄电池容量和环境温度的关系
  4. 乐视云没创意,还拿“免费”说事儿
  5. 之一:CABasicAnimation - 基本动画
  6. 2021-11-18Collections
  7. C++强化之路之线程池开发整体框架(二)
  8. 【java】java AsyncHttpClient使用
  9. 求翻转数循环结构C语言,[LeetCode Easy题快一起刷起来] 1. 两数之和 7. 整数翻转
  10. C/C++网络编程工作笔记0002---网络编程流程
  11. 计算机操作系统第四版课后全部习题答案
  12. U盘数据恢复软件EasyRecovery的使用教程
  13. 基于“点云智绘”与无人机激光雷达点云的土地整理解决方案及案例分享
  14. ffmpeg AVFrame 插入静音帧
  15. 难道没有GPHONE??
  16. 2016年8月16日 星期二 --出埃及记 Exodus 16:17
  17. JAVA 开发相关软件介绍以及安装使用教程(初学者一定要收藏)
  18. 手机测试属于硬件测试还是软件测试6,Redmi手机硬件测试的两个基本操作
  19. keepalived外界无法通过虚拟ip访问
  20. php实现单笔转账到支付宝功能

热门文章

  1. 被呼叫方拒绝接收呼叫_奇瑞和星途汽车2020年呼叫中心外包采购项目
  2. elasticsearch 6.2.2 搜索推荐系列(三)之高级搜索查询实现( 中文+拼音+首字母+简繁转换+特殊符号过滤)
  3. 局域网内无线路由器太多的方法
  4. 独家|胡郁出任讯飞消费者事业群总裁,物联网时代输入法战争启幕
  5. 织梦dedecms 自定义表单管理
  6. AntiSamy:防 XSS 攻击的一种解决方案使用教程
  7. APP与后台安全性问题及应对方案
  8. 【图的遍历】广度优先遍历(DFS)、深度优先遍历(BFS)及其应用
  9. Xinlinx zynq7020国产替代 FMQL20S400 全国产化 ARM 核心板+扩展板
  10. 【Redis】如何使用Redis保存Java对象