Spring框架核心细讲 IOC部分
文章目录
前言
此次是对于自己所学Spring中的一些重要知识的回顾与知新, 从浅入深,从使用Spring的好处到核心底层
一、Spring框架概述
- Spring是轻量级的开源的JavaEE框架
- Spring可以解决企业级应用开发的复杂性
- Spring两个核心的部分:IOC / AOP
(1) IOC:控制反转 将创建对象的过程交给Spring进行管理
(2) AOP:面向切面,不修改源代码进行功能的加强 - Spring特点
(1) 方便解耦 简化开发 – Spring将创建对象和注入属性全交给Spring管理
(2) Aop编程支持 – 可以在不影响主程序的结构下,添加功能加强
(3) 方便程序调试
(4) 方便和其它框架进行整合 – Spring内部有很多对于其它框架的整合jar包
(5) 方便进行事务操作
(6) 降低API开发难度 – 一个配置 一个注解 干掉了以前几十行 上百行的工作量
二、IOC概念和原理
2.1 什么是IOC
(1) 控制反转,将对象创建和对象之间的调用过程,交给Spring进行管理
(2) 使用IOC目的,降低耦合度
(3) 做入门案例就是IOC实现
2.2 IOC底层原理
(1) xml解析 工厂模式 反射
将创建对象和注入属性的工作在配置文件写好 Spring只需要读取 操作就是
Spring有两种工厂模式创建对象的方式 后面会娓娓道来
反射:通过读取编译好的class文件,获取已经加载到内存中的类,来完成动态操作
2.3 Bean管理
2.3.1 基于xml方式创建对象
(1)在 spring 配置文件中,使用 bean 标签,标签里面添加对应属性,就可以实现对象创建
(2)在 bean 标签有很多属性,介绍常用的属性 * id 属性:唯一标识 * class 属性:类全路径(包类路径)
(3)创建对象时候,默认也是执行无参数构造方法完成对象创建
<!--
name:类里面属性的名称
value:向属性注入的值
-->
<!--配置User創建-->
<bean id="user" class="com.worker.spring5.User"></bean>
上面是最普遍的插入方法,接下来讲解静态工厂和实例工厂的方式
实体类
这里没什么特别需要讲的,无参有参构造器,getter,setter,toString即可
public class Book {
private String name;
private int price;
private String detail;
public Book() {
}
public Book(String name, int price, String detail) {
this.name = name;
this.price = price;
this.detail = detail;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", price=" + price +
", detail='" + detail + '\'' +
'}';
}
}
静态工厂
创建一个staticFactory 静态工厂类
配置静态方法获取实体类Book 设置属性
//静态工厂
public class staticFactory {
public static Book getBook(String bookName) {
System.out.println("static静态工厂......");
Book book = new Book();
book.setName("javascript DOM编程艺术");
book.setPrice(67.8);
book.setDetail("学习使我强大");
return book;
}
}
实例工厂
创建一个 InstanceFactory 实例工厂类
配置实例方法获取实体类Book 设置属性
// 实例工厂
public class InstanceFactory {
public Book getBook(String bookName) {
System.out.println("实例工厂.......");
Book book = new Book();
book.setName("你不知道的javascript");
book.setPrice(47.8);
book.setDetail("学习使我强大");
return book;
}
}
xml配置文件
bean标签上使用 factory-method 指定创建对象的方法
factory-bean 指定工厂bean 实体使用
constructor-arg 该属性为有参构造器设置属性 工厂返回的是Book实例 前提是有对应几个参数的构造器
<!-- 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">
<!--
知识点:
factory-bean指定使用那个工厂实例;
factory-method指定使用那个工厂方法
-->
<!--1.static静态工厂-->
<bean id="book1" class="com.worker618.factory.staticFactory" factory-method="getBook">
<!--可以为方法指定参数-->
<constructor-arg value="javascript"/>
</bean>
<!--2.实例工厂-->
<bean id="InstanceFactory" class="com.worker618.factory.InstanceFactory"></bean>
<bean id="book2" class="com.worker618.pojo.Book" factory-bean="InstanceFactory" factory-method="getBook">
<constructor-arg value="javascipt"/>
</bean>
</beans>
2.3.2 基于注解方式创建对象
1.什么是注解
(1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值…)
(2)使用注解,注解作用在类上面,方法上面,属性上面
(3)使用注解目的:
1、简化 xml 配置
2、Spring 针对 Bean 管理中创建对象提供注解
(1)@Component 通用注解 当不知道该bean是什么层时使用
(2)@Service Serviece服务层
(3)@Controller SpringMVC 控制层
(4)@Repository 对应持久层即 Dao 层,主要用于数据库相关操作
- 上面四个注解功能是一样的,都可以用来创建 bean 实例
2.基于注解方式实现对象创建
1.引入依赖
2.开启组件扫描
- 需要开启context命名空间
如果扫描多个包,逗号隔开
也可以将路径成到父包 对父类的扫描 完成了代码的冗余
3.注解里的value属性可以省略不写 默认是class类首字母小写形式
<context:component-scan base-package="com.worker"></context:component-scan>
设置此属性为false 定制扫描规则
use-default-filters=“false” 默认为true 全部扫描 可以设置为false
<!--扫描文件包含有Controller注解的-->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<!--扫描文件不包含有Controller注解的-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
4.基于注解方式实现属性注入
(1)@Autowired:根据属性类型进行自动装配
(2)@Qualifier:根据名称进行注入 这个@Qualifier 注解的使用,和上面@Autowired 一起使用
@Qualifier(value = “userDaoImpl1”) //根据名称进行注
(3)@Resource:可以根据类型注入,可以根据名称注入 —> javax.annotation.Resource
(4)@Value:注入普通类型属性
官方不推荐使用Resource
@Repository(value = "userDaoimpl2")
public class UserDaoimpl2 implements UserDao{
@Override
public void add() {
System.out.println("add2......");
}
}
/* 默认值类名称 首字母小写 */
@Service
public class UserService {
// 不需要添加set方法
@Autowired
@Qualifier(value = "userDaoimpl1")
private UserDao userDao1;
@Resource(name="userDaoimpl2")
private UserDao userDao2;
@Value(value = "abc")
private String name;
}
官方不推荐使用Resource
5.完全注解开发
创建配置类
// 将当前类作为配置类 替代xml配置文件
@ComponentScan(basePackages = {"com.worker"}) // 开启组件扫描
@Configuration // 该注解作用 使当前类作为Spring的配置类 替代xml配置文件
public class SpringConfig {
}
2.3.3 xml自动装配
1.什么是自动装配
(1)根据指定装配规则(属性名称或者属性类型),Spring 自动将匹配的属性值进行注入
2.演示自动装配过程 autoWire属性完成
(1)根据属性名称自动注入
( 2 ) 根据 属性类型自动注入
注意点:同一个xml文件不可以出现多个相同类型的bean 并不清楚该选择哪个bean
autowire="byName"
autoWire="byType
<bean id="book" class="com.worker.spring5.bean.Book" init-method="init" destroy-method="destory" autowire="byName">
<property name="bname" value="中国美食"></property>
</bean>
<!--配置后置处理器-->
<bean id="myBeanPost" class="com.worker.spring5.bean.MyBeanPost"></bean>
2.3.4 外部属性文件
1、直接配置数据库信息
<bean id="dataSourse" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="root"></property>
<property name="password" value="1234"></property>
<property name="url" value="jdbc:mysql//localhost:3307/test?useUnicode=true&setCharEncoding=utf-8"></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
</bean>
读取配置文件进行注入属性
需要开启context命名空间
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath:配置文件全名"/>
<!--配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" >
<!-- 获取properties文件内容,根据key获取,使用spring表达式获取 -->
<property name="driverClassName" value="${配置文件的name值}"></property>
<property name="url" value="${配置文件的name值}"></property>
<property name="username" value="${配置文件的name值}"></property>
<property name="password" value="${配置文件的name值}"></property>
2.3.5 普通类型Bean:配置定义的bean类型就是返回类型
xml配置
<!--配置User創建-->
<bean id="user" class="com.worker.spring5.User"></bean>
Book类
private String bname;
//1.set方法注入
public void setBname(String bname) {
this.bname = bname;
}
工厂Bean(FactoryBean):配置文件定义bean类型可以和返回类型不一样
需要继承FactoryBean<返回的类型>
// Dept类
public class Dept implements FactoryBean<Course> {
// 定义返回的类型
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setName("你是很帅的");
return course;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
xml配置
<bean id="dept" class="com.worker.spring5.bean.Dept"></bean>
2.3.6 Bean作用域
(1)Bean作用域分为seesion/request/application/singleton/prototype
作用域 | 描述 |
---|---|
singleton | 在spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,bean作用域范围的默认值。 |
prototype | 每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()。 |
session | 同一个HTTP Session共享一个Bean,不同Session使用不同的Bean。该作用域仅适用于web的Spring WebApplicationContext环境。 |
request | 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于web的Spring WebApplicationContext环境。 |
application | 限定一个Bean的作用域为ServletContext的生命周期。该作用域仅适用于web的Spring WebApplicationContext环境。 |
(2)singleton 和 prototype 区别
第一 singleton 单实例,prototype 多实例
第二 设置 scope 值是 singleton 时候,加载 spring 配置文件时候就会创建单实例对象
设置 scope 值是 prototype 时候,不是在加载 spring 配置文件时候创建 对象,在调用 getBean 方法时候创建多实例对象
默认情况 bean单实例对象 scope=“singleton”
所以这里打印的实例地址都是一样的 \color{HotPink}{所以这里打印的实例地址都是一样的} 所以这里打印的实例地址都是一样的
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
Book book1 = context.getBean("book", Book.class);
Book book2 = context.getBean("book", Book.class);
System.out.println(book1);
System.out.println(book2);
}
加上scope="prototype" 接下来创建的bean都是多实例对象
打印地址就会发生变化
\color{HotPink}{打印地址就会发生变化}
打印地址就会发生变化
<bean id="book" class="com.worker.spring5.bean.Book" scope="prototype"></bean>
2.3.7bean的生命周期
1、生命周期
(1)从对象创建到对象销毁的过程
2、bean 生命周期
(1)通过构造器创建 bean 实例(无参数构造)
(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
(3)调用 bean 的初始化的方法(需要进行配置初始化的方法)
(4)bean 可以使用了(对象获取到了)
(5)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
3.配置 在bean中配置两个方法 init和destory xml中配置init-method destory-method属性 值为bean中定义的方法名
Book.class
public class Book {
private String bname;
public Book(){
System.out.println("第一步 调用无参构造");
}
public void setBname(String bname) {
this.bname = bname;
System.out.println("第二步 调用set注入属性");
}
public void init(){
System.out.println("第三步 初始化准备");
}
// 第四步获取实例 创建对象
public void destory(){
System.out.println("第五步 结束了 销毁吧");
}
}
x m l 配置 \color{hotpink}{xml配置} xml配置
<bean id="book" class="com.worker.spring5.bean.Book" init-method="init" destroy-method="destory">
<property name="bname" value="中国美食"></property>
</bean>
在bean生命周期里还有初始化之前和初始化之后(需要配置后置处理器)
后置处理器类配置 需要继承BeanPostProcessor接口 重写两个方法
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之前执行的方法");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之后执行的方法");
return bean;
}
}
x m l 配置 \color{hotpink}{xml配置} xml配置
<!--配置后置处理器-->
<bean id="myBeanPost" class="com.worker.spring5.bean.MyBeanPost"></bean>
三、扩展部分
3.1 区分环境的Bean
bean标签属性 profile: test(测试) / dev(开发)
<beans profile="test">测试环境</beans>
<beans profile="dev">开发环境</beans>
// 指定使用开发/测试环境的bean
System.setProperty("spring.profiles.active","test")
// 虚拟机参数位置加载 命令行指定
-Dspring.profiles.active=test
3.2 导入外部配置文件
作用:导入外部配置文件 各个配置文件因为业务拆分模块 最后导入到主配置文件 可读性加强 实现解耦与模块复用
import标签的resource指定xml配置文件路径
classpath为当前类路径作为根路径
// 随着Spring启动一起加载
<import resource="classpath:bean2.xml"></import>
3.3 有别名的Bean
使用alias标签 name(为哪个bean起别名) alias(起的别名) 两个属性
// 给bean起别名 与bean标签的name一样 与bean有这映射关系
<alias name="dept" alias="course"></alias>
3.4 常用的三种getBean方法
3.5 配置Connection
<bean id="dept" class="com.worker.spring5.bean.Dept"></bean>
<bean class="java.lang.Class" factory-method="forName">
<constructor-arg name="className" value="com.mysql.jdbc.Driver"></constructor-arg>
</bean>
<bean id="connection" class="java.sql.DriverManager" factory-method="getConnection" scope="prototype">
<constructor-arg name="url" value="jdbc:mysql:///test"/>
<constructor-arg name="user" value="root"/>
<constructor-arg name="password" value="1234"/>
</bean>
</beans>
总结
以上就是今天要讲的内容,本文仅仅简单介绍了