一、Spring简介
Spring 是由 Rod Johnson 2004 组织和开发的一个分层的 Java SE/EE fu stack (一站式)轻量级开源框架,Spring 可以被看作是一个大型工厂,这个工厂的作用就是生产和管理 Spring 容器中的Bean。它以 loC (Inversion of Control ,控制反转)和 AOP ( Aspect Oriented Programming , 面向切面编程)为内核,Spring 致力于 Java EE 应用各层的解决方案,在表现层它提供了 Spr ng MVC 以及与 Struts 框架的整合功能;在业务逻辑层可以管理事务 记录日志等;在持久层可以整合 MyBatis Hibernate JdbcTemplate 等。在 Spring 中,认为一切 Java 类都是资源,而资源都是类的实例对象(Bean),容纳并管理这些 Bean 的是 Spring 所提供的 IoC 容器,所以 Spring 是一种基于 Bean 的编程。
1、Spring核心概念
IoC(Inversion of Control ,控制反转):当某个 Java 对象(调用者)需要调用另一个 Java 对象(被调用者,即被依赖对象)时, 在传统模式下,调用者通常会采用 "new 被调用者"的代码方式来创建对象,这种方式会导致调用者与被调用者之间的捐合性增加,不利于后期项目的升级和维。在使用 Spring 框架之后,对象的实例不再由调用者来创建,而是由 Spring 容器来创建,Spring 容器会负责控制程序之间的关系,而不是由调用者的程序代码直接控制 这样,控制权由应用代码转移到了 Spring 容器,控制权发生了反转,这就是 Spring 的控制反转。
DI(Dependency Injection ,依赖注入):与控制反转 (loC) 的含义相同,只不过这两 个称呼是从两个角度描述的同一个概念 对Spring 容器的角度来看, Spring 容器负责将被依赖对象赋值给调用者的成员变量,这相当于为调用者注入了它依赖的实例,这就是 Spring 的依赖注入。依赖注入的作用就是在使用 Spring 框架创建对象时,动态地将其所依赖的对象注入Bean组件中。
AOP(Aspect Oriented Programming,面向切面编程):AOP 采取横向抽取机制,将分散在各个方法中的重复代码提取出来,然后在程序编译或运行时,再将这些提取出来的代码应用到需要执行的地方。AOP 用来封装多个类的公共行为,将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,减少系统的重复代码,降低模块间的耦合度。另外,AOP 还解决一些系统层面上的问题,比如日志、事务、权限等。
2、Spring IoC容器
Spring 框架的主要功能是通过其iOC容器来实现的,Spring 框架提供了两种IoC容器初始化方式,分别为 BeanFactory和AppIicationContext
**BeanFactory **,是基础类型的IoC容器,提供了完整的IoC服务支持。简单说它就是一个管理 Bean 的工厂,它主要负责初始化各种 Bean ,并调用它们的生命周期方法。BeanFactory最常用的实现类是XmIBeanFactory,该类会加载配置文件,根据 XML 配置文件中的定义来装配 Bean。但是此方法已不推荐使用。
ApplicationContext是BeanFactory 的子接口,也被称为应用上下文,包含了BeanFactory 的所有功能,还扩展了其它功能。
ClassPathXmlAp~licationContext 会从类路径 classPath 中寻找指定的 XML 配置文件,找到并装载完成 ApplicationContext 的实例化工作,其使用语法如下:
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Spring IoC容器(ApplicationContext)负责创建Bean,并通过容器将功能类Bean注入到你需要的Bean中。
二、体系架构

Spring 的核心容器是其他模块建立的基础,由 Beans 、Core 、Context 和 SpEL 表达式语言组成
Core 核心模块:提供了 Spring 框架的基本组成部分,包括 loC 和 DI 功能 ,是其他组件的基本核心。
Beans 模块:它包含访问配置文件、创建和管理 Bean 以及进行IOC/DI操作相关的所有类
Context 上下文模块:运行时Spring容器。建立在 Core Beans 模块的基础之上,它是访问定义和配置的任 何对象的媒介 其中 ApplicationConte 接口是上下文模块的焦点
-
SpEL 模块:是 Spring 后新增的模块,它提供了 Spring Expression Language 支持,支持在xml和注解中使用表达式类似jsp的EL表达式
2、数据访问/集成(Data Access/Integration)
JDBC 模块:提供了一个 JDBC 的抽象层,大幅度地减少了在开发过程中对数据库操作的编码
-
Transactions 事务模块:支持对实现特殊接口以及所有 POJO 类的编程和声明式的事 务管理
3、web层
Web 模块:提供了基本的 Web 开发集成特性,例如: 多文件上传功能 使用 Servlet 听器来初始化 loC 容器以及 Web 应用上下文
-
Servlet 模块:也称为 Spring-webmvc 模块,包含了 Spring 的模型一视图一控制器(MVC) REST Web Services 实现的 Web 应用程序
4、其它模块
AOP 模块:提供了面向切面编程实现,允许定义方法拦截器和切入点,将代码按照功能
进行分离,以降低搞合性
- Aspects 模块:提供了与 AspectJ 的集成功能, AspectJ 是一个功能强大且成熟的面向切
面编程 (AOP) 框架
-
Test 模块:提供了对单元测试和集成测试的支持
三、快如入门
1. Maven依赖
<!--引入spring-context包会自动引入Spring的四个核心包--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.13</version> </dependency> <!--单独引入Spring的四个核心包--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.3.14</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.14</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>5.3.14</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>5.3.14</version> </dependency>2、编写Spring的配置文件
idea在resources里创建Spring Config xml文件
applicationContext.xml(或者叫beans.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"> <!--Spring管理创建的对象,在Spring里都成为Bean,需要在这里进行注册--> <bean id="hello" class="com.example.spring.pojo.Hello"> <property name="name" value="Spring"/> </bean>
</beans>
## 3、初始化Spring容器、实例化bean
```java
public static void main(String[] args) {
// 获取ApplicationContext,拿到Spring的容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 将需要Spring管理创建对象的类在配置文件中注册,然后在需要用的地方直接get
Hello name = (Hello) context.getBean("hello");
System.out.println(name.toString());
}
四、详解 Spring容器初始化
1、非web项目
非web项目通常需要手工创建ApplicationContext
// 1.初始化 spring 容器,加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2.通过容器获取Hello实例
Hello name = (Hello) context.getBean("hello");
2、Web项目
-
在 Web 项目中, ApplicationContext 容器的实例化工作会交由 Web 服务器来完成,使用基于ContextLoader Listener实现的方式,此种方式只需要在
web.xml中添加如下代码<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- Spring配置文件默认在WEB-INF下,改到resources下--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param>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 http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--将指定类配置给 Spring ,让 Spring 创建其对象的实例--> <bean id="hello" class="com.example.spring.pojo.Hello"> <property name="name" value="Spring"/> </bean>
</beans>
# 五、详解 Bean
## 1、Bean的配置文件
- 如果在 bean中未指定id和name,Spring将会将class 值当作 id 使用。
- 在配置文件中,通常一个普通的 Bean 只需要定义 id (或 name) class 两个属性即可。
- applicationContext.xml
```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">
<!--将指定类配置给 Spring ,让 Spring 创建其对象的实例-->
<bean id="hello" class="com.example.spring.pojo.Hello">
<property name="name" value="Spring"/>
</bean>
</beans>
## 2、Bean的实例化
在 Spring 中,要想使用容器中的 Bean ,需要实例化 Bean,实例化 Bean 有三种方式,分别为:构造器实例化、静态工厂方式实例化、实例工厂方式实例化(其中最常用的是构造器实例化)。
### (1)构造器实例化
构造器实例化是指 Spring 容器通过 Bean 对应类中默认的无参构造方法来实例化 Bean。
```java
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Hello name = (Hello) context.getBean("hello");
System.out.println(name);
}
(2) 静态工厂实例化
使用静态工厂实例化Bean要求开发者创建一个静态工厂的方法来创建 Bean 的实例,其 Bean 配置中的 class 属性所指定的不再是 Bean 实例的实现类,而是静态工厂类,同时还需要使用 factory-method 属性来指定所创建的静态工厂方法。
(3)实例工厂实例化
不再使用静态方法创建 Bean 实例,而是采用直接创建 Bean 实例的方式 同时,在配置文件中,需要实例化的 Bean也不是通过 class 属性直接指向的实例化类,而是通过 factory - bean 属性指向配置的实例工厂,然后使用 factory - method 属性确定使用工厂中的哪个方法。
3、Bean的作用域
bean有七种作用域,常用的是singleton和prototype。Spring 配置文件中, Bean 的作用域是通过<bean> 元素的 scope 属性来指定的,该属性值可以设置为 singleton、prototype、request、session、globalSession、application、websocket七个值。
- singleton(单例)
使用 singleton 定义的 Bean 在Spring 容器中将只有一个实例,也就是说,无论有多少个 Bean引用它,始终将指向同一个对象,这也是 Spring 容器默认的作用域。
- prototype(原型)
每次通过 Spring 容器获取的 prototype 定义的 Bean 时,容器都将创建一个新的 Bean 实例。
<bean id="userDao" class="com.example.spring.pojo.UserDao" scope="singleton"/>
4、Bean的生命周期
Spring 容器可以管理 singleton 作用域的 Bean 的生命周期,在此作用域下, Spring 能够精确地知道该Bean 何时被创建,何时初始化完成以及何时被销毁。对于 prototype 作用域的Bean,Spring 只负责创建,当容器创建了 Bean 实例后, Bean 的实例就交给客户端代码来管理,Spring 容器将不再跟踪其生命周期 每次客户端请求 prototype 作用域的 Bean 时, Spring 容器都会创建一个新的实例,并且不会管那些被配置成 prototype 作用域的 Bean 的生命周期。
5、Bean的装配方式/Bean 依赖注入的方式
Bean 的装配可以理解为依赖关系注入, Bean 的装配方式即 Bean 依赖注入的方式。Spring 容器支持多种形式的 Bean 的装配方式,如基于 XML 的装配、基于注解( Annotation )的装配、自动装配等。最常用的是基于注解的装配
(1)基于 XML 的装配
Spring 提供了两种基于 XML 的装配方式:设值注入( Setter Injection )和构造注入 (Constructor Injection)。
使用设值注入时,在 Spring 配置文件中,需要使用 <bean> 元素的子元素<property> 来为每个属性注入值;而使用构造注入时,在配置文件里,需要使用 <bean> 元素的子元素<constructor -arg> 来定义构造方法的参数,可以使用其 value 属性(或子元素)来设置该参数的值。
1.1 设值注入
Bean 类必须提供一个默认的无参构造方法
-
Bean 类必须为需要注入的属性提供对应的 setter 方法
<bean id="hello" class="com.example.spring.pojo.Hello" > <property name="name" value="Spring"/> <property name="list"> <list> <value>"setlistvalue1"</value> <value>"setlistvalue2"</value> </list> </property> </bean>1.2 构造注入
-
Bean提供带所有参数的有参构造方法。
<bean id="hello" class="com.example.spring.pojo.Hello" > <constructor-arg index="0" name="name"/> <constructor-arg index="1"> <list> <value>"constructorvalue1"</value> <value>"constructorvalue2"</value> </list> </constructor-arg> </bean><constructor -arg >元素用于定义构造 参数 其属性 index 表示其索 引从0开始 ,value 属性用于设置注入 值,其子元素<Iist> 来为 User 类中对应的 list集合属性注入值 然后又使用了设值注入方式装 User 类的实 ,其中 <property> 元素用于调bean 实例中的 setter 方法完成属性赋值,从 依赖注入, 其子元素 Ii st> 同样是为 User类中对应 lis 集合属性注入值
(2)基于Annotation(注解)的装配
-
使用注解方式一
<context:annotation-config/>
<bean id="myService" class="com.example.spring.service.MyServiceImpl"/>
> 上述 Spring 配置文件中的注解方式虽然较大程度简化了XML 文件中 Bean 的配置,但仍需要在 Spring 配置文件中一一配置相应的 Bean,比较麻烦。
2. **使用注解方式二**
- 项目必须要导入spring-aop依赖
- 配置文件中增加如下内容
```xml
<!--使用context命名空间,通知Spring扫描指定包下所有Bean,进行注解解析-->
<context:component-scan base-packaqe="com.example.spring"/>
使用注解装配,在需要配置为bean的类上增加上述Spring注解即可
-
以下两个是完全等价的
@Service public class MyServiceImpl { ... }
```xml
<bean id="myService" class="com.example.spring.service.MyServiceImpl"/>
- Spring的注解:
@Component 把这个注解放到类上,这个类被Spring管理了,它就成了一个bean,可以作用在任何层次。`
此注解有三个衍生注解分别用在MVC的三层架构上,但是功能都是一样的,把类注册到Spring中变成bean。
@Controller 用在控制层(Controller)
@Service用在业务层(Service)
@Repository用在数据访问层(DAO)
@Autowired用于对 Bean 的属性变量、属性的 setter 方法及构造方法进行标注,配合对应的注解处理器完成 Bean 的自动配置工作。默认按照 Bean 的类型进行装配。
@Qualifier与@Autowired 注解配合使用,会将默认的按 Bean 类型装配修改为接Bean的实例名称装配, Bean 的实例名称由 @Qualifier 注解的参数指定。
@Resource其作用与 Autowired 一样,其区别在于@Autowired 默认按照 Bean 类型装配,而@Resource 默认按照 Bean 实例名称进行装配 @Resource 中有两个重要属性: name、type,Spring name 属性解析为 Bean 实例名称, type 属性解析为 Bean 实例类型 如果指定 name 属性,则按实例名称进行装配;如果指定 type 属性,则按 Bean 类型进行装配;如果都不指定,则先按 Bean 实例名称装配,如果不能匹配,再按照 Bean 类型进行装自己;如果都无法匹配,则抛出 NoSuchBeanDefinitionException 异常。
(3)自动装配
所谓自动装配,就是将一个 Bean 自动地注入到其他 Bean的Property中。Spring <bean> 元素中包含一个 autowire 属性,我们可以通过设置 autowire 的属性值,autowire=no/byType/byName/constructor,来自动装配 Bean。
-
autowire针对每个bean进行装配:
<bean id="hello" class="com.example.spring.pojo.Hello" autowire="byType"/><bean id="hello" class="com.example.spring.pojo.Hello" autowire="byName"/>byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的bean id
byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean id
六、AOP
1、AOP简介
(1)什么是AOP
AOP 的全称是 Aspect-Oriented Programming ,即面向切面编程(也称面向方面编程),) 是面向对象编程 (OOP) 的一种补充。
AOP 采取横向抽取机制,将分散在各个方法中的重复代码提取出来,然后在程序编译或运行时,再将这些提取出来的代码应用到需要执行的地方。AOP 用来封装多个类的公共行为,将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,减少系统的重复代码,降低模块间的耦合度。另外,AOP 还解决一些系统层面上的问题,比如日志、事务、权限等。
AOP 框架有两个,分别为 Spring AOP、AspectJ。
(2)AOP术语
Aspect (切面):切面通常是指封装的用于横向插入系统功能(如事务、曰志等)的类
Joinpoint (连接点):连接点就是指方法的调用
Pointcut (切入点):通常指的是类或者方法名,如某个通知要应用到所有以 add开头的方法中,那么所有以 add开头的方法都是切入点****
Advice( 通知):AOP 框架在特定的切入点执行的增强处理,即在定义好的切入点处所要执行的程序代码。可以将其理解为切面类中的方法,它是切面的具体实现
Target Object (目标对象):是指所有被通知的对象
Proxy (代理):将通知应用到目标对象之后,被动态创建的对象
-
Weaving (织入):将切面代码插入到目标对象上,从而生成代理对象的过程
2、动态代理
(1)JDK动态代理
待补充。。。
(2)CGLIB代理
待补充。。。
3、AspectJ
依赖包
spring-aspects:Spring AspectJ 提供的实现, Spring 的包中已经提供
-
aspectjweaver:: AspectJ 框架所提供的规范
(1)基于XML的声明式AspectJ
待补充。。。
(2)基于注解的声明式AspectJ
- 注解
- @Aspect
- @Pointcut
- @Before
- @AfterReturning
- @Around
- @@AfterThrowing
- @After
- @DeclareParents
-
案例
@Aspect @Component public class MyAspect { private Logger logger = LoggerFactory.getLogger(MyAspect.class); // 定义切入点表达式 @Pointcut(value = "execution( * com.example.spring.controller.*.*(..))") public void myPoinCut(){} // 前置通知 @Before("myPoinCut()") public void myBefore(JoinPoint joinPoint) { System.out.println("前置通知:模拟检查...."); System.out.println("目标类是:"+joinPoint.getTarget()); System.out.println(",被植入增强处理的目标方法为:"+joinPoint.getSignature().getName()); } // 后置通知 @AfterReturning("myPoinCut()") public void myAfterReturning(JoinPoint joinPoint) { System.out.println("后置通知:模拟记录日志...."); System.out.println(",被植入增强处理的目标方法为:"+joinPoint.getSignature().getName()); } // 环绕通知 @Around("myPoinCut()") public Object myLogger(ProceedingJoinPoint pjp) throws Throwable { String className = pjp.getTarget().getClass().toString(); String methodName = pjp.getSignature().getName(); Object[] array = pjp.getArgs(); ObjectMapper mapper = new ObjectMapper(); logger.info("调用前:"+className+":"+methodName+"传递的参数为:"+mapper.writeValueAsString(array)); // 执行当前目标方法 Object obj = pjp.proceed(); logger.info("调用后:"+className+":"+methodName+"返回值:"+mapper.writeValueAsString(obj)); return obj; } // 异常通知 public void myAfterThrowing(JoinPoint joinPoint, Throwable e) { System.out.println("异常通知:出错了," + e.getMessage()); } // 最终通知 @After("myPoinCut()") public void myAfter(){ System.out.println("最终通知:结束了..."); } }首先使用 @Aspect 注解定义了 切面 ,由于该类在Spring中是作为组件使用的,所以还需要添加@Component 注解才能生效,然后使@Poincut 注解来配置切入点表达式,并通过定义方法来表示切入点名称,接下来在每个通知对应的方法上添加了相应的注解,并将切入点名称 "myPointCut" 作为参数传递给需要执行增强的通知方法。如果需要其他参数,如异常通知的异常参数 ,可以根据代码提示传递相应的属性值。
参考:https://www.bilibili.com/video/BV1yK411M7hb?p=2七、Spring JDBC
Spring JDBC 模块负责数据库资源管理,JdbcTemplate 类是 Spring JDBC 的核心类
1、添加依赖
<!--spring-jdbc依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.13</version> </dependency> <!--mysql驱动依赖--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.27</version> </dependency>2、添加JDBC配置
<?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 https://www.springframework.org/schema/context/spring-context.xsd"><context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="{jdbc.jdbcUrl}"/>
<property name="username" value="{jdbc.password}"/>
</bean><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
> 定义 jdbcTemplate 时,需要将 dataSource 注入到 jdbcTemplate 中,而其他需要使用jdbcTemplate的Bean ,也需要将 jdbcTemplate 注入到该 Bean 中(通常注入到 Dao 类中,在Dao 类中进行与数据库的相关操作)。
## 3、使用Spring JdbcTemplate
```java
@Test
public void createTest() {
// 获取Spring容器
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获得JdbcTemplate实例
JdbcTemplate jdbcTemplate = (JdbcTemplate) applicationContext.getBean("jdbcTemplate");
// 创建表
jdbcTemplate.execute("CREATE TABLE `student` (\n" +
" `id` int(11) NOT NULL,\n" +
" `name` varchar(255) DEFAULT NULL,\n" +
" `age` int(11) DEFAULT NULL,\n" +
" PRIMARY KEY (`id`)\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;");
}
4、jdbcTemplate的常用方法
创建Student POJO
-
创建Student增、删、改、查的Service接口,这里直接创建了类
public class StudentServiceImpl { private JdbcTemplate jdbcTemplate; public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } // 增加 public int addStudent(Student student) { String sql = "insert into student(age,name) values(?,?)"; // 定义个数组存储sql语句中的参数 // sql语句里的参数顺序必须和传进去的参数顺序一致 Object[] obj = new Object[]{ student.getAge(), student.getName() }; int num = this.jdbcTemplate.update(sql, obj); return num; } // 更新 public int updateStudent(Student student) { // sql语句里的参数顺序必须和传进去的参数顺序一致 String sql = "update student set name=?,age=? where id=?"; Object[] params = new Object[]{ student.getName(), student.getAge(), student.getId() }; int num = this.jdbcTemplate.update(sql, params); return num; } // 删除 public int deleteStudent(int id) { String sql = "delete from Student where id = ?"; int num = this.jdbcTemplate.update(sql, id); return num; } // 查询一个 public Student findStudentById(int id) { String sql = "select * from student where id = ?"; BeanPropertyRowMapper<Student> rowMapper = new BeanPropertyRowMapper<Student>(Student.class); return this.jdbcTemplate.queryForObject(sql, rowMapper, id); } // 查询所有 public List<Student> findAllStudent() { String sql = "select * from student"; BeanPropertyRowMapper<Student> rowMapper = new BeanPropertyRowMapper<Student>(Student.class); return this.jdbcTemplate.query(sql, rowMapper); } } 在appcliationContext.xml里定义一个id为studentService的Bean,用于将jdbcTemplate注入到StudentService实例中。
-
在单元测试类中测试增、删、改、查。
@Test public void addStudentTest() { // 获取Spring容器 ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); StudentServiceImpl studentService = (StudentServiceImpl) applicationContext.getBean("studentService"); Student student = new Student(); student.setAge(19); student.setName("xie"); int num = studentService.addStudent(student); if (num > 0) { System.out.println("成功插入了" + num + "条数据"); } else { System.out.println("插入失败!"); } } @Test public void updateStudentTest() { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); StudentServiceImpl studentService = (StudentServiceImpl) applicationContext.getBean("studentService"); Student student = new Student(); student.setId(1); student.setName("谢"); student.setAge(28); int num = studentService.updateStudent(student); System.out.println(num); } @Test public void deleteStudentTest() { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); StudentServiceImpl studentService = (StudentServiceImpl) applicationContext.getBean("studentService"); int num = studentService.deleteStudent(1); System.out.println(num); } @Test public void findByIdTest() { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); StudentServiceImpl studentService = (StudentServiceImpl) applicationContext.getBean("studentService"); Student student = studentService.findStudentById(1); System.out.println(student); } @Test public void findAll() { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); StudentServiceImpl studentService = (StudentServiceImpl) applicationContext.getBean("studentService"); List<Student> student = studentService.findAllStudent(); System.out.println(student); }八、Spring 事务
jar包spring-tx是Spring 提供的用于事务管理的依赖包。Spring 中的事务管理分为两种方式:一种是传统的编程式事务管理,另一种是声明式事务管理。
编程式事务管理:是通过编写代码实现的事务管理,包括定义事务的开始、正常执行后的事务提交和异常时的事务回滚 。
声明式事务管理:是通过 AOP 技术实现的事务管理,其主要思想是将事务管理作为一个
切面代码单独编写,然后通过 AOP 技术将事务管理的切面代码织入到业务目标类中。
Spring 的声明式事务管理可以通过两种方式来实现,一种是基于 XML 的方式,另一种是基 Annotation 的方式。
1、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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 导入资源文件 读取db.properties文件中的数据 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClass}"/>
<property name="url" value="${jdbc.jdbcUrl}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 配置Spring的jdbcTemplate 并注入dataSource数据源-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置注入类-->
<bean id="studentService" class="com.example.spring.service.StudentServiceImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<!--事务管理器,依赖于数据源-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:advice id="txAdvice"
transaction-manager="transactionManager">
<!-- 配置这个事务建议的属性 -->
<tx:attributes>
<!-- 指定所有get开头的方法执行在只读事务上下文中 -->
<tx:method name="get*" read-only="true"/>
<!-- 其余方法执行在默认的读写上下文中 -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<aop:config>
<!-- <aop:pointcut/>元素定义AspectJ的切面表示法,这里是表示x.y.service.FooService包下的任意方法。 -->
<aop:pointcut id="txPointCut" expression="execution(* com.example.spring.service.*.*(..))"/>
<!-- 然后我们用一个通知器:<aop:advisor/>把这个切面和tx:advice绑定在一起,表示当这个切面:fooServiceOperation执行时tx:advice定义的通知逻辑将被执行 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
</beans>
2、注解方式
在Spring 容器中注册事务注解驱动。
<tx:annotation-driven transaction-manager="transactionManager"/>
在需要使用事务的 Spring Bean 类或者 Bean 类的方法上添加注解@Transactional如果将注解添加在 Bean 类上,则表示事务的设置对整个 Bean 类的所有方法都起作用;如果将注解添加在 Bean 类中的某个方法上,则表示事务的设置只对该方法有效。
默认情况下,在遇到运行时异常和Error,Spring事务会进行回滚,而遇到非运行时异常Exception则不会回滚。
九、Spring Test单元测试
在利用JUnit4做单元测试的时候,通常要在Before方法中,初始化Spring容器,导致容器被初始化多次。并且通过context.getBean()方法从Spirng容器中获取需要测试的目标Bean,并且还要进行强制类型转换的造型操作,操作繁琐。
@Before
public void init() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
baseDao = (IBaseDao) context.getBean("baseDao");
assertNotNull(baseDao);
}
-
依赖
<!--单元测试--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.3.15</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> -
使用spring-test后做junit单元测试
//指定单元测试环境 @RunWith(SpringJUnit4ClassRunner.class) //指定配置文件路径 @ContextConfiguration(locations = {"/applicationContext.xml","*.xml"}) public class MaxTest { // 自动注入 @Autowired private Max max; @Test public void getMax() throws Exception { assertEquals(5,max.getMax()); }
}
# 十、计划任务
applicationContext.xml增加如下配置
```xml
<!--定时任务注解-->
<task:annotation-driven/>
@Component
public class xxxTask {
@Scheduled(cron = "0/5 * * * * ? ") // 间隔5秒执行
public void xxx() {
System.out.println("----定时任务执行中-----");
}
}
十一、Spring工具类
待补充......
十二、Spring与Mybatis整合
-
pom.xml
<dependencies> <!--Spring核心依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.14</version> </dependency> <!--Spring事务依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.14</version> </dependency> <!--Mybatis依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.9</version> </dependency> <!--Mybatis与Spring结合的依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.3</version> </dependency> <!--Mysql驱动依赖--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.27</version> </dependency> <!--druid连接池依赖--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.4</version> </dependency> <!--单元测试依赖--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> -
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" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!--读取db.properties--> <context:property-placeholder location="classpath:db.properties"/> <!--配置数据源--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <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> <!--事务管理器,依赖于数据源--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--开启事务注解--> <tx:annotation-driven transaction-manager="transactionManager"/> <!--配置MyBatis工厂--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!--引用数据源--> <property name="dataSource" ref="dataSource"/> <!--指定配置文件路径、xml文件目录--> <property name="configLocation" value="classpath:mybatis-config.xml"/> <property name="mapperLocations" value="classpath:mapper/*.xml"/> </bean> <!--配置扫描Mybatis的接口所在目录--> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.example.spring.mapper"/> </bean> <!-- druid --> <bean id="stat-filter" class="com.alibaba.druid.filter.stat.StatFilter"> <property name="slowSqlMillis" value="3000" /> <property name="logSlowSql" value="true" /> <property name="mergeSql" value="true" /> </bean> <bean id="wall-filter" class="com.alibaba.druid.wall.WallFilter"> <property name="dbType" value="mysql" /> </bean> <!--自动扫描包下的注解,注册为Spring Bean--> <context:component-scan base-package="com.example.spring"/> </beans> -
mybatis-config.xml
<?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><settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="safeRowBoundsEnabled" value="true"/>
<setting name="cacheEnabled" value="false" />
</settings><typeAliases>
<package name="com.example.model"/>
</typeAliases>
</configuration>
4. db.properties
```xml
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=dbc:mysql://localhost:3306/test?characterEncoding=UTF-8
jdbc.username=root
jdbc.password=root
-
测试
@Test public void testSpring() { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); StudentService studentService = (StudentService) applicationContext.getBean("studentService"); studentService.Student(); System.out.println("hhh"); System.out.println("test"); }
@Service
public class StudentService {
public void Student() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
StudentMapper studentMapper = (StudentMapper) applicationContext.getBean("studentMapper");
List<Student> allStudent = studentMapper.findAllStudent();
System.out.println(allStudent);
}
}
```java
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4d518b32] will not be managed by Spring
==> Preparing: select * from test.student;
==> Parameters:
<== Columns: id, name, age
<== Row: 1, x, 1
<== Row: 2, f, 2
<== Total: 2
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@723e88f9]
[com.example.spring.pojo.Student@7d3d101b, com.example.spring.pojo.Student@30c8681]