1 环境要求
(1) IDEA开发工具: 2022.3.3
(2) JDK: Java17+
(3) Maven: 3.6+
(4) Spring: 6+
2 准备工作
2.1 引入Spring相关依赖
<dependencies>
<!--spring的核心IOC容器,spring的任何部分运行都基于IOC容器,即spring的基础依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-version}</version>
</dependency>
<!--junit5测试-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.0</version>
</dependency>
<!--日志门面接口:slf4j-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.9</version>
</dependency>
<!-- 日志框架(具体实现):logback -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.11</version>
</dependency>
<!--log4j-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.20.0</version>
</dependency>
<!--Spring AOP依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring-version}</version>
</dependency>
<!--Spring aspect依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring-version}</version>
</dependency>
<!--动态代理AOP:解析”切入点表达式”-->
<!-- <dependency>-->
<!-- <groupId>org.aspectj</groupId>-->
<!-- <artifactId>aspectjweaver</artifactId>-->
<!-- <version>1.8.14</version>-->
<!-- </dependency>-->
<!--MySQL数据库驱动-->
<!-- <dependency>-->
<!-- <groupId>mysql</groupId>-->
<!-- <artifactId>mysql-connector-java</artifactId>-->
<!-- <version>8.0.31</version>-->
<!-- </dependency>-->
<!--(新)MySQL数据库驱动,配置文件mysql.driver=com.mysql.cj.jdbc.Driver-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.1.0</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.13</version>
</dependency>
<!--Spring集成Mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>3.0.2</version>
</dependency>
<!--阿里druid连接池(数据源)-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.19</version>
</dependency>
<!--c3p0连接池(数据源)-->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
</dependency>
<!--Spring的JdbcTemplate连接池(数据源)-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring-version}</version>
</dependency>
<!--Spring为我们提供的”事务管理器”(要做”声明式事务”必须引入的包)-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring-version}</version>
</dependency>
<!--fastJson的依赖-->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.41</version>
</dependency>
<!--jackson的依赖:包含了SpringMVC中@RequestBody解析JSON数据功能-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
<!--servlet的依赖-->
<!-- <dependency>-->
<!-- <groupId>javax.servlet</groupId>-->
<!-- <artifactId>javax.servlet-api</artifactId>-->
<!-- <version>4.0.1</version>-->
<!-- <scope>provided</scope><!–compile默认的,全范围有效; test测试有效; provided其它地方没有就生效,其它地方有了就用其它地方的; runtime运行时有效,编译时无效; –>-->
<!-- </dependency>-->
<!--tomcat10依赖的servlet-->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<scope>provided</scope>
</dependency>
<!--解决"无法访问jakarta.servlet.ServletException"-->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-api</artifactId>
<version>10.1.13</version>
</dependency>
<!--SpringMVC依赖包-->
<dependency>
<groupId>org.springframework</groupId><!--依赖spring-web,但maven会自动导入-->
<artifactId>spring-webmvc</artifactId>
<version>${spring-version}</version>
</dependency>
<!--内含StringUtils工具类--> <!--StringUtils.isEmpty()判断null和””--> <!--StringUtils.isBlank()在isEmpty的基础上增加判断空白符(空格,制表符\t,换行符\n,换页符\f,回车符\r)-->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<!--腾讯云短信服务SMS(Short Message Service)-->
<dependency>
<groupId>com.github.qcloudsms</groupId>
<artifactId>qcloudsms</artifactId>
<version>1.0.6</version>
</dependency>
<!--ApachePOI,HSSF对象,操作.xls-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.3</version>
</dependency>
<!--ApachePOI,XSSF对象,操作.xlsx-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.3</version>
</dependency>
<!--Redis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency> <!--连接池-->
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.10.0</version>
</dependency>
<!--文件上传的依赖包,针对CommonsMultipartResolver,而使用StandardServletMultipartResolver则不需要下面的依赖-->
<!-- <dependency> <!–内部自带一个common-io包–>-->
<!-- <groupId>commons-fileupload</groupId>-->
<!-- <artifactId>commons-fileupload</artifactId>-->
<!-- <version>1.5</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>commons-io</groupId>-->
<!-- <artifactId>commons-io</artifactId>-->
<!-- <version>2.13.0</version>-->
<!-- </dependency>-->
<!-- <!–远程文件上传–>-->
<!-- <dependency>-->
<!-- <groupId>com.sun.jersey</groupId>-->
<!-- <artifactId>jersey-core</artifactId>-->
<!-- <version>1.19.4</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>com.sun.jersey</groupId>-->
<!-- <artifactId>jersey-client</artifactId>-->
<!-- <version>1.19.4</version>-->
<!-- </dependency>-->
</dependencies>
2.2 Spring配置文件(.xml)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--引入properties文件:被其他bean标签使用${key},也可以用于注解方式的依赖注入@Value("${key}")-->
<context:property-placeholder location="classpath:config.properties" file-encoding="utf-8"/>
<!--包扫描:使@Component等注解生效-->
<context:component-scan base-package="xyz.aboluo" use-default-filters="false"> <!--use-default-filters:是否使用默认的过滤规则(通常不写)-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <!--除了@Controller注解不扫描,其它注解都扫描-->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <!--只扫描@Controller注解(要结合use-default-filters=”false”使用)-->
</context:component-scan>
<!--开启对"注解AOP"的支持-->
<aop:aspectj-autoproxy/>
<!--bean标签(对象创建):
id:唯一标签
class:创建对象对应类所在的全路径
scope:singleton(默认)单例:创建的实例对象始终是同一个,作用范围是整个应用
单例对象生命周期:主配置文件一加载,容器创建后对象就被创建了(容器在对象就在,容器销毁对象就销毁)
prototype多例:每次获取的实例对象都是新的
多例对象生命周期:使用时才会创建 长时间不使用,被java的”垃圾回收器GC”回收了(容器销毁了,多例对象不一定销毁)
init-method:监听对象创建,实例对象被创建后调用init-method所指定的方法
destroy-method:监听对象销毁,实例对象被销毁前调用destroy-method所指定的方法-->
<bean id="user" class="xyz.aboluo.User">
<!--property表示"set注入"
name:set方法去掉set,首字母小写
ref:引用其它bean类型(该bean必须已经被IOC管理)-->
<property name="name" value="${aaa}"></property>
<property name="age" ref="${bbb}"></property>
<!--constructor-arg表示"注解注入"
name:构造函数形参名-->
<constructor-arg name="hobby" value="${ccc}"/>
</bean>
<!--spring-jdbc连接池(数据源)-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${mysql.driver}"/>
<property name="url" value="${mysql.url}"/>
<property name="username" value="${mysql.username}"/>
<property name="password" value="${mysql.password}"/>
</bean>
<!--阿里druid连接池(数据源)-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${mysql.driver}"/>
<property name="url" value="${mysql.url}"/>
<property name="username" value="${mysql.username}"/>
<property name="password" value="${mysql.password}"/>
</bean>
<!--c3p0连接池(数据源)-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${mysql.driver}"/>
<property name="jdbcUrl" value="${mysql.url}"/>
<property name="user" value="${mysql.username}"/>
<property name="password" value="${mysql.password}"/>
</bean>
<!--事务管理器-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/> <!--注入数据源-->
</bean>
<!--开启spring对"声明式事务"的注解支持-->
<tx:annotation-driven transaction-manager="txManager"/>
<!--引入其它xml配置文件-->
<import resources="spring.xml"/>
</beans>
3 IOC
底层核心原理是JAVA反射
IOC(Inversion Of Control)控制反转(创建对象不再时通过new,而是交给IOC容器)
Spring通过IOC容器来管理所有JAVA对象的实例化和初始化、控制对象与对象之间的依赖关系,这些由IOC容器管理的JAVA对象称为Spring Bean(它与由关键字new创建的JAVA对象没有任何区别)
3.1 IOC实现
3.1.1 ApplicationContext的主要实现类
BeanFactory是IOC容器的基本实现,是Spring内部使用的接口,不向开发人员提供
ApplicationContext是BeanFactory的子接口,提供了更多高级特性,面向开发者(几乎所有场合都可以使用ApplicationContext,而不是更底层的BeanFactory)
实现类 | 简介 |
ClassPathXmlApplicationContext | 通过读取类路径下的xml配置文件创建IOC容器对象 |
AnnotationConfigApplicationContext | 通过读取配置类创建IOC容器对象 |
3.1.3.1 ClassPathXmlApplicationContext
@Test
public void userTest() {
// 加载spring配置文件,创建"容器对象"
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
// 从容器中获取对应的对象
User user = context.getBean("user", User.class);
// 使用对象
user.aaa();
}
3.1.3.2 AnnotationConfigApplicationContext
@Test
public void userTest() {
// 加载spring配置类,创建"容器对象"
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
// 从容器中获取对应的对象
User user = context.getBean("user", User.class);
// 使用对象
user.aaa();
}
3.2 依赖注入DI(Dependency Injection)
在Spring创建对象过程中,注入对象依赖的属性:
(1) set注入: 有空参构造方法,和对应的set方法
(2) 构造注入: 有对应的构造方法
(3) 注解注入: 有空参构造方法
3.3 注解开发
3.3.1 开启组件扫描
3.3.2 创建对象注解
被注解的类必须有空参构造方法
这些注解不能写在接口上,要写在类上
注解 | 说明 |
@Component | 默认使用类名(首字母小写) |
@Controller | 通常用于控制层,功能与@Component相同 |
@Service | 通常用于业务层,功能与@Component相同 |
@Repository | 通常用于数据访问层,功能与@Component相同 |
3.3.3 依赖注入的注解
注解 | 说明 |
@Autowired | 根据类型去IOC容器匹配类/类的子类/接口实现类 可以用在类或方法上 |
@Qualifier("名称") | 要配合@Autowired使用 根据类型和名称去IOC容器进行匹配 |
@Value("值")或("${key}") | 基本数据类型和String类型 不能用作静态变量(static),不能用作常量(final) |
3.3.4 静态依赖注入
@Autowired不能作用在静态成员上,但可以在类中先声明静态成员变量,然后用@Autowired作用在非静态set方法上来进行属性注入,间接达到"静态依赖注入"的效果
@Component
public class Common {
/**
* 静态声明
*/
private static StringRedisTemplate stringRedisTemplate;
@Autowired
public void setStringRedisTemplate(StringRedisTemplate stringRedisTemplate) {
Common.stringRedisTemplate = stringRedisTemplate;
}
}
3.4 全注解开发
用配置类来替代xml配置文件
注解 | 说明 |
@Import | 用在Spring配置类上 可以引入配置类 也可以引入Controller,Service,POJO等类,被@Import引入的类可以不写@Component,@Service等注解,依然会被注册进SpringIOC容器 |
@Scope("singleton/prototype") | 用于指定bean对象的作用范围(默认singleton) 可以不配合单独使用,该bean被@Import引入Spring配置类即可生效 可以配合@Component等注解,也可以配合@Bean注解 |
@Bean | 将方法的返回值作为Bean交给SpringIOC容器管理 如果方法需要参数,会从IOC容器获取(默认按类型注入/多个匹配按形参名注入) |
@Configuration //配置类注解
@Import({DataSourceConfig.class,TransactionConfig.class}) //将类注册进SpringIOC容器 ; 引入其他配置类
@ComponentScan(value = "xyz.aboluo", excludeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION, //按注解类型过滤(不扫描)
classes = {Controller.class, Service.class}
), includeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION, //按注解类型过滤(只扫描)
classes = {Controller.class, Service.class}
)) //开启组件扫描(配置类也要在其中)
@PropertySource(value = "config.properties", encoding = "utf-8") //引入properties文件
@EnableAspectJAutoProxy //开启Spring对”注解AOP”的支持
@EnableTransactionManagement //开启Spring对”注解事务”的支持(需要有对应的"事务管理器"交给SpringIOC容器)
@MapperScan({"xyz.aboluo.dao","xyz.aboluo.dao2"}) //dao接口包扫描
@EnableWebMvc //开启"json数据转换为对象"的功能,方法形参前加@RequestBody(一个方法只能使用1次)
public class SpringConfig {
//事务管理器
@Bean
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource) {
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
//Spring整合Mybatis
@Bean
@Scope("prototype")
public SqlSessionFactoryBean getSqlSessionFactoryBean(DataSource dataSource, ApplicationContext applicationContext) {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
//注入数据源
sqlSessionFactoryBean.setDataSource(dataSource);
//给某一包下的所有JavaBean起别名(类名就是别名,不区分大小写)
sqlSessionFactoryBean.setTypeAliasesPackage("xyz.aboluo.pojo");
//读取mybatis的主配置文件(非必读)
// sqlSessionFactoryBean.setConfigLocation(applicationContext.getResource("classpath:mybatisMain.xml"));
//读取mybatis的映射配置文件(非必读,只要保证xml和dao接口有相同的包路径并且同名即可,或者使用@Select等注解开发)
// List<Resource> Resources = new ArrayList<>();
// Resources.add(applicationContext.getResource("classpath:xyz/aboluo/dao/UserDao.xml"));
// Resources.add(applicationContext.getResource("classpath:xyz/aboluo/dao/SudokuDao.xml"));
// sqlSessionFactoryBean.setMapperLocations(Resources.toArray(new Resource[0]));
return sqlSessionFactoryBean;
}
//配置dao层接口包扫描(可以用@MapperScan替代)
// @Bean
// public MapperScannerConfigurer getMapperScannerConfigurer() {
// MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
// mapperScannerConfigurer.setBasePackage("xyz.aboluo.dao");
// return mapperScannerConfigurer;
// }
}
public class DataSourceConfig {
@Value("${mysql.driver}")
private String mysqlDriver;
@Value("${mysql.url}")
private String mysqlUrl;
@Value("${mysql.username}")
private String mysqlUsername;
@Value("${mysql.password}")
private String mysqlPassword;
//数据源
@Bean(name = "dataSource")
public DriverManagerDataSource getDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(mysqlDriver);
dataSource.setUrl(mysqlUrl);
dataSource.setUsername(mysqlUsername);
dataSource.setPassword(mysqlPassword);
return dataSource;
}
}