Spring入门篇
Spring Frameword
- Spring Framework是Spring生态圈中最基础的项目,是其他项目的根基
1.1 Spring Frameword系统架构图
1.2 Spring Frameword学习路线
1.3 核心概念
- 代码现状
- 耦合度偏高
- 解决方案
- 使用对象时,在程序中不要主动new产生对象,转换为由外部提供对象
- IoC(Inversion of Control)控制反转
- 对象的创建控制权由程序转到外部,这种思想为控制反转
1.3.1 IoC ( Inversion of Control ) 控制反转
- 使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转
1.3.2 Spring技术对IoC思想进行了实现
- Spring提供了一个容器,称为IoC容器用来充当IoC思想中的“外部”
- IoC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IOC容器中统称为Bean
1.3.3 DI ( Dependency Injection ) 依赖注入
- 在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入
1.3.4 目标:充分解耦
- 使用IoC容器管理bean (IoC)
- 在IoC容器内将有依赖关系的bean进行关系绑定 (DI)
1.3.5 最终效果
- 使用对象时不仅可以直接从IoC容器中获取,并且获取到的bean已经绑定了所有的依赖关系
1.4 IoC入门
- 导入Spring坐标
<dependency>
<groupId>org.springframeword</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
- 定义Spring管理的类(接口)
public interface BookService{
public void save();
}
public class BookServiceImpl implements BookService {
private BookDao bookDao = new BookDaoImpl();
public void save(){
boolDao.save();
}
}
- 创建Spring配置文件,配置对应类作为Spring管理的bean
<?xml version="1.” encoding="UTF-8"?>
<beans xmIns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bookService"class="com.itheima.service.impl.BookServiceImpl"></bean>
</beans>
注意事项:bean 定义时id属性在同一个上下文中不能重复
- 初始化IoC容器 ( Spring核心容器/Spring容器 ),通过容器获取bean
public class App {
public static void main(String[] args) {
//加载配置文件得到上下文对象,也就是容器对象
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取资源
BookService bookService = (BookService)tx.getBean("bookService");
bookService.save();
}
1.4.1 bean作用范围说明
- bean默认为单例
- 适合交给容器进行管理的bean
- 表现层对象
- 业务层对象
- 数据层对象
- 工具对象
- 不适合交给容器进行管理的bean
- 封装实体的域对像
1.4.2 bean实例化
1.4.2.1 使用构造方法实例化bean(常用)
<bean id="bookDao”class="com.itheima.dao.impl.BookDaoImpl"/>
1.4.2.2 使用静态工厂实例化bean(了解)
<bean id="orderDaoclass="com. itheima,factory.0rderDaoFactory" factory-method="getOrderDao"/>
1.4.2.3 使用实例工厂实例化bean(了解)
<bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/>
<bean id="userDao"factory-method="getUserDao" factory-bean="userFactory"/>
1.4.2.4 使用FactoryBean实例化bean(需要掌握)
<bean id="userDao”class="com.itheima.factory.UserDaoFactoryBean"/>
public class UserDaoFactoryBean implements FactoryBean<UserDao>{
//代替原始实例工厂中创建对象的方法
public UserDao getObject() throws Exception{
return new UserDaoImpl();
}
public class<?> getobjectType() {
return UserDao.class;
}
public boolean isSingleton() {
//若为true就是单例,false就是非单例
return true;
}
}
1.4.3 bean的生命周期
- 生命周期:从创建到消亡的完整过程
- bean生命周期:bean从创建到销毁的整体过程
- bean生命周期控制:在bean创建后到销毁前做一些事情
bean管理的BookDao类:
public class BookDaoImpl implements BookDao {
public void save() {
System.out.printIn("book dao save...");
}
//表示bean初始化对应的操作
public void init(){
System.out.printIn("init...");
}
//表示bean 销毁前对应的操作
public void destory(){
System.out.printIn("destory...");
}
ApplicationContext xml文件配置信息:
<!---配置bean的生命周期
初始化时调用方法: init-method
销毁时调用方法:destroy-method
--->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
Main:
public class AppForLifeCycle{
public static void main( String[] args ) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml")
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
ctx.close();
}
以上是bean的暴力关闭方法!
还有一种设置关闭钩子的方法:
Main:
public class AppForLifeCycle{
public static void main( String[] args ) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml")
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
ctx.registershutdownHook();//这就是设置关闭钩子
/*设置关闭钩子方法相比close更加安全方便,若close在关闭对象的调用方法的前面,那对象都被暴力关闭了,后面调用其方法也会报错!
ctx.close();
}
1.5 依赖注入
思考:向一个类中传递数据的方式有几种 ?
- 普通方法 (set方法)
- 构造方法
思考:依赖注入描述了在容器中建立bean与bean之间依赖关系的过程,如果bean运行需要的是数字或字符串呢?
- 引用类型
- 简单类型(基本数据类型与string )
1.5.1 setter注入
1.5.1.1 引用类型注入
在bean中定义引用类型属性并提供可访问的set方法
public class BookServiceImpl implements BookService{
private BookDao bookDao;
public void setBookDao(BookDao bookDao){
this.bookDao = bookDao;
}
}
配置中使用property标签ref属性注入引用类型对象
<bean id="bookService" class="com,itheima,serwice.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
</bean>
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
1.5.1.2 简单类型注入
在bean中定义引用类型属性并提供可访问的set方法
public class BookDaoImpl implements BookDao {
private int connectionNumber;
public void setConnectionNumber(int connectionNumber) {
this.connectionNumber = connectionNumber;
}
}
配置中使用property标签value属性注入简单类型数据
<bean id="bookDao" class="com.itheima,dao.impl.BookDaoImpl">
<property name="connectionNumber" value="10"/>
</bean>
1.5.2 构造器注入
1.5.2.1 引用类型
在bean中定义引用类型属性并提供可访问的构造方法
public class BookServiceImpl implements BookService{
private BookDao bookDao;public BookServiceImp1(BookDao bookDao) {
this.bookDao = bookDao;
}
}
配置中使用constructor-arg标签ref属性注入引用类型对象
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<constructor-arg name="bookDao" ref="bookDao"/>
</bean>
<bean id="bookDao"class="com.itheima.dao.impl.BookDaoImpl"/>
1.5.2.1 简单类型
在bean中定义引用类型属性并提供可访问的set方法
public class BookDaoImpl implements BookDao{
private int connectionNumber;
public void setConnectionNumber(int connectionNumber) {
this.connectionNumber = connectionNumber;
}
}
配置中使用constructor-arg标签value属性注入简单类型数据
<bean id="bookDao"class="com,itheima.dao.impl.BookDaoImpl">
<constructor-arg name="connectionNumber" value="10"/>
</bean>
配置中使用constructor-arg标签type属性设置按形参类型注入
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<constructor-arg type="int" value="19"/>
<constructor-arg type="java.lang.String" value="mysql"/>
</bean>
配置中使用constructor-arg标签index属性设置按形参位置注入
<bean id = "bookDao" class = "com.itheima.dao.impl.BookDaoImpl">
<constructor-arg index = "0" value = "10"/>
<constructor-arg index = "1" value = "mysql"/>
</bean>
1.5.3 依赖注入的选择:
-
强制依赖使用构造器进行,使用setter注入有概率不进行注入导致nul1对象出现
-
可选依赖使用setter注入进行,灵活性强
-
Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
-
如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
-
实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
-
自己开发的模块推荐使用setter注入
1.5.3.1 依赖自动装配:
- IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配
- 自动装配方式
- 按类型(常用)
- 按名称
- 按构造方法
- 不启动自动装配
<bean id="bookService"class="com.itheima,service.impl.BookServiceImpl" autowire="byName"/>
autowire:就是配置自动装配的属性标签
1.5.3.1.1 自动装配的特征:
- 自动装配用于引用类型依赖注入,不能对简单类型进行操作
- 使用按类型装配时 ( byType ) 必须保障容器中相同类型的bean唯一,推荐使用
- 使用按名称装配时( byName)必须保障容器中具有指定名称的bean,因变量名与配置合,不推荐使用
- 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效
1.5.4 集合注入
数组:List、Set、Map、Properties
- 注入数组对象
<property name="array">
<array>
<value>100</value>
<value>200</value>
<value>300</value>
</array>
</property>
- 注入List对象(重点)
<property name="list">
<list>
<value>itcast</value>
<value>itheima</value>
<value>boxuegu</value>
</list>
</property>
- 注入set对象
<property name="set">
<set>
<value>itcast</value>
<value>itheima</value>
<value>boxuegu</value>
</set>
</property>
- 注入Map对象(重点)
<property name="map">
<map>
<entry key="country" value="china"/>
<entry key="province" value="henan"/>
<entry. key="city" value="kaifeng"/>
</map>
</property>
- 注入Properties对象
<property name="properties">
<props>
<prop key="country">china</prop>
<prop key="province">henan</prop>
<prop key="city">kaifeng</prop>
</props>
</property>
1.6 第三方数据源管理
1.6.1 数据源对象管理
- 导入druid坐标
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
- 配置数据源对象作为spring管理的bean
<bean id="dataSource" class="com,alibaba.druid.pool.DruidDataSource">
<property name="driverClassName” value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/spring_db"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
1.7 加载properties文件
1.7.1 在applicationContext中开辟新的命名空间(context空间)
- 技巧:改空间分改五步
<beans xmIns="http://www.springframework.org/schema/beans"
xmIns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<!-- xmIns:context…… and ……/schema/context 中的两处context -->
xmIns:context="http://www.springframework.org/schema/context'
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
<!-- ……/schema/context and ……/context/spring-context.xsd 中的三处context -->
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
1.7.2 使用context空间加载properties文件
<context:property-placeholder location="jdbc.properties"/>
1.7.3 使用属性占位符${}读取properties文件中的属性
<bean class="com.alibaba.druid.pool.DruidDataSpurce">
<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>
1.7.4 加载多个properties文件
<context:property-placeholder location="classpath:*.properties" system-properties-mode="NEVER"/>
<!-- 在location中添加多个properties即可 -->
<!-- 补充说明,如果系统注入的配置属性与自写的冲突时,可以在system-properties-mode中设置系统属性为NEVER,不加载 -->
1.8 容器
1.8.1 创建容器
- 方式一:类路径加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext,xml");
- 方式二:文件路径加载配置文件
ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\applicationContext,xml");
- 加载多个配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean1.xml", "bean2.xml");
1.8.2 获取bean
- 方式一:使用bean名称获取
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
- 方式二:使用bean名称获取并指定类型
BookDao bookDao = ctx.getBean("bookDao",BookDao.class);
- 方式三:使用bean类型获取
BookDao bookDao = ctx.getBean(BookDao.class);
1.9 总结
1.10 注解开发
1.10.1 用component注解配置bean
-
第一步在bean的类上加上@component注解
-
在properties文件中的context命名空间中进行component的scan
<context:component-scan base-package="com.itheima.hao.impl"/>
- Spring提供@Component注解的三个衍生注解
1.10.2 纯注解开发
@Configuration
这个注解可以代替properties文件@ComponentScan("com.itheima")
这个可以代替<context:component-scan base-package="com.itheima.hao.impl"/>
- 最后创建容器对象
ApplicationContext ctx = new AnnotationConfigApplicationContextSpringConfig.class);
1.10.3 总结
1.10.4 注解开发bean的生命周期&作用范围
1.10.5 依赖注入
1.10.5.1 引用类型注入
- 用
@Autowired
注解来自动按类型注入
在使用
Autowired
时有点打破IOC的思想,因为Autowired
可以不用提供set入口方法,而是通过暴力反射来注入的
- 在有同类型的bean时想注入就要用按名称来注入了,
@Qualifier("bookDao2")
这个注解就可以实现
@Qualifier("beanName")
记住这个注解是依赖Autowired
注解的
1.10.5.2 简单类型注入
1.10.5.2 properties文件属性注入
- 第一步在配置类中用
PropertySource
注解来加载properties文件 - 第二步用
@Value("${name}")
就可以注入
1.10.6 纯注解管理第三方bean
- 导入式
- 扫描式
1.10.7 纯注解bean依赖注入
1.10.8 XML配置对比注解配置
1.11 spring整合mybatis
- 坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.</version>
</dependency>
1.12 Spring整合junit
- 导两个包
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
- 使用spring整合junit专用的类加载器
1.13 AOP
- 面向切面编程,一种编程范式,指导开发者如何组织程序结构
- 作用:在不惊动原始设计的基础上为其进行功能增强
- Spring理念:无入侵式/无侵入式
- 连接点(JoinPoint ):程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等
- 在SpringAOP中,理解为方法的执行
- 切入点( Pointcut ):匹配连接点的式子
- 在springAOP中,一个切入点可以只描述一个具体方法,也可以匹配多个方法
- 一个具体方法:com.itheima.dao包下的BookDao接口中的无形参无返回值的save方法
- 匹配多个方法:所有的save方法,所有的get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法
- 在springAOP中,一个切入点可以只描述一个具体方法,也可以匹配多个方法
- 通知(Advice):在切入点处执行的操作,也就是共性功能
- 在springAOP中,功能最终以方法的形式呈现
- 通知类:定义通知的类
- 切面(Aspect ): 描述通知与切入点的对应关系
1.13.1 APO快速入门(注解版)
1.13.1.1 导入aop相关的坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
1.13.1.2 定义接口和实现类
public interface BookDao {
public void save();
public void update();
}
@Repository
public class BookDaoImpl implements BookDao {
public void save() {
System.out.printIn(System.currentTimeMillis());
System.out.println("book dao save ...");
}
public void update(){
System.out.println("book dao update ...");
}
}
1.13.2 切入点表达式
- 切入点表达式标准格式:动作关键字( 访问修饰符 返回值 包名.类/接口名.方法名( 参数 )异常名
1.13.3 AOP的通知类型
-
AOP通知描述了抽取的共性功能,根据共性功能抽取的位置不同,最终运行代码时要将其加入到合理的位置
-
AOP通知共分为5种类型
- 前置通知
- 后置通知
- 环绕通知(重点)
- 前置通知
重点,常用
- 返回后通知(了解)
- 抛出异常后通知(了解)