一、Spring简介
Spring是一个为简化企业级开发而生的开源框架。
Spring是一个IOC(DI)和AOP容器框架。
IOC (Inversion of Control) : 反转控制
DI (Dependency Injection) : 依赖注入 DI是IOC的一种具体实现
AOP(Aspect-Oriented Programming) : 面向切面编程
使用Spring开发可以将Bean对象,Dao组件对象,Service组件对象等交给Spring容器来管理,这样使得很多复杂的代码在Spring中开发却变得非常的优雅和简洁,有效的降低代码的耦合度,极大的方便项目的后期维护、升级和扩展。
优良特性:①非侵入式:基于Spring开发的应用中的对象可以不依赖于Spring的API。
②控制反转:指的是将对象的创建权交给Spring去创建。使用Spring之前,对象的创建都是由我们自己在代码中new创建。而使用Spring之后。对象的创建都是由给了Spring框架。
③依赖注入:是指依赖的对象不需要手动调用setXXX方法去设置,而是通过配置赋值。
④面向切面编程:在不修改源代码的基础上进行功能扩展。
⑤容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期。
⑥组件化:Spring实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用XML和Java注解组合这些对象。
⑦一站式:Spring实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用XML和Java注解组合这些对象。
2、Spring框架分为五大模块:
(1)Core container:核心容器
Bean提供BeanFactory,它是一个工厂模式的复杂实现
Core提供了框架的基本组成部分,包括IOC和DI功能
Context建立在由核心和bean模块提供的基础上,它是访问定义和配置的任何对象的媒介。ApplicationContext接口是上下文模块的重点
SpEL在运行时提供了查询和操作一个对象的强大的Spring
(2)AOP&Aspects:提供了面向切面编程的实现
(3)DataAccess/Integration:提供了对数据访问、集成的功能
(4)Web:提供了面向Web应用程序的集成功能
(5)Test:提供了对JUnit或TestNG框架的测试功能
3、HelloSpring
(1) 创建Java工程,并导入jar包
<dependencies>
<!--导入spring-context-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.1</version>
</dependency>
<!--导入junit4.12-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
(2)新建Student【测试类】
(3)创建Spring核心配置文件【applicationContext.xml或beans.xml】
位置:resources目录下
将Student类装配到Spring容器中
(4)创建Spring容器对象【ClassPathXmlApplicationContext】
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
(5) 通过容器获取Student对象
Student zzq = context.getBean("zzq", Student.class);
System.out.println("zzq = " + zzq);
4、getBean三种方式
①getBean(String id):从spring容器中,通过id获取对象
不足:默认获取对象类型是Object,需要强转,比较繁琐
②getBean(Class clazz):从spring容器中,通过Class获取对象
不足:当容器中有多个相同Class对象时,会报如下错误:
expected single matching bean but found 2: ltq,zzq
③getBean(String id,Class clazz):从spring容器中,通过id和Class获取对象
建议使用
5、Spring依赖注入三种方式
①set注入<property>
<!-- 使用bean标签,装配Student
id:设置装配对象唯一标识
class:设置装配对象的全类名【类的全限定名】
-->
<bean id="ltq" class="com.atguigu.pojo.Student">
<!-- 为对象中的属性,注入数值-->
<property name="id" value="1001"></property>
<property name="stuName" value="ltq"></property>
</bean>
②构造器注入<constructor-arg>
<bean id="zzq" class="com.atguigu.pojo.Student">
<constructor-arg name="id" value="102"></constructor-arg>
<constructor-arg name="stuName" value="zzq"></constructor-arg>
</bean>
③p名称空间注入 xmlns:p="http://www.springframework.org/schema/p" <P:>
本质还是set注入
<!-- 引入p名称空间 -- >
xmlns:p="http://www.springframework.org/schema/p"
<bean id="cjy" class="com.atguigu.pojo.Student" p:id="1003" p:stuName="cjy"></bean>
6、Spring中的IOC【DI】
-
Spring中有IOC思想, IOC思想必须基于 IOC容器来完成, 而IOC容器在最底层实质上就是一个对象工厂.
-
Spring实现IOC两种方式
-
BeanFactory【Spring底层实现】
-
ApplicationContext【推荐使用】
-
-
-
ApplicationContext结构图
-
ApplicationContext
-
ConfigurableApplicationContext
-
ClassPathXmlApplicationContext【基于类路径下,检索xml文件】
-
FileSystemXmlApplicationContext【基于系统路径(真实路径)下,检索xml文件】
-
-
-
7、Spring中注入数值
(1)字面量值 可以存储基本数据类型及包装类,String类型的数据
<!-- 装配字面量值-->
<bean id="sls" class="com.atguigu.pojo.Emp">
<property name="id" value="101"></property>
<property name="empName" value="sls"></property>
<property name="age" value="19"></property>
<property name="salary" value="100"></property>
<property name="gender" value="男"></property>
<!-- <property name="dept" value="sdfd"></property>-->
</bean>
(2)特殊字符 使用CDATA区 < ! [CDATA[ ] ] >
(3)外部已声明bean ref
<!-- 装配部门-->
<bean id="jxb" class="com.atguigu.pojo.Dept">
<property name="deptId" value="1001"></property>
<property name="deptName" value="教学部门"></property>
<property name="deptLoc" value="3008"></property>
</bean>
<bean id="cxls" class="com.atguigu.pojo.Emp">
<property name="id" value="103"></property>
<property name="empName" value="cxls"></property>
<property name="age" value="20"></property>
<property name="salary" value="100"></property>
<property name="gender" value="男"></property>
<property name="dept" ref="jxb"></property>
</bean>
(4)级联属性赋值
<!-- 装配部门-->
<bean id="jxb" class="com.atguigu.pojo.Dept">
<property name="deptId" value="1001"></property>
<property name="deptName" value="教学部门"></property>
<property name="deptLoc" value="3008"></property>
</bean>
<bean id="cxls" class="com.atguigu.pojo.Emp">
<property name="id" value="103"></property>
<property name="empName" value="cxls"></property>
<property name="age" value="20"></property>
<property name="salary" value="100"></property>
<property name="gender" value="男"></property>
<property name="dept" ref="jxb"></property>
<!-- 级联属性赋值-->
<property name="dept.deptName" value="财务部门"></property>
</bean>
如更改级联属性值时,管理bean中属性也同时被更改【级联对象与原对象,是同一个对象】
(5)内部bean
<!-- 内部bean-->
<bean id="gls" class="com.atguigu.pojo.Emp">
<property name="id" value="104"></property>
<property name="empName" value="gls"></property>
<property name="age" value="18"></property>
<property name="salary" value="100"></property>
<property name="gender" value="男"></property>
<property name="dept">
<bean id="msbm" class="com.atguigu.pojo.Dept">
<property name="deptId" value="1001"></property>
<property name="deptName" value="秘书部门"></property>
<property name="deptLoc" value="3001"></property>
</bean>
</property>
</bean>
8、Spring装配第三方bean
①导入jar包
<!--导入druid的jar包-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--导入mysql的jar包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.37</version>
</dependency>
②编写db.properties文件
#key=value
jdbc.username=root
jdbc.password=root
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.initialSize=5
jdbc.maxActive=10
③编写applicationContext.xml文件
-
加载属性文件【db.properties】
-
装配DruidDataSource数据源
<?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"> <!-- 加载外部属性文件 classpath: 基于【当前】类路径加载文件 classpath*: 基于【所有】类路径加载文件 --> <context:property-placeholder location="classpath:db.properties"/> <!-- 装配DruidDataSource数据源--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}"></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> </beans>
9、Bean的作用域
设置bean作用域语法,在bean标签中添加属性:scrop
①singleton 单例 在Spring的IOC容器中仅存在一个Bean实例 所有bean的默认作用域
spring在创建容器对象时,创建bean对象【全局只创建一次容器对象,所以全局只有一个bean对象】
②prototype 多例 每次调用getBean方法都会返回一个新的实例 bean标签的scope属性设置
③request 请求域 当前请求有效,离开当前请求失效;
当前请求:地址栏不变即为当前请求,地址栏改变不在当前请求
每次HTTP请求都会创建一个心的Bean实例,该作用域仅适用于WebApplicationContext环境
④session 会话域 同一个Session会话共享一个Bean实例,该作用域仅适用于WebApplicationContext环境
10、Bean的生命周期
1、标准生命周期
② 为bean的属性设置值和对其他bean的引用
③ 调用bean的初始化方法
④ bean可以使用了
⑤ 当容器关闭时,调用bean的销毁方法
2、添加后置处理器的生命周期
①通过构造器或工厂方法创建bean实例
②为bean的属性设置值和对其他bean的引用
将bean实例传递给bean后置处理器的postProcessBeforeInitialization()方法
③调用bean的初始化方法
将bean实例传递给bean后置处理器的postProcessAfterInitialization()方法
④bean可以使用了
⑤当容器关闭时调用bean的销毁方法
二、Spring中自动装配
Spring提供的两种装配方式:
①手动装配:在bean中添加set注入或者构造注入等方式
②自动装配:无需set注入或构造注入,就可以自动装配属性值方式
语法:
在bean标签中,添加autowire属性,常用属性值有:
①byName:通过类中属性名称与ioc容器中id匹配
如果匹配成功,则自动装配成功;如果匹配失败,则会将null值装配
②byType:通过类中属性类型与ioc容器中的class匹配
匹配失败:
匹配0个:不会报错,会将null值装配
匹配多个:会报错 expected single matching bean but found 2: address,address2
匹配成功:
匹配1个bean时,则匹配成功
注意:自动装配底层使用set注入
问:实战中建议使用byName或byType呢?
答:都不建议使用,建议使用注解方式
2、spring中的注解
<1>使用spring注解,简化装配bean配置
(1)@Component 标识一个受Spring IOC容器管理的普通组件
(2)@Repository 标识一个受Spring IOC容器管理的持久化组件
(3)@Service 标识一个受Spring IOC容器管理的业务逻辑层组件
(4)@Controller 标识一个受SpringIOC容器管理的表述层控制组件
注意:使用注解默认会将类名首字母小写作为bean的id
可以使用value属性为注解,设置bean值【如只书写一个属性值时,value可省略】
<2>使用spring注解,简化装配bean中的属性配置【注入数值】
@AutoWired 作用:实现自动装配
装配规则:先按照byType方式进行匹配
如匹配成功【容器中有且仅有一个匹配类型】,则自动装配成功
如匹配失败 : ,再按照byName进行匹配,如匹配成功则正常使用,如匹配失败,则会按照byType方式提示错误信息
匹配0个:required=true【默认值】,会报错
expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
required=false 不会报错,会将null值装配
匹配多个:会报错:expected single matching bean but found 2:address,address2
<3>@Autowired中的required属性作用:设置装配属性**是否必须**自动装配
required=true:必须为指定属性自动装配
required=false:不必须为指定属性自动装配
<4> 默认@Autowired注解书写在字段中 ,底层反射方式注入数值
@AutoWired注解书写在setXXX() 方法中,底层使用set方式 注入
@AutoWired注解书写在构造方法中,底层使用构造器方式注入
<5> @Qualifier注解:
将ioc容器中bean的id 自动装配到指定类的属性中
一般与@Autowired注解配合使用
<6>@Value注解,自动装配字面量数值
3、Spring组件扫描
原因:需要使用注解,就必须开启组件扫描
<1>方式一:默认开启组件扫描【扫描当前包及其子包】
<context:component-scan base-package="com.atguigu"></context:component-scan>
<2>方式二:排除扫描
<context:component-scan base-package="com.atguigu">
<!-- 设置排除组件指定注解全限定名【全类名】-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
<!-- 设置排除组件指定类全限定名【全类名】-->
<!-- <context:exclude-filter type="assignable" expression="com.atguigu.service.impl.StudentServiceImpl"/>-->
</context:component-scan>
<3>方式三:包含扫描
使用包含扫描需要将默认组件扫描关闭【use-default-fifters="false"】
<context:component-scan base-package="com.atguigu" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
<!-- <context:include-filter type="assignable" expression="com.atguigu.dao.impl.StudentDaoImpl"/>-->
<!-- <context:include-filter type="assignable" expression="com.atguigu.dao.impl.StudentMapperImpl"/>-->
</context:component-scan>
4、完全注解开发
步骤:
①创建配置类
②为配置添加相应的注解
@Configuration:设置当前类为配置类,用来代替xml配置文件
@ComponentScan:为配置类,开启组件扫描
③创建AnnotationConfigApplicationContext容器对象,并使用
package com.atguigu.springutil;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* Creates with IntelliJ IDEA.
* Author: 李龙
* Date: 2021/10/12 16:11
* Description: TODO
* Since version-1.0
*/
@ComponentScan(basePackages = "com.atguigu")
@Configuration
public class SpringConfig {
}
import com.atguigu.bean.Student;
import com.atguigu.service.StudentService;
import com.atguigu.service.impl.StudentServiceImpl;
import com.atguigu.springutil.SpringConfig;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* Creates with IntelliJ IDEA.
* Author: 李龙
* Date: 2021/10/12 16:12
* Description: TODO
* Since version-1.0
*/
public class Test05NoXml {
@Test
public void test(){
//创建容器对象【配置类】
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
//从容器中获取bean对象
StudentServiceImpl studentService = context.getBean("studentService", StudentServiceImpl.class);
//StudentServiceImpl studentService = context.getBean("studentService", StudentService.class);//也可以,底层反射原理
//调用bean对象中相应方法
studentService.addStudent(new Student());
}
}
5、Spring整合Junit4
步骤:
①导入spring-test:5.3.1.jar包
<!--spring集成junit4-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.1</version>
</dependency>
②添加注解
@ContextConfiguration(locations="classpath: ")
@RunWith(SpringJUnit4ClassRunner.class)
③装配测试类,并使用
import com.atguigu.bean.Student;
import com.atguigu.service.StudentService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* Creates with IntelliJ IDEA.
* Author: 李龙
* Date: 2021/10/12 16:20
* Description: TODO
* Since version-1.0
*/
@ContextConfiguration(locations = "classpath:applicationContext_annotation.xml")
// @ContextConfiguration(classes = SpringConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class Test06SpringJunit {
@Autowired
private StudentService studentService;
/**
* Spring整合Junit4
*/
@Test
public void testSpringUserService(){
System.out.println("studentService = " + studentService);
studentService.addStudent(new Student());
}
}