Spring由浅入深
作者:互联网
文章目录
- Spring
- 1、简介
- 2、什么是容器
- 3、IOC容器
- 4、Spring配置
- 6、基于原始注解
- 7、Spring新注解
- 8、代理模式
- 9、AOP
- 10、MyBatis-Spring
- 11、Spring事务
Spring
1、简介
1.1、什么是Spring
Spring是分层的 Java SE/EE应用 full-stack 轻量级开源框架,以 IoC(Inverse Of Control:反转控制)和 AOP(Aspect Oriented Programming:面向切面编程)为内核。
提供了展现层 SpringMVC 和持久层 Spring JDBCTemplate 以及业务层事务管理等众多的企业级应用技术 ,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE 企业应用开源框架。
2002年,Rod Jahnson首次推出了Spring框架雏形interface21框架。
2004年3月24日,Spring框架以interface21框架为基础,经过重新设计,发布了1.0正式版。
Spring理念 : 使现有技术更加实用 . 本身就是一个大杂烩 , 整合现有的框架技术
官网 : http://spring.io/
官方下载地址 : https://repo.spring.io/libs-release-local/org/springframework/spring/
GitHub : https://github.com/spring-projects
1.2、Spring的优点
- 方便解耦,简化开发
- 声明式事务的支持
- Spring是一个轻量级的框架,非侵入式。(注:现在可能不是轻量的)
- 控制反转IoC,面向切面Aop
- 对事物的支持,集成各种优秀框架
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。
1.3、Spring的体系结构
Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式 。
- Spring Core:核心容器,提供Spring框架的基本功能。核心容器的主要组件是BeanFactory,它是工厂模式的实现。BeanFactory使用控制反转IOC模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
- Spring Context:继承BeanFactory,提供上下文信息,扩展出JNDI、EJB、电子邮件、国际化、校验和调度等功能。
- Spring AOP:Spring AOP 模块直接将面向切面的编程功能,集成到了Spring框架中,所以可以很容易地使 Spring 框架管理任何支持 AOP的对象。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中。
- Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所以这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
- Spring DAO:提供了JDBC的抽象层,还提供了声明性事务管理方法。并且极大地降低了需要编写地异常代码数据 (例如打开和关闭连接)。
- Spring Web:提供了基础的 Web 开发的上下文信息,现有的Web框架,如JSF、Tapestry、Structs等,提供了集成。
- Spring MVC:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架便成为高度可配置的,MVC 其中容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
1.4、扩展
Spring Boot与Spring Cloud
- Spring Boot 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务;
- Spring Cloud是基于Spring Boot实现的;
- Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架;
- Spring Boot使用了约束优于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置 , Spring Cloud很大的一部分是基于Spring Boot来实现,Spring Boot可以离开Spring Cloud独立使用开发项目,但是Spring Cloud离不开Spring Boot,属于依赖的关系。
- SpringBoot在SpringClound中起到了承上启下的作用,如果你要学习SpringCloud必须要学习SpringBoot。
2、什么是容器
- 从概念上来讲容器是Spring的核心,是用来管理对象的,容器将创建对象,把他们连接在一起,配置,并管理他们的整个生命周期从创建到销毁。
org.springframework.context.ApplicationContext
接口代表 Spring IoC 容器,负责实例化、配置和组装 bean。容器通过读取配置元数据获取有关要实例化、配置和组装哪些对象的指令。配置元数据以 XML、Java 注释或 Java 代码表示。它可以让您表达组成应用程序的对象以及这些对象之间丰富的相互依赖关系。ApplicationContext
Spring 提供了该接口的几种实现。在独立应用程序中,通常创建ClassPathXmlApplicationContext
或FileSystemXmlApplicationContext
对象。
3、IOC容器
**控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,**也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,控制反转就是:获得依赖对象的方式反转了。
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
3.1、配置元数据
- IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。
- Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。
导入jar包:
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.13</version>
</dependency>
applicationContext.xml
配置文件:
一般spring容器叫(ApplicationContext.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
<property name="accountDao" ref="accountDao"/>
<property name="name" value="value"/>
</bean>
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions go here -->
</beans>
3.2、如何去使用容器
- ApplicationContext的实现类
实现类 | 作用 |
---|---|
ClassPathXmlApplicationContext | 它是从类的根路径下加载配置文件,推荐使用这种 |
FileSystemXmlApplicationContext | 它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置 |
AnnotationConfigApplicationContext | 当使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解 |
实例化容器,可以加载多个配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml", "daos.xml");
getBean():获取容器中的bean
//getBean(String name, Class<T> requiredType)获取实例对象
PetStoreService service = context.getBean("petStore", PetStoreService.class);
4、Spring配置
4.1、Bean标签基本配置
- Spring 配置中可以有一个或者多个
<bean>
标签,处于<beans>
中。 - bean定义对应于构成应用程序的实际对象。通常,定义服务层对象、数据访问对象(DAO)、表示对象(如Struts操作实例)、基础结构对象(如Hibernate SessionFactorys)、JMS队列等。通常,不在容器中配置细粒度域对象,因为创建和加载域对象通常是DAO和业务逻辑的责任。但是,可以使用Spring与AspectJ的集成来配置在IoC容器控制之外创建的对象。
- id:用于标识单个 bean ,变量名。
- 如果没有配置id,name就是默认标识符,如果配置id,又配置了name,那么name是别名。
- 如果不配置id和name,可以根据applicationContext.getBean(.class)获取对象。
- class:属性定义 bean 的类型并使用完全限定的类名,对象。
<bean id="fromName" name="toName h2,h3;h4" class="com.kuang.pojo.Hello">
<property name="name" value="Spring"/>
</bean>
4.2、Bean实例化三种方式
1、构造函数实例化
- 无参构造
<bean id="exampleBean" class="examples.ExampleBean"/>
<bean name="anotherExample" class="examples.ExampleBeanTwo"/>
2、工厂静态方法实例化
3、工厂实例方法实例化
4.3、Bean依赖注入
概念
- 依赖注入(Dependency Injection,DI)
- 依赖:指Bean对象的创建依赖于容器,Bean对象的依赖资源。
- 注入:指Bean对象所依赖的资源,由容器来设置和装配。
1、构造器注入
- 有参构造器注入
<!-- 第一种根据参数名字设置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
<!-- name指参数名 -->
<constructor-arg name="name" value="value"/>
</bean>
<!-- 第二种根据index参数下标设置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
<!-- index指构造方法 , 下标从0开始 -->
<constructor-arg index="0" value="value"/>
</bean>
<!-- 第三种根据参数类型设置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
<constructor-arg type="java.lang.String" value="value"/>
</bean>
2、Setter 注入
要求被注入的属性,必须要有set方法,set方法的方法名由set + 属性首字母大写,如果属性是Boolean类型,没有set方法,是is方法。
测试类:
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class Student {
private String name;//基本类型
private Address address;//实体属性
private String[] books;//数组
private List<String> hobbys;//list集合
private Map<String,String> card;//map集合
private Set<String> games;//set集合
private String wife;//Null,可能没有妻子
private Properties info;//配置文件注入
public void setName(String name) {
this.name = name;
}
public void setAddress(Address address) {
this.address = address;
}
public void setBooks(String[] books) {
this.books = books;
}
public void setHobbys(List<String> hobbys) {
this.hobbys = hobbys;
}
public void setCard(Map<String, String> card) {
this.card = card;
}
public void setGames(Set<String> games) {
this.games = games;
}
public void setWife(String wife) {
this.wife = wife;
}
public void setInfo(Properties info) {
this.info = info;
}
public void show(){
System.out.println("name="+ name
+ ",address="+ address.getAddress()
+ ",books="
);
for (String book:books){
System.out.print("<<"+book+">>\t");
}
System.out.println("\n爱好:"+hobbys);
System.out.println("card:"+card);
System.out.println("games:"+games);
System.out.println("wife:"+wife);
System.out.println("info:"+info);
}
}
1、基本类型注入
<!--
name:属性名
name可以设置多个别名,可以用逗号,分号,空格隔开
ref:指的是另一个bean定义的id名称,引用Spring中创建好的对象
value:给属性设置基本数据类型的值,底层通过反射获取set方法
-->
<property name="name" value="pip"/>
2、Bean对象注入
<bean id="address" class="com.pip.pojo.Address">
<property name="address" value="陕西"/>
</bean>
<bean id="student" class="com.pip.pojo.Student">
<property name="address" ref="address"/>
</bean>
3、数组注入
<property name="books">
<array>
<value>西游记</value>
<value>红楼梦</value>
<value>水浒传</value>
</array>
</property>
4、list集合注入
<property name="hobbys">
<list>
<value>听歌</value>
<value>看电影</value>
<value>爬山</value>
</list>
</property>
5、map集合注入
<property name="card">
<map>
<entry key="手机号" value="12341234123"/>
<entry key="id" value="00001"/>
</map>
</property>
6、set集合注入
<property name="games">
<set>
<value>LOL</value>
<value>BOB</value>
<value>COC</value>
</set>
</property>
7、Null注入
<property name="wife">
<null/>
</property>
<bean class="ExampleBean">
<property name="email" value=""/>//这里是设为空字符串
</bean>
8、Properties注入
<property name="info">
<props>
<prop key="学号">20190604</prop>
<prop key="性别">男</prop>
<prop key="姓名">小明</prop>
</props>
</property>
3、其他注入
p命名和c命名注入
1、P命名空间注入
首先,需要引入P命名空间:
xmlns:p="http://www.springframework.org/schema/p"
P命名空间注入本质也是set方法注入,但比起上述的set方法注入更加方便,主要体现在配置文件中,如下:
<!--P(属性: properties)命名空间 , 属性依然要设置set方法-->
<bean id="user" class="com.pip.pojo.User" p:name="pip" p:age="18"/>
2、c 命名空间注入
- 构造器注入,需要有参构造
需要在头文件中加入约束文件
xmlns:c="http://www.springframework.org/schema/c"
<!--C(构造: Constructor)命名空间 , 属性依然要设置set方法-->
<bean id="user" class="com.pip.pojo.User" c:name="pip" c:age="18"/>
4.4、Bean自动装配
Spring中bean有三种装配机制:
- 在xml中显式配置;(使用ref显示装配)
- 在java中显式配置;
- 隐式的bean发现机制和自动装配。
概念
- 自动装配是使用spring满足bean依赖的一种方法
- spring会在应用上下文中为某个bean寻找其依赖的bean。
Spring的自动装配是如何实现的:
- 组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;
- 自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI;
1、byName
autowire byName (按名称自动装配)
Spring 查找与需要自动装配的属性同名的 bean(根据id是否和属性名相同)。例如,如果一个 bean 定义被设置为按名称自动装配并且它包含一个master属性(即它有一个 setMaster(..)方法),Spring 会查找一个名为的 bean 定义master并使用它来设置属性。
<!--
自动装配byName必须要有相应的set方法
-->
<bean id="address" class="com.pip.pojo.Address"></bean>
<!--用户具有一个address实体类属性-->
<bean id="user" class="com.pip.pojo.User" autowire="byName">
<property name="u_name" value="pip"/>
</bean>
2、byType
autowire byType (按类型自动装配)
如果容器中恰好存在一个属性类型的 bean,则让属性自动装配。如果存在多个,则会引发致命异常,不能byType为该 bean使用自动装配。如果没有匹配的 bean,则不会发生任何事情(未设置属性)。
<!--这里使用猫和狗来举例子-->
<bean id="dog" class="com.pip.pojo.Dog"/>
<bean id="cat" class="com.pip.pojo.Cat"/>
<bean id="cat2" class="com.pip.pojo.Cat"/>
<bean id="user" class="com.pip.pojo.User" autowire="byType">
<property name="u_name" value="pip"/>
</bean>
自动装配的优缺点
优点:
- 自动装配可以显着减少指定属性或构造函数参数的需要。
- 自动装配可以随着对象的发展更新配置。例如,如果需要向类添加依赖项,则无需修改配置即可自动满足该依赖项。因此,自动装配在开发过程中特别有用,当代码库变得更稳定时,不会否定切换到显式装配的选项。
4.5、Bean作用域
scope:指对象的作用范围,取值如下:
singleton
单例作用域(单例模式)
- 当定义一个 bean 定义并且它的作用域为单例时,Spring IoC 容器会创建该 bean 定义定义的对象的一个实例。该单个实例存储在此类单例 bean 的缓存中,并且对该命名 bean 的所有后续请求和引用都返回缓存对象。白话来说就是公用一个缓存里的对象
- Bean的实例化个数:1个
- Bean的实例化时机:当Spring核心文件被加载时,实例化配置的Bean实例
- Bean的生命周期:
- 对象创建:当应用加载,创建容器时,对象就被创建了
- 对象运行:只要容器在,对象一直活着
- 对象销毁:当应用卸载,销毁容器时,对象就被销毁了
- 单例作用域是 Spring 中的默认作用域。要将 bean 定义为 XML 中的单例,如下例所示:
<bean id="accountService" class="com.something.DefaultAccountService"/>
<!-- the following is equivalent, though redundant (singleton scope is the default) -->
<bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/>
Prototype
原型作用域(原型模式)
- bean 部署的非单一原型范围导致每次对特定 bean 发出请求时都会创建一个新 bean 实例。
- 通常,对所有有状态 bean 使用原型作用域,对无状态 bean 使用单例作用域。
- Bean的实例化个数:多个
- Bean的实例化时机:当调用getBean()方法时实例化Bean
- 对象创建:当使用对象时,创建新的对象实例
- 对象运行:只要对象在使用中,就一直活着
- 对象销毁:当对象长时间不用时,被 Java 的垃圾回收器回收了
以下示例将 bean 定义为 XML 中的原型:
<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>
Request
考虑 bean 定义的以下 XML 配置:
<bean id="loginAction" class="com.something.LoginAction" scope="request"/>
Spring 容器LoginAction
通过loginAction
对每个 HTTP 请求使用bean 定义来创建bean 的新实例。也就是说, loginAction
bean 的范围在 HTTP 请求级别。您可以根据需要更改所创建实例的内部状态,因为从同一loginAction
bean 定义创建的其他实例不会看到这些状态更改。它们是针对个人要求的。当请求完成处理时,该请求范围内的 bean 将被丢弃。
当使用注解驱动的组件或 Java 配置时,@RequestScope
注解可用于将组件分配给request
作用域。以下示例显示了如何执行此操作:
@RequestScope
@Component
public class LoginAction {
// ...
}
Session
考虑 bean 定义的以下 XML 配置:
<bean id="userPreferences" class="com.something.UserPreferences" scope="session"/>
Spring 容器UserPreferences
通过在userPreferences
单个 HTTP 的生命周期中使用bean 定义来创建bean 的新实例Session
。换句话说,userPreferences
bean 有效地限定在 HTTPSession
级别。与请求范围的 bean 一样,您可以根据需要更改所创建实例的内部状态,因为知道Session
也使用从相同userPreferences
bean 定义创建的实例的其他 HTTP实例不会看到这些状态更改,因为它们特定于单个 HTTP Session
。当 HTTPSession
最终被丢弃时,作用域为该特定 HTTP 的 bean Session
也将被丢弃。
当使用注解驱动的组件或 Java 配置时,可以使用 @SessionScope
注解将组件分配给session
作用域。
@SessionScope
@Component
public class UserPreferences {
// ...
}
Application
考虑 bean 定义的以下 XML 配置:
<bean id="appPreferences" class="com.something.AppPreferences" scope="application"/>
Spring 容器AppPreferences
通过appPreferences
对整个 Web 应用程序使用一次 bean 定义来创建bean 的新实例。也就是说, appPreferences
bean 的作用域在ServletContext
级别并存储为常规 ServletContext
属性。这有点类似于 Spring 单例 bean,但在两个重要方面有所不同:它是一个单例 per ServletContext
,而不是 per Spring ApplicationContext
(在任何给定的 Web 应用程序中可能有多个),并且它实际上是公开的,因此作为一个ServletContext
属性可见.
当使用注解驱动的组件或 Java 配置时,可以使用 @ApplicationScope
注解将组件分配给application
作用域。以下示例显示了如何执行此操作:
@ApplicationScope
@Component
public class AppPreferences {
// ...
}
4.6、Bean别名
在 Bean 定义之外给 Bean 取别名
<!--
name:bean名
alias:别名
-->
<alias name="fromName" alias="toName"/>
4.7、引入其他配置文件
团队的合作通过import来实现 ,导入其他的容器xml文件
<import resource="{path}/beans.xml"/>
4.8、context标签
使用context标签之前需要引入context约束
开启注解支持:
<context:annotation-config/>
指定注解扫描包:支持自动将包下的类自动创建bean并注册到spring容器中,包含开启注解支持功能)
<context:component-scan base-package="指定要扫描的包"/>
用于加载.properties 文件中的配置:
<context:property-placeholder location="xx.properties"/>
6、基于原始注解
1、简介
概念
Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替xml配置 文件可以简化配置,提高开发效率。
快速说明
注解 | 说明 |
---|---|
@Component | 使用在类上用于实例化Bean |
@Controller | 使用在web层类上用于实例化Bean |
@Service | 使用在service层类上用于实例化Bean |
@Repository | 使用在dao层类上用于实例化Bean |
@Autowired | 使用在字段上用于根据类型依赖注入 |
@Qualifier | 结合@Autowired一起使用用于根据名称进行依赖注入 |
@Resource | 相当于@Autowired+@Qualifier,按照名称进行注入 |
@Value | 注入普通属性 |
@Scope | 标注Bean的作用范围 |
@PostConstruct | 使用在方法上标注该方法是Bean的初始化方法 |
@PreDestroy | 使用在方法上标注该方法是Bean的销毁方法 |
2、注解使用
2.1、配置
引入依赖jar包:spring-aop jar包
引入context约束
<?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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
配置扫描哪些包下的注解:
使用注解进行开发时,需要在applicationContext.xml中配置组件扫描,作用是指定哪个包及其子包下的Bean 需要进行扫描以便识别使用注解配置的类、字段和方法。
<!--指定注解扫描包-->
<context:component-scan base-package="指定要扫描的包"/>
@Component
使用@Compont或@Repository标识相应的类需要Spring进行实例化。
在指定包下编写类,增加注解
@Component("user")//id可加可不加
// 相当于配置文件中 <bean id="user" class="当前注解的类"/>
public class User {
public String name = "pip";
}
@Component三个衍生注解
和Component功能一模一样,只是名字不同
- @Controller:web层
- @Service:service层
- @Repository:dao层
@Autowired
概念
@Autowired
是根据类型自动装配的,不支持id匹配。@Autowired
可以加到属性或者方法上- 可以不用写set方法,但是不建议!
- 使用
@Compont
或@Service
标识UserServiceImpl
需要Spring进行实例化 - 使用
@Autowired
或者@Autowired
+@Qulifier
或者@Resource
进行userDao的注入
配置**applicationContext.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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--开启属性注解支持-->
<context:annotation-config/>
<!--这里使用猫和狗来举例子-->
<bean id="dog" class="com.pip.pojo.Dog"/>
<bean id="cat" class="com.pip.pojo.Cat"/>
<bean id="cat2" class="com.pip.pojo.Cat"/>
<bean id="user" class="com.pip.pojo.User" autowire="byType">
<property name="u_name" value="pip"/>
</bean>
</beans>
Bean
//说明:false,对象可以为null;true,对象必须存对象,不能为null。
@Autowired(required=false)
private Cat cat;
@Autowired
private Dog dog;
private String u_name;
@Qualifier
- @Qualifier不能单独使用。
- @Autowired是根据类型自动装配的,加上@Qualifier则可以根据byName的方式自动装配
@Autowired(required=false)
@Qualifier(value = "cat2")
private Cat cat;
@Autowired
private Dog dog;
private String u_name;
@Resource
@Resource
如有指定的name属性,先按该属性进行byName方式查找装配;- 其次再进行默认的byName方式进行装配;
- 如果以上都不成功,则按byType的方式自动装配。
@Autowired与@Resource异同:
1、@Autowired
与@Resource
都可以用来装配bean。都可以写在字段上,或写在setter方法上。
2、@Autowired
默认按类型装配(属于spring规范),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用
3、@Resource
(属于J2EE复返),相当于@Autowired+@Qualifier,按照名称进行注入,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired先byType,@Resource先byName。
@value
使用注解注入基本属性,可加在set方法中。
@Component("user")
// 相当于配置文件中 <bean id="user" class="当前注解的类"/>
public class User {
@Value("pip")
// 相当于配置文件中 <property name="name" value="pip"/>
public String name;
}
@scope
-
使用
@Scope
标注Bean的范围 -
singleton
:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。 -
prototype
:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收
@Controller("user")
@Scope("prototype")
public class User {
@Value("pip")
public String name;
}
7、Spring新注解
1、简介
概念
使用上面的注解还不能全部替代xml配置文件,还需要使用注解替代的配置如下
快速说明
注解 | 说明 |
---|---|
@Configuration | 用于指定当前类是一个 Spring 配置类,当创建容器时会从该类上加载注解 |
@ComponentScan | 用于指定 Spring 在初始化容器时要扫描的包。 作用和在 Spring 的 xml 配置文件中的<context:component-scan base-package="com.pip"/> 一样 |
@Bean | 使用在方法上,标注将该方法的返回值存储到 Spring 容器中 |
@PropertySource | 用于加载.properties 文件中的配置 |
@Import | 用于导入其他配置类 |
2、注解使用
@Configuration
用于指定当前类是一个 Spring 配置类,当创建容器时会从该类上加载注解
@Configuration
public class SpringConfiguration {
}
@ComponentScan
用于指定 Spring 在初始化容器时要扫描的包。 作用和在 Spring 的 xml 配置文件中的一样
@ComponentScan("com.pip")//等同于<context:component-scan base-package="com.pip"/>
public class SpringConfiguration {
}
@Import
用于导入其他配置类
@Configuration
@ComponentScan("com.pip")
@Import({DataSourceConfiguration.class})//与<import resource="{path}/beans.xml"/>功能一样
public class SpringConfiguration {
}
@Bean
相当于之前的<bean>
标签使用在方法上,标注将该方法的返回值存储到 Spring 容器中
@Bean和@Component可以分开使用也可以同时使用,我觉得并无差别
@Configuration
public class AppConfig {
@Bean("name")//name可加可不加根据需求
public Bean bean() {
return new Bean();
}
}
@PropertySource
用于加载.properties 文件中的配置
8、代理模式
这里简单阐述一下JDK的代理技术
静态代理
静态代理分析
- 抽象对象 : 一般使用接口或者抽象类来实现
- 真实对象 : 被代理的角色
- 代理对象 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作。如增加日志等
- 调用对象 : 使用代理角色来进行一些操作。
都学到这里了,我就不通过实际例子来说明了,通过代码进行举例
抽象对象:
public interface AbstractSubject {
void method();
}
真实对象:
public class RealSubject implements AbstractSubject{
@Override
public void method() {
System.out.println("真实对象中的method方法");
}
}
代理对象:
public class Proxy implements AbstractSubject{
private RealSubject rs;
public void setRs(RealSubject rs) {
this.rs = rs;
}
@Override
public void method() {
log();
rs.method();
}
/**
* 添加的日志功能
*/
public static void log(){
System.out.println(new Date);
}
}
调用对象:
RealSubject rs = new RealSubject();
Proxy proxy = new Proxy();
//注入真实对象到代理对象中
proxy.setRs(rs);
//调用代理对象的方法
proxy.method();
//结果:
//Thu Nov 25 01:18:24 CST 2021
//真实对象中的method方法
缺点:每一个代理对象都需要我们去编写,非常的耗时耗力,通过动态代理解决。
动态代理
基于类的动态代理–cglib,我没学就不记了
动态代理的对象和静态代理相同
抽象对象:
public interface AbstractSubject {
void method();
}
真实对象:
public class RealSubject implements AbstractSubject{
@Override
public void method() {
System.out.println("真实对象中的method方法");
}
}
动态生成代理对象:
核心 : InvocationHandler 和 Proxy
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyInvocationHandler implements InvocationHandler {
private Object object;
public void setObject(Object object) {
this.object = object;
}
//生成动态代理对象
//Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);
//loader:定义代理类的类加载器
//interfaces:代理类要实现的接口列表
//h:指派方法调用的调用处理程序
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
object.getClass().getInterfaces(),this);
}
/**
* 动态代理对象调用接口方法时自动调用该方法
* @param proxy:调用该方法的代理实例
* @param method:所述方法对应于调用代理实例上的接口方法的实例。方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口。
* @param args:参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置增强");
Object o = method.invoke(object, args);
System.out.println("后置增强");
return o;
}
}
调用对象:
RealSubject rs = new RealSubject();
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//添加真实对象到代理对象中
pih.setObject(rs);
//动态代理接口中的方法
AbstractSubject proxy = (AbstractSubject) pih.getProxy();
//代理对象调用方法
proxy.method();
9、AOP
1、什么是AOP?
AOP 为 Aspect Oriented Programming 的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
AOP 是 OOP 的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍 生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序 的可重用性,同时提高了开发的效率。
AOP底层是通过动态代理实现的!在运行期间,Spring通过动态代理技术动态的生成代理对象,代理对象方法执行时进行增强功能的介入,在去调用目标对象的方法,从而完成功能的增强。
1.2、AOP的作用以及优点
- 作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强。
- 优点:减少重复代码,提高开发效率,并且便于维护。
1.3、AOP的动态代理技术
常用的动态代理技术
- JDK 代理 : 基于接口的动态代理技术
- cglib 代理:基于父类的动态代理技术
2、AOP 的相关术语
- Target(目标对象):代理的目标对象
- Proxy (代理):一个类被 AOP 织入增强后,就产生一个结果代理类。
- Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点。
- Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。(被增强的方法)
- Advice(通知/ 增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。(即,它是切面类中的一个方法)
- Aspect(切面):是切入点和通知(引介)的结合。(即,它是一个类)
- Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而 AspectJ采用编译期织入和类装载期织入。(将切点与通知结合的过程)
3、配置详解
3.1、导入jar包
- 导入织入jar包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
- 导入Springjar包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.13</version>
</dependency>
3.2、配置详解
3.2.1、xml配置文件详解
- 导入aop约束
- aop织入的配置
<aop:config>
<aop:aspect ref=“切面类”>
<!--通知-->
</aop:aspect>
</aop:config>
- 如果多个切点表达式相同可以抽取切点表达式,通知通过pointcut-ref引入。
<aop:pointcut id="diyPonitcut" expression="execution(* com.pip.Service.UserServiceImpl.*(..))"/>
- 通知的类型:前置通知、后置通知、环绕通知、异常抛出通知、最终通知
<aop:通知类型 method="切面类中方法名" pointcut="切点表达式"></aop:通知类型>
名称 | 标签 | 说明 |
---|---|---|
前置通知 | <aop:before> | 用于配置前置通知。指定增强的方法在切入点方法之前执行 |
后置通知 | <aop:after-returning> | 用于配置后置通知。指定增强的方法在切入点方法之后执行 |
环绕通知 | <aop:around> | 用于配置环绕通知。指定增强的方法在切入点方法之前和之后都执行 |
异常抛出通知 | <aop:throwing> | 用于配置异常抛出通知。指定增强的方法在出现异常时执行 |
最终通知 | <aop:after> | 用于配置最终通知。无论增强方式执行是否有异常都会执行 |
3.2.2、切点表达式
execution([修饰符] 返回值类型 包名.类名.方法名(参数))
- 访问修饰符可以省略
- 返回值类型、包名、类名、方法名可以使用星号* 代表任意
- 包名与类名之间一个点 . 代表当前包下的类,两个点 … 表示当前包及其子包下的类
- 参数列表可以使用两个点 … 表示任意个数,任意类型的参数列表
例如:
execution(public void com.pip.aop.Target.method())
execution(void com.pip.aop.Target.*(..))
execution(* com.pip.aop.*.*(..))
execution(* com.pip.aop..*.*(..))
execution(* *..*.*(..))
4、实现AOP的三种方式
4.1、通过 Spring API 实现
通过API接口实现
编写接口类:
public interface UserService {
void add();
void delete();
void uadate();
void select();
}
实现类:
import org.springframework.stereotype.Component;
@Component()
public class UserServiceImpl implements UserService{
@Override
public void add() {
System.out.println("添加了一个用户");
}
@Override
public void delete() {
System.out.println("删除了一个用户");
}
@Override
public void uadate() {
System.out.println("修改了一个用户");
}
@Override
public void select() {
System.out.println("查询用户");
}
}
编写增强类,这里编写两个,一个前置增强 一个后置增强:
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class BeforeLog implements MethodBeforeAdvice {
//method : 要执行的目标对象的方法
//objects : 被调用的方法的参数
//Object : 目标对象
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName() + "的" + method.getName()+ "方法被执行了");
}
}
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterLog implements AfterReturningAdvice {
//returnValue 返回值
//method被调用的方法
//args 被调用的方法的对象的参数
//target 被调用的目标对象
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了" + target.getClass().getName()
+"的"+method.getName()+"方法,"
+"返回值:"+returnValue);
}
}
编写xml配置文件:
<!--头部文件导入aop约束-->
<?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.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置目标类-->
<bean id="userService" class="com.pip.Service.UserServiceImpl"/>
<!--配置切面类-->
<bean id="beforeLog" class="com.pip.log.BeforeLog"/>
<!--配置切面类-->
<bean id="afterLog" class="com.pip.log.AfterLog"/>
<aop:config>
<!--声明一个切入点 execution():匹配要执行的方法-->
<aop:pointcut id="pointcut" expression="execution(* com.pip.Service.UserServiceImpl.*(..))"/>
<!--执行环绕 advice-ref:执行方法 pointcut-ref:引用切入点-->
<aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
</beans>
测试:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
//通过接口中的方法去实现,动态代理原理
UserService userService = applicationContext.getBean("userService", UserService.class);
userService.add();
userService.uadate();
userService.delete();
userService.select();
4.2、自定义类实现
通过切面实现
接口与实现类与第一种方式相同
自定义切入类:
public class DiyPointcut {
public void before(){
System.out.println("---------方法执行前---------");
}
public void after(){
System.out.println("---------方法执行后---------");
}
}
编写xml配置文件:
<!--导入AOP约束-->
<?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.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置目标类-->
<bean id="userService" class="com.pip.Service.UserServiceImpl"/>
<!--配置切面类-->
<bean id="diy" class="com.pip.log.DiyPointcut"/>
<aop:config>
<!--引入DiyPointcut的bean为切面对象-->
<aop:aspect ref="diy">
<!--抽取出来的切点表达式,-->
<aop:pointcut id="diyPonitcut" expression="execution(* com.pip.Service.UserServiceImpl.*(..))"/>
<!--
通知配置:
method=“通知方法名称”
pointcut=“切点表达式"
pointcut-ref="引用的切点"
-->
<aop:before method="before" pointcut-ref="diyPonitcut"/>
<aop:after method="after" pointcut-ref="diyPonitcut"/>
</aop:aspect>
</aop:config>
</beans>
测试:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
UserService userService = applicationContext.getBean("userService", UserService.class);
userService.add();
userService.uadate();
userService.delete();
userService.select();
4.3、使用注解实现
- 接口类与实现类还是第一个
- 编写一个
@Aspect
增强类:
@Aspect
public class AnnotationPointcut {
//抽取切入点
@Pointcut("execution(* com.pip.Service.UserServiceImpl.*(..))")
public void myPoint(){}
@Before("AnnotationPointcut.myPoint()")
public void before(){
System.out.println("---------方法执行前---------");
}
@After("execution(* com.pip.Service.UserServiceImpl.*(..))")
public void after(){
System.out.println("---------方法执行后---------");
}
@Around("execution(* com.pip.Service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
System.out.println("签名:"+jp.getSignature());
//执行目标方法proceed
Object proceed = jp.proceed();
System.out.println("环绕后");
System.out.println(proceed);
}
}
编写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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注册切面类到配置文件,使用@Component实现同理-->
<bean id="annotationPointcut" class="com.pip.log.AnnotationPointcut"/>
<!--开启aop自动代理-->
<aop:aspectj-autoproxy/>
<!--注册实现类对象-->
<bean id="userService" class="com.pip.Service.UserServiceImpl"/>
</beans>
测试:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
UserService userService = applicationContext.getBean(UserService.class);
userService.add();
userService.uadate();
userService.delete();
userService.select();
4.3.1、注解配置 AOP 详解
-
使用**@Aspect**标注切面类
-
使用@通知注解标注通知方法
- 通知的配置语法:@通知注解(“切点表达式")
名称 注解 说明 前置通知 @Before 用于配置前置通知。指定增强的方法在切入点方法之前执行 后置通知 @AfterReturning 用于配置后置通知。指定增强的方法在切入点方法之后执行 环绕通知 @Around 用于配置环绕通知。指定增强的方法在切入点方法之前和之后都执行 异常抛出通知 @AfterThrowing 用于配置异常抛出通知。指定增强的方法在出现异常时执行 最终通知 @After 用于配置最终通知。无论增强方式执行是否有异常都会执行 -
抽取切点表达式
@Pointcut("execution(* com.pip.Service.UserServiceImpl.*(..))")
public void myPoint(){}
@Before("切入类名.myPoint()")
public void before(){}
-
在配置文件中配置aop自动代理
proxy-target-class:默认为false,设为true表示使用CGLib动态代理技术织入增强,即使proxy-target-class设置为false,但是如果目标类没有声明接口,则spring将自动使用CGLib动态代理。
<aop:aspectj-autoproxy/>
10、MyBatis-Spring
1、简介
什么是MyBatis-Spring?
MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。它将允许 MyBatis 参与到 Spring 的事务管理之中,创建映射器 mapper 和 SqlSession
并注入到 bean 中,以及将 Mybatis 的异常转换为 Spring 的 DataAccessException
。 最终,可以做到应用代码不依赖于 MyBatis,Spring 或 MyBatis-Spring。
不在需要mybaties-config配置文件,但可以在mybaties-config中保留一些MyBatis 的基础配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--set方法-->
<settings>
<setting name="" value=""/>
</settings>
<!--别名-->
<typeAliases>
</typeAliases>
</configuration>
知识基础
使用MyBatis-Spring之前需要导入各个jar包的版本
MyBatis-Spring | MyBatis | Spring 框架 | Spring Batch | Java |
---|---|---|---|---|
2.0 | 3.5+ | 5.0+ | 4.0+ | Java 8+ |
1.3 | 3.4+ | 3.2.2+ | 2.1+ | Java 6+ |
2、导入依赖
junit测试
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
Spring相关
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.13</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.13</version>
</dependency>
myBatis
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
mySql驱动
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
mybatis-spring
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
aop织入包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
3、在spring中配置数据源
将数据源配置移交给Spring容器管理
- jdbc.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/数据库名?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=123456
- spring配置
<!--加载properties文件,也可以不抽取,直接在数据源中赋值-->
<context:property-placeholder location="jdbc.properties"/>
<!--
配置数据源:
这里使用Spring自带的数据源,可使用c3p0,durid等等都可
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
4、在spring配置工厂
将SqlSessionFactory工厂交给spring来管理
- SqlSessionFactory需要一个 DataSource(数据源)。这可以是任意的 DataSource,只需要和配置其它 Spring 数据库连接一样配置它就可以了。
- 在基础的 MyBatis 用法中,是通过 SqlSessionFactoryBuilder 来创建 SqlSessionFactory 的。而在 MyBatis-Spring 中,则使用 SqlSessionFactoryBean 来创建。
- configLocation:它用来指定 MyBatis 的 XML 配置文件路径。它在需要修改 MyBatis 的基础配置非常有用。通常,基础配置指的是 < settings> 或 < typeAliases>元素。
- mapperLocations:关联Mapper.xml配置文件,相当于mybaties配置中的
<mappers>
<!-- 配置SqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--关联数据源,一个SqlSessionFactory只需要一个数据源-->
<property name="dataSource" ref="dataSource"/>
<!--关联myBatis-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:mapper/userMapper.xml"/>
</bean>
userMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.pip.mapper.UserMapper">
<select id="query" resultType="com.pip.bean.User">
select * from User
</select>
</mapper>
5、创建SqlSession
注意!!!如果你的接口实现类去继承了SqlSessionDaoSupport,请跳过这一步,直接到6.2的方法二!!!
SqlSessionTemplate
是 MyBatis-Spring 的核心。作为 SqlSession
的一个实现,这意味着可以使用它无缝代替你代码中已经在使用的 SqlSession
。 SqlSessionTemplate
是线程安全的,可以被多个 DAO 或映射器所共享使用。
(白话意思是在MyBatis中,可以使用 SqlSessionFactory
来创建 SqlSession
,但它线程不安全,在MyBatis-Spring使用SqlSessionTemplate
代替SqlSession
)
当调用 SQL 方法时(包括由 getMapper()
方法返回的映射器中的方法),SqlSessionTemplate
将会保证使用的 SqlSession
与当前 Spring 的事务相关。 此外,它管理 session 的生命周期,包含必要的关闭、提交或回滚操作。另外,它也负责将 MyBatis 的异常翻译成 Spring 中的 DataAccessExceptions
。
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--因为SqlSessionTemplate中没有set方法,所以使用构造器注入关联sqlSessionFactory工厂-->
<constructor-arg index="0" ref="sqlSessionFactory" />
</bean>
6、增加Mapper接口的实现类
6.1、方法一
私有化sqlSessionTemplate
//接口
public interface UserMapper {
List<Product> query();
}
public class UserMapperImpl implements UserMapper{
private SqlSessionTemplate sqlSession;
public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSession = sqlSessionTemplate;
}
@Override
public List<User> query() {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.query();
}
}
在spring中注册接口实现类的bean
<bean id="userMapper" class="com.pip.mapper.UserMapperImpl">
<!--将创建好的sqlSession注入到实现类的属性-->
<property name="sqlSession" ref="sqlSession"/>
</bean>
6.2、方法二
接口实现类去继承SqlSessionDaoSupport类
SqlSessionDaoSupport
的原理就是方法一
SqlSessionDaoSupport
具有getSqlSession()
方法 , 可以将SqlSessionFactory
直接注入。比起方式一 , 不需要管理SqlSessionTemplate
, 而且对事务的支持更加友好,可跟踪源码查看。
- 接口实现类
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
private SqlSession sqlSession = getSqlSession();
@Override
public List<User> query() {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.query();
}
}
- 在spring中注册接口实现类的bean
<bean id="userMapper" class="com.pip.mapper.UserMapperImpl">
<!--将创建好的sqlSessionFactory注入到实现类中的getSqlSession()方法-->
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
11、Spring事务
1、什么是事务
事务把一些列动作当成一个独立的工作单元,简单来说,这些动作要么全部完成,要么全部不起作用。
事务四大原则ACID(面试重点)
- 原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
- 一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
- 隔离性:数据库允许多个并发事务同时对一个相同数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
- 持久性:事务一旦完成,无论系统发生什么错误,结果都不会受到影响。通常情况下,事务的结果被写到持久化存储器中
2、Spring中的事务管理
Spring在不同的事务管理API之上定义了一个抽象层,使得开发人员不必了解底层的事务管理API就可以使用Spring的事务管理机制。Spring支持编程式事务管理和声明式的事务管理。
编程式事务管理
- 将事务管理代码嵌到事务方法中来控制事务的提交和回滚。
- 缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码
声明式事务管理
- 将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
- 在不需要事务管理的时候,只要在设定文件上修改一下,即可移去事务管理服务,无需改变代码重新编译 ,这样维护起来极其方便
- 将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理。
3、通过xml方式实现事务
1、引入约束
在配置文件中,引入约束:tx
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
2、配置事务管理器
- 无论使用Spring的哪种事务管理策略(编程式或者声明式)事务管理器都是必须的。
- Spring的核心事务管理抽象,管理封装了一组独立于技术的方法
<!--JDBC事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
3、配置事务通知
<tx:advice>
:配置事务通知,绑定事务管理器
<tx:method>
:
- name:切点方法名称。*代表所有方法
- isolation:事务的隔离级别
- propogation:事务的传播行为
名称 | 作用 |
---|---|
REQUIRED | 支持当前事务,如果当前没有事务,就新建一个事务。默认为这个选择 |
NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与REQUIRED类似的操作 |
- timeout:超时时间
- read-only:是否只读
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
4、织入事务
<!--织入-->
<aop:config>
<!--切入点-->
<aop:pointcut id="txPointcut" expression="execution(* com.pip.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
- 隔离性:数据库允许多个并发事务同时对一个相同数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
- 持久性:事务一旦完成,无论系统发生什么错误,结果都不会受到影响。通常情况下,事务的结果被写到持久化存储器中
2、Spring中的事务管理
Spring在不同的事务管理API之上定义了一个抽象层,使得开发人员不必了解底层的事务管理API就可以使用Spring的事务管理机制。Spring支持编程式事务管理和声明式的事务管理。
编程式事务管理
- 将事务管理代码嵌到事务方法中来控制事务的提交和回滚。
- 缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码
声明式事务管理
- 将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
- 在不需要事务管理的时候,只要在设定文件上修改一下,即可移去事务管理服务,无需改变代码重新编译 ,这样维护起来极其方便
- 将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理。
3、通过xml方式实现事务
1、引入约束
在配置文件中,引入约束:tx
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
2、配置事务管理器
- 无论使用Spring的哪种事务管理策略(编程式或者声明式)事务管理器都是必须的。
- Spring的核心事务管理抽象,管理封装了一组独立于技术的方法
<!--JDBC事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
3、配置事务通知
<tx:advice>
:配置事务通知,绑定事务管理器
<tx:method>
:
- name:切点方法名称。*代表所有方法
- isolation:事务的隔离级别
- propogation:事务的传播行为
名称 | 作用 |
---|---|
REQUIRED | 支持当前事务,如果当前没有事务,就新建一个事务。默认为这个选择 |
NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与REQUIRED类似的操作 |
- timeout:超时时间
- read-only:是否只读
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
4、织入事务
<!--织入-->
<aop:config>
<!--切入点-->
<aop:pointcut id="txPointcut" expression="execution(* com.pip.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
标签:由浅入深,对象,Spring,配置,bean,方法,public 来源: https://blog.csdn.net/qq_52799045/article/details/121578618