Spring初识
Spring简介
Spring 是一个开源的轻量级 JavaEE(现在称为 Jakarta EE)开发框架,用于构建企业级应用程序和分布式系统。它提供了一种简化和解耦应用程序组件的方式,使开发人员能够更加专注于业务逻辑的实现,而不需要过多关心底层的技术细节。Spring 框架包含多个模块,每个模块提供不同的功能,如依赖注入、面向切面编程、事务管理、Web 开发等。
Spring核心概念
- IoC(Inversion of Control)控制反转: IoC 是 Spring 的核心思想,它通过将对象的创建、组装和管理交给 Spring 容器来实现,从而减少了代码之间的耦合。开发人员只需要声明需要的组件,而不需要自己创建和管理对象。Spring 使用依赖注入(DI)来实现 IoC。
- DI(Dependency Injection)依赖注入: 依赖注入是 IoC 的具体实现,通过注入组件之间的依赖关系,实现了对象之间的解耦。Spring 通过注解或配置文件来声明依赖关系,然后将需要的依赖自动注入到对象中。
- AOP(Aspect-Oriented Programming)面向切面编程: AOP 是一种编程范式,它允许开发人员将横切关注点(如日志记录、事务管理)从业务逻辑中分离出来,以便更好地维护和管理。Spring AOP 提供了切面的实现,使得开发人员能够在方法执行前、执行后或抛出异常时插入额外的逻辑。
- Spring MVC: Spring MVC 是 Spring 框架的一个模块,用于构建 Web 应用程序。它提供了 MVC(Model-View-Controller)的架构,使开发人员能够将应用程序的不同方面进行分离,从而更好地管理和扩展。
- Spring Boot: Spring Boot 是 Spring 生态系统中的一个子项目,旨在简化 Spring 应用程序的构建和部署。它提供了自动化配置、快速开发和微服务的支持,让开发人员能够更加轻松地创建独立的、可执行的 Spring 应用程序。
- Spring Data: Spring Data 提供了一种统一的方式来访问和操作各种不同类型的数据源,如关系型数据库、NoSQL 数据库、搜索引擎等。它简化了数据访问层的开发,并提供了常见的 CRUD 操作以及查询的支持。
- Spring Security: Spring Security 是 Spring 框架的安全性模块,用于实现身份验证、授权、安全配置等功能,保护应用程序免受各种安全威胁。
- Spring Cloud: Spring Cloud 是用于构建分布式系统和微服务架构的一组工具和框架。它提供了服务注册与发现、负载均衡、断路器、配置管理等功能,帮助开发人员构建可靠的、可扩展的分布式应用。
- Spring Integration: Spring Integration 提供了一种将不同系统和应用程序集成到一起的方式,支持消息传递、异步通信、数据转换等。
搭建Spring框架工程
- 新建maven项目
- 导入spring context jar包
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.10</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies> - 创建bean对象
package com.acaiblog.spring.pojo;
public class User {
private Integer id;
private String name;
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
} - 创建配置文件applicationContext.xml
<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="user" class="com.acaiblog.spring.pojo.User">
<property name="id" value="1"/>
<property name="name" value="acai"/>
</bean>
</beans> - 测试Spring
import com.acaiblog.spring.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring {
public void test(){
// 创建容器对象
ApplicationContext aplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取配置bean
User user = aplicationContext.getBean("user", User.class);
System.out.println(user);
}
} - 测试结果
User{id=1, name='acai'}
Spring特性
- 非侵入式:基于Spring开发的应用中的对象可以不依赖于Spring的APi
- 容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期
- 组件化:Spring实现了简单的组件化配置组合成一个复杂的应用,在Spring中可以使用XML和JAVA注解组合这些对象
- 一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库
Spring获取bean的三种方式
getBean(String beanId)
:通过beanId获取对象;缺点:需要强制类型转换,不灵活。getBean(Class clazz)
:通过Class对象获取对象;缺点:容器中有多个bean会报错getBean(String beanId,Class clazz)
:通过beanId和Class对象
Bean标签
在Spring Framework中,”bean” 是一个核心概念,用于定义应用程序中的各种组件、对象或服务。Spring的IoC(Inversion of Control,控制反转)容器负责管理和实例化这些bean。在XML配置文件中,使用
Bean标签属性
属性 | 描述 |
---|---|
id | 表示bean的唯一标识符,应该在整个Spring上下文中是唯一的。 |
class | 指定bean的全限定类名,用于告诉Spring容器应该实例化哪个类来创建bean对象。 |
scope | 定义bean的作用域,常用的有singleton(单例,默认)、prototype(原型)、request、session等。例如:scope="singleton" 。 |
init-method | 指定在bean初始化之后调用的方法。 |
destroy-method | 指定在bean销毁之前调用的方法。 |
Bean子标签property属性
property主要是用来给类对象方法注入参数
属性 | 描述 |
---|---|
name | 指定bean的属性名。 |
value | 设置基本数据类型的属性值。 |
ref | 引用其他bean作为属性值。 |
Bean子标签constructor-arg属性
constructor-arg标签主要是用来给构造器注入参数
属性名称 | 描述 |
---|---|
index | 构造函数参数的索引(从0开始)。 |
type | 参数的数据类型。 |
value | 参数的值,可以是字符串、基本类型或引用。 |
ref | 参数的引用,指向另一个bean的id。 |
name | 参数的名称,用于指定构造函数的参数名。 |
SpringIOC底层实现
BeanFactory与ApplicationContext
- BeanFactory:IOC容器的基本实现,是Spring内部的接口。
- ApplicationContext:是BeanFactory的子接口,提供更多高级的特性。面向Spring使用者,几乎所有场合都使用ApplicationContext而不是BeanFactory
Spring数值的注入方式
- set方法
- 通过构造器
- 名称空间注入
set注入
语法
<bean id="user" class="com.acaiblog.spring.pojo.User"> |
构造器注入
<bean id="user" class="com.acaiblog.spring.pojo.User"> |
名称空间注入
<bean id="user" |
外部已声明bean
如果想通过查询员工信息的同时获取员工所在部门信息就需要使用外部已声明bean
- 员工bean
package com.acaiblog.spring.pojo;
public class Employee {
private Integer id;
private String name;
private String email;
private Dept dept;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
", dept=" + dept +
'}';
}
} - 部门bean
package com.acaiblog.spring.pojo;
public class Dept {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String toString() {
return "Dept{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
} - Spring配置文件
<bean id="dept1" class="com.acaiblog.spring.pojo.Dept">
<property name="id" value="1"/>
<property name="name" value="运维部"/>
</bean>
<bean id="employee" class="com.acaiblog.spring.pojo.Employee">
<property name="id" value="1"/>
<property name="name" value="acai"/>
<property name="email" value="baocai.guo@qq.com"/>
<property name="dept" ref="dept1"/>
</bean> - 测试代码
import com.acaiblog.spring.pojo.Employee;
import com.acaiblog.spring.pojo.User;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring {
public void test(){
// 创建容器对象
ApplicationContext aplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取配置bean
Employee employee = aplicationContext.getBean("employee", Employee.class);
System.out.println(employee);
}
} - 测试结果
Employee{id=1, name='acai', email='baocai.guo@qq.com', dept=Dept{id=1, name='运维部'}}
bean级联属性赋值
<bean id="dept1" class="com.acaiblog.spring.pojo.Dept"> |
内部bean属性赋值
内部bean不会覆盖外部bean的属性值
<bean id="employee" class="com.acaiblog.spring.pojo.Employee"> |
bean List集合注入赋值
需求
比如云计算事业部,有两个员工。使用List集合的方式展示数据
- 在Dept pojo中新增employeeList类属性,并且新增get、set、tostring方法
public class Dept {
private List<Employee> employeeList;
public List<Employee> getEmployeeList() {
return employeeList;
}
public void setEmployeeList(List<Employee> employeeList) {
this.employeeList = employeeList;
}
public String toString() {
return "Dept{" +
"id=" + id +
", name='" + name + '\'' +
", employeeList=" + employeeList +
'}';
}
} - 编辑bean
<bean id="zhangsan" class="com.acaiblog.spring.pojo.Employee">
<property name="id" value="1"/>
<property name="name" value="zhangsan"/>
<property name="email" value="zhangsan@qq.com"/>
</bean>
<bean id="lisi" class="com.acaiblog.spring.pojo.Employee">
<property name="id" value="2"/>
<property name="name" value="lisi"/>
<property name="email" value="lisi@qq.com"/>
</bean>
<bean id="dept" class="com.acaiblog.spring.pojo.Dept">
<property name="id" value="1"/>
<property name="name" value="云计算事业部"/>
<property name="employeeList">
<list>
<ref bean="zhangsan"/>
<ref bean="lisi"/>
</list>
</property>
</bean> - 测试代码
public class TestSpring {
public void test(){
// 创建容器对象
ApplicationContext aplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取配置bean
Dept dept = aplicationContext.getBean("dept", Dept.class);
System.out.println(dept);
}
} - 测试结果
Dept{id=1, name='云计算事业部', employeeList=[Employee{id=1, name='zhangsan', email='zhangsan@qq.com', dept=null, empList=null}, Employee{id=2, name='lisi', email='lisi@qq.com', dept=null, empList=null}]}
bean Map集合注入赋值
- 在Dept pojo类新增map属性
public class Dept {
private Map<String, Employee> employeeMap;
public Map<String, Employee> getEmployeeMap() {
return employeeMap;
}
public void setEmployeeMap(Map<String, Employee> employeeMap) {
this.employeeMap = employeeMap;
}
public String toString() {
return "Dept{" +
"id=" + id +
", name='" + name + '\'' +
", employeeList=" + employeeList +
", employeeMap=" + employeeMap +
'}';
}
} - 编辑Spring bean配置文件
<bean id="zhangsan" class="com.acaiblog.spring.pojo.Employee">
<property name="id" value="1"/>
<property name="name" value="zhangsan"/>
<property name="email" value="zhangsan@qq.com"/>
</bean>
<bean id="lisi" class="com.acaiblog.spring.pojo.Employee">
<property name="id" value="2"/>
<property name="name" value="lisi"/>
<property name="email" value="lisi@qq.com"/>
</bean>
<bean id="dept" class="com.acaiblog.spring.pojo.Dept">
<property name="id" value="1"/>
<property name="name" value="云计算事业部"/>
<property name="employeeMap">
<map>
<entry>
<key><value>111</value></key>
<ref bean="zhangsan"/>
</entry>
<entry>
<key><value>222</value></key>
<ref bean="lisi"/>
</entry>
</map>
</property>
</bean> - 测试代码
public class TestSpring {
public void test(){
// 创建容器对象
ApplicationContext aplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取配置bean
Dept dept = aplicationContext.getBean("dept", Dept.class);
System.out.println(dept);
}
} - 测试结果
Dept{id=1, name='云计算事业部', employeeList=null, employeeMap={111=Employee{id=1, name='zhangsan', email='zhangsan@qq.com', dept=null, empList=null}, 222=Employee{id=2, name='lisi', email='lisi@qq.com', dept=null, empList=null}}}
Spring管理第三方bean
Spring管理druid
- 导入jar依赖包
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.18</version>
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>3.1.4</version>
</dependency> - 编写数据库配置文件
#db.properties
db.driver=org.mariadb.jdbc.Driver
db.url=jdbc:mariadb://acaiblog.top:3306/spring
db.username=root
db.password=123456 - 在beans配置文件中加载数据库配置文件
<context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
<!-- 装配数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
</bean> - 测试代码
public class TestSpring {
public void test() throws Exception{
// 创建容器对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取bean
DruidDataSource druidDataSource = applicationContext.getBean("dataSource", DruidDataSource.class);
// 连接数据库对象
DruidPooledConnection druidPooledConnection = druidDataSource.getConnection();
System.out.println(druidPooledConnection);
}
}
Spring FactoryBean
FactoryBean 是 Spring 框架中的一个接口,用于创建和管理 Spring 容器中的对象。它允许开发人员在创建 bean 实例时进行更加灵活和自定义的操作。通过实现 FactoryBean 接口,您可以控制 bean 的实例化、初始化和销毁过程,以及对外暴露的对象类型。
内置方法
方法 | 描述 |
---|---|
getObject() |
实际创建和返回 bean 实例,可以执行自定义逻辑,如从外部资源加载数据、实例化其他对象等。 |
getObjectType() |
返回由 FactoryBean 创建的对象的类型,通常用于告诉 Spring 容器实际创建的 bean 类型。 |
isSingleton() |
返回一个布尔值,指示由 FactoryBean 创建的对象是否是单例(singleton)或原型(prototype)。 |
实现步骤
- 重写FactoryBean方法
package com.acaiblog.spring.Factory;
import com.acaiblog.spring.pojo.Dept;
import org.springframework.beans.factory.FactoryBean;
public class MyFactoryBean implements FactoryBean<Dept> {
public boolean isSingleton() {
/**设置参数是否为单例*/
return FactoryBean.super.isSingleton();
}
public Dept getObject() throws Exception {
/**参数对象创建的方法,比如:创建一个部门然后将部门返回*/
Dept dept = new Dept(1,"运维部");
return dept;
}
public Class<?> getObjectType() {
/**设置参数对象class*/
return Dept.class;
}
} - 装配Bean
<bean id="factoryBean" class="com.acaiblog.spring.Factory.MyFactoryBean">
- 测试代码
public class TestSpring {
public void test() throws Exception{
// 创建容器对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取bean
Dept dept = applicationContext.getBean("factoryBean", Dept.class);
System.out.println(dept);
}
} - 测试结果
Dept{id=1, name='运维部', employeeList=null, employeeMap=null}
Spring Bean的作用域
语法
在 Spring 配置文件中使用
<bean id="myBean" class="com.example.MyBean" scope="prototype"/> |
作用域
作用域 | 描述 |
---|---|
singleton | 每个 Spring 容器中只会存在一个单例的 Bean 实例。在应用程序生命周期内,只会创建一个 Bean 实例并缓存以供后续使用。 |
prototype | 每次请求该 Bean 时,都会创建一个新的实例。不同地方请求该 Bean 会得到不同的实例。 |
request | 在 Web 应用中有效,每个 HTTP 请求都会创建一个新的 Bean 实例,在整个请求周期内有效。不同请求间可对应不同的实例。 |
session | 在 Web 应用中有效,每个用户会话(Session)都会创建一个新的 Bean 实例,在整个会话周期内有效。不同用户对应不同的实例。 |
application | 在 Web 应用中有效,每个 ServletContext(Web 应用上下文)都会创建一个新的 Bean 实例,在整个应用生命周期内有效。 |
websocket | 在 Web 应用中有效,每个 WebSocket 会话都会创建一个新的 Bean 实例,在整个 WebSocket 会话周期内有效。 |
custom | 您可以实现自定义的作用域,通过实现 org.springframework.beans.factory.config.Scope 接口来定义更灵活的作用域。 |
Spring Bean生命周期
在Spring框架中,Bean的生命周期是指一个Bean从被创建到被销毁的整个过程。Spring框架提供了丰富的生命周期回调方法,可以让开发者在不同的阶段进行自定义操作。
BeanFactory接口描述
接口名称 | 特点 |
---|---|
ConfigurableApplicationContext | 可配置和修改应用程序上下文,包含刷新和关闭方法。 |
ApplicationContext | 提供核心功能的只读应用程序上下文,无法在运行时修改或重新配置。 |
生命周期步骤
- 创建Student类
package com.acaiblog.spring.pojo;
public class Student {
private Integer id;
private String name;
public void Init(){
System.out.println("初始化方法");
}
public void Destory(){
System.out.println("销毁方法");
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
} - 设置Bean属性值,init-method在示例创建之前调用初始化的方法;destroy-method容器关闭之后调用销毁方法
<bean id="student" class="com.acaiblog.spring.pojo.Student" init-method="Init" destroy-method="Destory">
<property name="id" value="1"/>
<property name="name" value="慕容峻才"/>
</bean> - 测试代码
public class TestSpring {
public void test() throws Exception{
// 创建容器对象使用ConfigurableApplicationContext可以关闭容器,用来自动调用销毁方法
ConfigurableApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取bean
Student student = applicationContext.getBean("student", Student.class);
System.out.println(student);
// 调用Bean中定义的destroy-method方法
applicationContext.close();
}
} - 测试结果
初始化方法
Student{id=1, name='慕容峻才'}
销毁方法
Bean的后置处理器
作用
在初始化前后对bean进行额外的处理
实现步骤
- 实现BeanPostProcessor接口
package com.acaiblog.spring.processor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
/**
* Bean初始化之前执行
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean初始化之前执行");
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
/**
* Bean初始化之后会执行
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean初始化之后执行");
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
} - Bean配置文件装配后置处理器
<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" 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">
<bean id="student" class="com.acaiblog.spring.pojo.Student" init-method="Init" destroy-method="Destory">
<property name="id" value="1"/>
<property name="name" value="慕容峻才"/>
</bean>
<bean class="com.acaiblog.spring.processor.MyBeanPostProcessor"/>
</beans>
Spring基于xml自动装配
根据bean标签的autowire属性指定装配规则,不需要明确指定。Spring自动将匹配的属性值注入bean中。autowire属性值如下表:
属性名 | 描述 |
---|---|
byName | 按组件名称自动装配 |
byType | 按组件类型自动装配 |
constructor | 通过构造函数自动装配 |
环境搭建
- 创建部门接口
package com.acaiblog.spring.dao;
import com.acaiblog.spring.pojo.Dept;
public interface DeptDao {
/**
* 添加部门信息
* @param dept
*/
public void insertDept(Dept dept);
} - 创建部门的实现类
package com.acaiblog.spring.dao.Impl;
import com.acaiblog.spring.dao.DeptDao;
import com.acaiblog.spring.pojo.Dept;
public class DeptDaoImpl implements DeptDao {
public void insertDept(Dept dept) {
System.out.println("添加部门成功");
}
} - 创建部门的service
package com.acaiblog.spring.service;
import com.acaiblog.spring.pojo.Dept;
public interface DeptService {
/**
* 添加部门信息
* @param dept
*/
public void save(Dept dept);
} - 创建部门service的实现类
package com.acaiblog.spring.service.Impl;
import com.acaiblog.spring.dao.DeptDao;
import com.acaiblog.spring.pojo.Dept;
import com.acaiblog.spring.service.DeptService;
public class DeptServiceImpl implements DeptService {
private DeptDao deptDao;
public void save(Dept dept) {
deptDao.insertDept(dept);
}
} - 测试代码
public class TestSpring {
public void test() throws Exception{
// 创建容器对象使用ConfigurableApplicationContext可以关闭容器,用来自动调用销毁方法
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
// 获取bean
DeptService deptService = applicationContext.getBean("deptService", DeptService.class);
deptService.saveDept(new Dept());
}
}
byName自动装配
对象中属性与容器中的beanId进行匹配,如果属性名和beanId匹配成功则自动装配成功
<bean id="deptDao" class="com.acaiblog.spring.dao.Impl.DeptDaoImpl"></bean> |
byType自动装配
对象中的属性类型与容器中bean的class进行匹配,如果唯一匹配则自动装配成功
<bean id="deptDao" class="com.acaiblog.spring.dao.Impl.DeptDaoImpl"></bean> |
总结
- 基于xml的自动装配,底层使用set注入
- 不建议使用byName、byType,建议实现注解的方式实现自动装配
Spring中的注解
搭建环境
创建spring工程day07_spring导入spring相关依赖包
<dependencies> |
创建Employee pojo
package com.acaiblog.spring.pojo; |
创建dept pojo
package com.acaiblog.spring.pojo; |
创建Dept接口
package com.acaiblog.spring.dao; |
创建DeptDaoImpl
package com.acaiblog.spring.dao.impI; |
创建DeptService
package com.acaiblog.spring.service; |
创建DeptServiceImpl
package com.acaiblog.spring.service.impl; |
创建DeptController
package com.acaiblog.spring.controller; |
创建spring配置文件
|
创建测试代码,验证环境没有问题
import com.acaiblog.spring.dao.impI.DeptDaoImpl; |
使用注解将对象装配到IOC容器中
注解的位置: 在类的上面标识
使用注解装配:默认将类名首字母小写作为bean id;可以使用value属性为类的bean id指定id;当注解中只使用一个value属性时,value关键字可以省略
使用注解的步骤:导入相关jar包,spring默认已经导入;开启组件扫描;使用注解标识组件
注解 | 描述 |
---|---|
@Autowired |
自动装配依赖关系。 |
@Component |
通用的Spring组件注解。 |
@Controller |
标识控制器类。 |
@Service |
标识服务类。 |
@Repository |
标识数据访问对象(DAO)类。 |
注解实现步骤
- DeptDaoImpl中定义注解
package com.acaiblog.spring.dao.impI;
import com.acaiblog.spring.dao.DeptDao;
import com.acaiblog.spring.pojo.Dept;
import org.springframework.stereotype.Repository;
public class DeptDaoImpl implements DeptDao {
public void insertDept(Dept dept) {
System.out.println("添加部门成功");
}
} - pojo中定义注解
package com.acaiblog.spring.pojo;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
public class Dept {
} - service中定义注解
package com.acaiblog.spring.service.impl;
import com.acaiblog.spring.dao.DeptDao;
import com.acaiblog.spring.pojo.Dept;
import com.acaiblog.spring.service.DeptService;
import org.springframework.stereotype.Service;
public class DeptServiceImpl implements DeptService {
private DeptDao deptDao;
public void saveDept(Dept dept) {
deptDao.insertDept(dept);
}
} - controller中定义注解
package com.acaiblog.spring.controller;
import com.acaiblog.spring.pojo.Dept;
import com.acaiblog.spring.service.DeptService;
import org.springframework.stereotype.Controller;
public class DeptController {
private DeptService deptService;
public void saveDept(){
deptService.saveDept(new Dept());
}
} - spring配置文件设置扫描注解
<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">
<!-- 开启组件扫描,base-package设置扫描注解包-->
<context:component-scan base-package="com.acaiblog.spring"></context:component-scan>
</beans> - 测试代码
import com.acaiblog.spring.controller.DeptController;
import com.acaiblog.spring.dao.impI.DeptDaoImpl;
import com.acaiblog.spring.pojo.Dept;
import com.acaiblog.spring.service.impl.DeptServiceImpl;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring {
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
Dept dept = context.getBean("dept", Dept.class);
DeptDaoImpl deptDao = context.getBean("deptDao", DeptDaoImpl.class);
DeptServiceImpl deptService = context.getBean("deptServiceImpl", DeptServiceImpl.class);
DeptController deptController = context.getBean("deptController", DeptController.class);
System.out.println("dept:" + dept);
System.out.println("deptDao:" + deptDao);
System.out.println("deptService:" + deptService);
System.out.println("deptController:" + deptController);
}
}
使用注解装配对象中的属性[自动装配]
@Autowired
@Autowired注解作用:自动装配对象中的属性
@Autowired注解装配原理:反射机制
@Autowired注解装配方式:先byType匹配,如果匹配0个返回错误;如果匹配1个正常允许;如果匹配多个再按照byName进行唯一筛选匹配,筛选成功对象中的属性名称等同于beanId,筛选是吧对象中的属性名称比等于beanId。
@Autowired注解required属性为true,表示被标识的属性必须装配数值,如未装配会报错;属性为false,表示被标识的属性必须装配属性,如未装配不会报错。
实现步骤
添加注解
package com.acaiblog.spring.service.impl; |
测试代码
import com.acaiblog.spring.pojo.Dept; |
测试结果
添加部门成功 |
@Qualifier
@Qualifier和@Autowired配合使用,将设置的beanId名称装配到对象属性中。
Spring组件扫描
扫描包下所有子包
<context:component-scan base-package="com.acaiblog.spring"></context:component-scan> |
扫描指定的多个包
<context:component-scan base-package="com.acaiblog.aaa,com.acaiblog.bbb"></context:component-scan> |
包含扫描
<!-- 开启组件扫描,base-package设置扫描注解包,use-default-filters="false"关闭默认的组件扫描--> |
排除扫描
<context:component-scan base-package="com.acaiblog.spring"> |
Spring完全注解开发
@Configuration 将该注解的类代替xml配置文件
@ComponentSan 配置要扫描的包
实现步骤
创建配置类,在类上面添加注解
package com.acaiblog.spring.config; |
使用AnnotationConfigApplicationContext容器对象
import com.acaiblog.spring.config.SpringConfig; |
测试结果
dept: Dept{id=null, name='null', employeeList=null, employeeMap=null} |
Spring集成Junit4
导入jar包
<dependency> |
指定Spring配置文件路径和Spring环境下运行Junit4的运行器
import com.acaiblog.spring.pojo.Dept; |
Spring AOP
AOP概述
AOP:Aspect-Oriented Programming,面向切面编程;是对OOP(Object-Oriented Programming,面向对象编程)的一种扩展,是一种通过动态代理实现程序功能扩展和统一维护的技术。
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提供程序的可重用行,同时提高了开发的效率。
AOP专业术语
- 横切关注点:非核心代码,称之为横切关注点
- 切面:将横切关注点提取到类,称之为切面类
- 通知:将横切关注点提取到类之后,横切关注点更名为通知
- 目标:目标对象,指的是需要被代理的对象(实现类)
- 代理:代理对象可以理解为中转
- 连接点:通知方法需要指定通知位置,这个位置称之为连接点(通知之前)
- 切入点:通知方法需要指定通知位置,这个位置称之为连接点(通知之后)
AspectJ框架
AspectJ是java社区里最完整的AOP框架,在Spring2.0以上版本中可以使用基于AspectJ注解或基于xml配置的AOP。
切入点表达式
语法
通配符
通配符 | 描述 |
---|---|
* |
可以代表任意权限修饰符和返回值类型,可以代表任意包名、类名、方法名 |
.. |
代表任意参数类型及参数个数 |
重用切入点表达式
使用@PointCut注解,提取可重用的切入点表达式
|
使用方法名引入切入点表达式:
|
JoinPoint对象
作用
- 获取方法名称:
joinPoint.getSignature().getName();
- 获取参数名称:
joinPoint.getArgs();
AspectJ 通知
前置通知
语法:@Before
执行时机:指定方法执行之前执行,指定方法是切入点表达式设置位置
后置通知
语法:@After
执行时机:指定方法执行之后执行
返回通知
语法:@AfterReturning
执行时机:指定方法返回结果时执行
注意事项:@AfterReturning中的returning属性与方法入参参数名一致
异常通知
语法:@AfterThrowing
执行时机:指定方法出现异常时执行
环绕通知
语法:@Around
作用:整合前面4个通知
注意:参数中必须使用ProceedingJoinPoint
定义切面的优先级
语法:@Oder(value=index),index是int类型,默认值是int可存储的最大值;数值越小优先级越高
使用AspectJ框架
pom.xml添加jar包
<dependencies> |
编写applicationContext.xml配置文件
|
在MyLogging中配置切面类
package com.acaiblog.aop; |
JDBCTemplate
什么是JDBCTemplate
JDBCTemplate是一个Spring提供的小型持久化框架,简化jdbc的代码。
基本使用
pom.xml导入jar包
<dependencies> |
resource下创建db配置文件db.properties
db.driver=org.mariadb.jdbc.Driver |
resource下创建spring配置文件application.xml
|
编写测试类
import org.junit.Test; |
JDBCTemplate常用API
增加
方法 | 描述 |
---|---|
update(String sql) |
执行给定的 SQL 更新语句,返回受影响的行数。 |
update(String sql, Object... args) |
执行带参数的 SQL 更新语句,返回受影响的行数。 |
update(String sql, SqlParameterSource paramSource) |
执行带参数的 SQL 更新语句,返回受影响的行数。 |
batchUpdate(String sql, BatchPreparedStatementSetter pss) |
批量执行带参数的 SQL 更新语句,每个更新语句在事务中执行。 |
batchUpdate(String sql, Map<String, ?>[] batchValues) |
批量执行带参数的 SQL 更新语句,每个更新语句在事务中执行。 |
删除
方法 | 描述 |
---|---|
update(String sql) |
执行给定的 SQL 更新语句,返回受影响的行数。 |
update(String sql, Object... args) |
执行带参数的 SQL 更新语句,返回受影响的行数。 |
update(String sql, SqlParameterSource paramSource) |
执行带参数的 SQL 更新语句,返回受影响的行数。 |
batchUpdate(String sql, BatchPreparedStatementSetter pss) |
批量执行带参数的 SQL 更新语句,每个更新语句在事务中执行。 |
batchUpdate(String sql, Map<String, ?>[] batchValues) |
批量执行带参数的 SQL 更新语句,每个更新语句在事务中执行。 |
修改
方法 | 描述 |
---|---|
update(String sql) |
执行给定的 SQL 更新语句,返回受影响的行数。 |
update(String sql, Object... args) |
执行带参数的 SQL 更新语句,返回受影响的行数。 |
update(String sql, SqlParameterSource paramSource) |
执行带参数的 SQL 更新语句,返回受影响的行数。 |
batchUpdate(String sql, BatchPreparedStatementSetter pss) |
批量执行带参数的 SQL 更新语句,每个更新语句在事务中执行。 |
batchUpdate(String sql, Map<String, ?>[] batchValues) |
批量执行带参数的 SQL 更新语句,每个更新语句在事务中执行。 |
查询
方法 | 描述 |
---|---|
query(String sql, RowMapper<T> rowMapper) |
执行给定的 SQL 查询语句,将结果映射为对象列表。 |
queryForObject(String sql, Class<T> elementType) |
执行给定的 SQL 查询语句,返回单个结果对象。 |
queryForList(String sql) |
执行给定的 SQL 查询语句,返回结果列表。 |
queryForMap(String sql) |
执行给定的 SQL 查询语句,将结果映射为键值对。 |
queryForList(String sql, Class<T> elementType) |
执行给定的 SQL 查询语句,将结果映射为指定类型的对象列表。 |
queryForMap(String sql, Object... args) |
执行带参数的 SQL 查询语句,将结果映射为键值对。 |
queryForObject(String sql, Class<T> elementType, Object... args) |
执行带参数的 SQL 查询语句,返回单个结果对象。 |
queryForList(String sql, Object... args) |
执行带参数的 SQL 查询语句,返回结果列表。 |
query(String sql, RowMapper<T> rowMapper, Object... args) |
执行带参数的 SQL 查询语句,将结果映射为对象列表。 |
queryForMap(String sql, SqlParameterSource paramSource) |
执行带参数的 SQL 查询语句,将结果映射为键值对。 |
queryForObject(String sql, SqlParameterSource paramSource, Class<T> elementType) |
执行带参数的 SQL 查询语句,返回单个结果对象。 |
queryForList(String sql, SqlParameterSource paramSource) |
执行带参数的 SQL 查询语句,返回结果列表。 |
query(String sql, RowMapper<T> rowMapper, SqlParameterSource paramSource) |
执行带参数的 SQL 查询语句,将结果映射为对象列表。 |
设计数据库表结构
create table dept( |
增加数据
import org.junit.Test; |
修改数据
import org.junit.Test; |
删除数据
import org.junit.Test; |
批量增加
import org.junit.Test; |
查询
查询单个数值
import org.junit.Test; |
查询单个对象
import org.junit.Test; |
查询多个对象
import org.junit.Test; |
Spring声明式事务管理
编程式事务管理
- 获取数据库连接Connection对象
- 取消事务的自动提交
- 执行操作
- 正常完成操作时手动提交事务
- 执行失败时回滚事务
- 关闭相关资源
声明式事务管理【AOP管理事务】
- 先横向提取事务管理代码,再动态置入
使用声明式事务管理
创建数据库表
create table book( |
pom.xml中添加依赖包
<dependencies> |
resources下创建db.properties配置文件
db.driver=org.mariadb.jdbc.Driver |
resources下创建spring配置文件
|
创建图书接口
package com.acaiblog.spring.dao; |
创建图书接口扩展
package com.acaiblog.spring.dao; |
声明式事务管理属性
@Transacitional注解属性
- 事务传播行为Propagation:当事务方法被另一个事务方法调用时,必须指定事务应该如何传播;
传播行为 | 描述 |
---|---|
REQUIRED | 如果当前存在事务,则加入该事务;否则,新建一个事务。 |
SUPPORTS | 如果当前存在事务,则加入该事务;否则,以非事务方式执行。 |
MANDATORY | 要求当前存在事务,如果不存在则抛出异常。 |
REQUIRES_NEW | 无论当前是否存在事务,都会创建一个新的事务。 |
NOT_SUPPORTED | 以非事务方式执行方法,如果当前存在事务,则将其挂起。 |
NEVER | 以非事务方式执行方法,如果当前存在事务,则抛出异常。 |
NESTED | 如果当前存在事务,则在一个嵌套的事务中执行;如果没有事务,则按REQUIRED行为创建一个新事务。 |
- 事务隔离级别:一个事务与其他事务之间的隔离等级
隔离级别 | 描述 |
---|---|
DEFAULT (使用数据库默认) | 使用数据库的默认隔离级别(通常为数据库配置的默认级别)。 |
READ_UNCOMMITTED (读未提交) | 允许读取尚未被其他事务提交的数据,存在脏读和不可重复读的风险。 |
READ_COMMITTED (读已提交) | 只能读取已经被其他事务提交的数据,避免脏读,但仍可能存在不可重复读。 |
REPEATABLE_READ (可重复读) | 确保在事务执行期间,其他事务不能修改数据,避免脏读和不可重复读。 |
SERIALIZABLE (串行化) | 最高隔离级别,确保事务串行执行,避免脏读、不可重复读和幻读。 |
- 事务超时:设置超时时间,到达设置的时间之后会强制事务回滚;类型int,单位秒;默认值-1未设置强制回滚时间
- 事务只读:一般事务中只有查询操作时才会设置事务只读
- 事务回滚:rollbackFor,设置回滚的异常class;norollbackFor,不设置回滚异常的class。
基于xml配置声明式事务管理
|