一、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 的编程。
- 控制反转(IoC ):当某个 Java 对象(调用者)需要调用另一个 Java 对象(被调用者,即被依赖对象)时, 在传统模式下,调用者通常会采用 "new 被调用者"的代码方式来创建对象,这种方式会导致调用者与被调用者之间的捐合性增加,不利于后期项目的升级和维。在使用 Spring 框架之后,对象的实例不再由调用者来创建,而是由 Spring 容器来创建,Spring 容器会负责控制程序之间的关系,而不是由调用者的程序代码直接控制 这样,控制权由应用代码转移到了 Spring 容器,控制权发生了反转,这就是 Spring 的控制反转。
- **依赖注入( Dependency Injection ,简称 DI) **:与控制反转 (loC) 的含义相同,只不过这两 个称呼是从两个角度描述的同一个概念 对Spring 容器的角度来看, Spring 容器负责将被依赖对象赋值给调用者的成员变量,这相当于为调用者注入了它依赖的实例,这就是 Spring 的依赖注入。依赖注入的作用就是在使用 Spring 框架创建对象时,动态地将其所依赖的对象注入Bean组件中。
- AOP:
BeanFactory 就是一千管理 Bean 的工厂,它主要负责初始化各种 Bean ,并调用它们的生命周期方法,ApplicationContext是BeanFactory 的子接口,也被称为应用上下文,包含了BeanFactory 的所有功能。
二、体系架构
image.png
1、核心容器
Spring 的核心容器是其他模块建立的基础,由 Beans 模块、Core 核心模块、Context 上下文模块和 SpEL 表达式语言模块组成
- Core 核心模块:提供了 Spring 框架的基本组成部分,包括 loC 和 DI 功能 ,是其他组件的基本核心。
- Beans 模块:它包含访问配置文件、创建和管理 Bean 以及进行IOC/DI操作相关的所有类
- Context 上下文模块:立在 Core Beans 模块的基础之上,它是访问定义和配置的任 何对象的媒介 其中 ApplicationConte 接口是上下文模块的焦点
- SpEL 模块:是 Spring 后新增的模块,它提供了 Spring Expression Language 支持,是运行时查询和操作对象图的强大的表达式语言
2、数据访问/集成
- 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. 依赖
<!--单独引入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>
<!--引入spring-context包会自动引入Spring的四个核心包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.13</version>
</dependency>
<!--引入此包会自动引入Spring的四个核心包+spring-aop+spring-web-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</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
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容器初始化
Java 项目中,会采用通过 ClassPathXmlApplicationContext 类来实例化ApplicationContext 容器的方式。
// 1.初始化 spring 容器,加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2.通过容器获取Hello实例
Hello name = (Hello) context.getBean("hello");
在 Web 项目中, ApplicationContext 容器的实例化工作会交由 Web 服务器来完成 Web 服务器实例化ApplicationContext 容器时,通常会使用基于ContextLoader Li stener 实现的方式,此种方式只需要在web.xml` 中添加如下代码
<!… 指定 Spring 配置文件的位置,多个配置文件时,以逗号分隔一〉
<context-param>
<param-name>contextConfigLocation<!param-name>
<!一 Spring 将加载 spring 目录下的 applicationContext .xml 文件一
<param-value>
classpath:spring/applicationContext.xml
<!param-value>
<!context-param>
<!一指定以 ContextLoaderListener 方式启动 Spring 容器
<listener>
<listener-class>
rg.springframework.web.context.ContextLoaderListener
<!listener-class>
</listener>
获得bean
<?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
2、Bean的实例化
在 Spring 中,要想使用容器中的 Bean ,需要实例化 Bean,实例化 Bean 有三种方式,分别为:构造器实例化、静态工厂方式实例化、实例工厂方式实例化(其中最常用的是构造器实例化)。
(1)构造器实例化
构造器实例化是指 Spring 容器通过 Bean 对应类中默认的无参构造方法来实例化 Bean。
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,比较麻烦。
- 使用注解方式二
- 项目必须要导入spring-aop依赖
- 配置文件中增加如下内容
<!--使用context命名空间,通知Spring扫描指定包下所有Bean,进行注解解析-->
<context:component-scan base-packaqe="com.example.spring"/>
使用注解装配,在需要配置为bean的类上增加上述Spring注解即可
- 以下两个是完全等价的
@Service
public class MyServiceImpl {
...
}
<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 ,即面向切面编程(也称面向方面编程)
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
(1)基于XML的声明式AspectJ
待补充。。。
(2)基于注解的声明式AspectJ
待补充。。。
六、Spring JDBC
Spring JDBC 模块负责数据库资源管理,Jdbc T emplate 类是 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">
<!-- 1. 读取db.properties文件中的数据 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 2. 配置数据源-->
<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>
<!-- 3. 配置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>-->
</beans>
定义 jdbcTemplate 时,需要将 dataSource 注入到 jdbcTemplate 中,而其他需要使用jdbcTemplate的Bean ,也需要将 jdbcTemplate 注入到该 Bean 中(通常注入到 Dao 类中,在Dao 类中进行与数据库的相关操作)。
3、使用Spring JdbcTemplate
@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、dbcTemplate的常用方法
- 创建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);
}








网友评论