Spring学习之 IOC容器

    科技2022-08-16  103

    文章目录

    一、Spring二、Spring的组成三、IOC概念和原理1、IOC本质2、IOC底层原理3、Spring提供IOC容器实现的两种方式 四、依赖注入(DI)1、IOC操作Bean管理(基于xml方式)2、IOC操作Bean管理(注入对象)3、IOC操作Bean管理(注入集合属性)4、IOC操作Bean管理(外部属性文件) 五、Bean作用域1、什么是bean2.类别3、配置 六、Bean生命周期七、Bean的自动装配1、byName2、byType 八、使用注解九、完全注解开发

    看的是b站尚硅谷Spring5的教学视频:https://www.bilibili.com/video/BV1Vf4y127N5

    一、Spring

    Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。

    1、Spring是轻量级的开源的JavaEE框架 2、Spring可以解决企业应用开发的复杂性 3、Spring有两个核心部分:IOC和AOP (1)IOC:控制反转,把创建对象过程交给Spring进行管理 (2)Aop:面向切面,不修改源代码进行功能增强 4、Spring特点 (1)方便解耦,简化开发 (2)Aop编程支持 (3)方便程序测试 (4)方便和其他框架进行整合 (5)方便进行事务操作 (6)降低API开发难度

    5、下载地址 (1)官网 : http://spring.io/ (2)官方下载地址 : https://repo.spring.io/libs-release-local/org/springframework/spring/ (3)GitHub : https://github.com/spring-projects

    二、Spring的组成

    Spring 框架是一个分层架构,由 7 个定义良好的模块组成。 Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式 。

    【Spring Core核心容器】: 核心容器提供 Spring 框架的基本功能。 核心容器的主要组件是 BeanFactory,它是工厂模式的实现。 BeanFactory 使用控制反转(IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。

    【Spring 上下文】: Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。 Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。

    【Spring AOP】: 通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能 , 集成到了 Spring 框架中。 所以,可以很容易地使 Spring 框架管理任何支持 AOP的对象。 Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。 通过使用 Spring AOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中。

    【Spring DAO】: JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。 异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。 Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。

    【Spring ORM】: Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。

    【Spring Web 模块】: Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。 所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。

    【Spring MVC 框架】: MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。 通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。

    三、IOC概念和原理

    1、IOC本质

    控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,把对象创建和对象之间的调用过程,交给Spring进行管理Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。使用IOC目的:为了耦合度降低

    2、IOC底层原理

    (1)xml解析 (2)工厂模式 (3)反射

    IOC思想基于IOC容器完成,IOC容器底层就是对象工厂

    3、Spring提供IOC容器实现的两种方式

    1、BeanFactory接口 IOC容器基本实现,是Spring内部接口的使用接口,不提供给开发人员进行使用

    加载配置文件时候不会创建对象,在获取对象时才会创建对象(延迟初始化)

    2、ApplicationContext接口 BeanFactory接口的子接口,提供更多更强大的功能,提供给开发人员使用

    加载配置文件时候就会把在配置文件对象进行创建,推荐使用!

    四、依赖注入(DI)

    1、Bean管理概念: (1)Spring创建对象 (2)Spring注入属性

    2、Bean管理操作有两种方式: (1)基于xml配置文件方式实现 (2)基于注解方式实现 【推荐】

    1、IOC操作Bean管理(基于xml方式)

    1、基于xml创建对象: (1)在spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建 (2)在bean标签有很多属性,介绍常用的属性

    id属性:唯一标识class属性:类全路径(包类路径)

    (3)创建对象时候,默认也是执行无参数构造方法完成对象创建

    <!--1 配置User对象创建--> <bean id="user" class="com.atguigu.spring5.User"></bean>

    2、基于xml注入属性(DI,依赖注入): (1)set方法 第一步,创建类,定义属性和对应的set方法

    public class Book { //创建属性 private String bname; //创建属性对应的set方法 public void setBname(String bname) { this.bname = bname; } }

    第二步,在spring xml配置文件配置对象创建,配置属性注入

    <!--(2)spring方式: set方法注入属性--> <bean id="book" class="com.atguigu.spring5.Book"> <!--使用property完成属性注入 name:类里面属性名称 value:向属性注入的值 --> <property name="bname" value="Hello"></property> <property name="bauthor" value="World"></property> </bean>

    (2)有参数构造函数注入 第一步,创建类,定义属性,创建属性对应有参数构造方法

    public class Orders { //属性 private String oname; private String address; //有参数构造 public Orders(String oname,String address) { this.oname = oname; this.address = address; } }

    第二步,在spring配置文件中进行配置

    <!--(2)spring方式:有参数构造注入属性--> <bean id="orders" class="com.atguigu.spring5.Orders"> <constructor-arg name="oname" value="Hello"></constructor-arg> <constructor-arg name="address" value="China!"></constructor-arg> </bean>

    3、p名称空间注入

    <!--1、添加p名称空间在配置文件头部--> <?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:p="http://www.springframework.org/schema/p"> <!--在这里添加一行p--> <!--2、在bean标签进行属性注入(算是set方式注入的简化操作)--> <bean id="book" class="com.atguigu.spring5.Book" p:bname="very" p:bauthor="good"> </bean>

    2、IOC操作Bean管理(注入对象)

    1、外部bean

    public class UserService {//service类 //创建UserDao类型属性,生成set方法 private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void add() { System.out.println("service add..............."); userDao.update();//调用dao方法 } } public class UserDaoImpl implements UserDao {//dao类 @Override public void update() { System.out.println("dao update..........."); } }

    Spring配置文件配置

    <!--1 service和dao对象创建--> <bean id="userService" class="com.atguigu.spring5.service.UserService"> <!--注入userDao对象 name属性:类里面属性名称 ref属性:创建userDao对象bean标签id值 --> <property name="userDao" ref="userDaoImpl"></property> </bean> <bean id="userDaoImpl" class="com.atguigu.spring5.dao.UserDaoImpl"></bean>

    2、内部Bean

    //部门类 public class Dept { private String dname; public void setDname(String dname) { this.dname = dname; } } //员工类 public class Emp { private String ename; private String gender; //员工属于某一个部门,使用对象形式表示 private Dept dept; public void setDept(Dept dept) { this.dept = dept; } public void setEname(String ename) { this.ename = ename; } public void setGender(String gender) { this.gender = gender; } }

    在spring配置文件中配置内部Bean

    <!--内部bean--> <bean id="emp" class="com.atguigu.spring5.bean.Emp"> <!--设置两个普通属性--> <property name="ename" value="Andy"></property> <property name="gender" value=""></property> <!--设置对象类型属性--> <property name="dept"> <bean id="dept" class="com.atguigu.spring5.bean.Dept"><!--内部bean赋值--> <property name="dname" value="宣传部门"></property> </bean> </property> </bean>

    3、级联赋值

    <!--方式一:级联赋值--> <bean id="emp" class="com.atguigu.spring5.bean.Emp"> <!--设置两个普通属性--> <property name="ename" value="Andy"></property> <property name="gender" value=""></property> <!--级联赋值--> <property name="dept" ref="dept"></property> </bean> <bean id="dept" class="com.atguigu.spring5.bean.Dept"> <property name="dname" value="公关部门"></property> </bean>

    3、IOC操作Bean管理(注入集合属性)

    //(1)创建类,定义数组、list、map、set 类型属性,生成对应 set 方法 public class Stu { //1 数组类型属性 private String[] courses; //2 list集合类型属性 private List<String> list; //3 map集合类型属性 private Map<String,String> maps; //4 set集合类型属性 private Set<String> sets; public void setSets(Set<String> sets) { this.sets = sets; } public void setCourses(String[] courses) { this.courses = courses; } public void setList(List<String> list) { this.list = list; } public void setMaps(Map<String, String> maps) { this.maps = maps; } <!--(2)在 spring 配置文件进行配置--> <bean id="stu" class="com.atguigu.spring5.collectiontype.Stu"> <!--数组类型属性注入--> <property name="courses"> <array> <value>java课程</value> <value>数据库课程</value> </array> </property> <!--list类型属性注入--> <property name="list"> <list> <value>张三</value> <value>小三</value> </list> </property> <!--map类型属性注入--> <property name="maps"> <map> <entry key="JAVA" value="java"></entry> <entry key="PHP" value="php"></entry> </map> </property> <!--set类型属性注入--> <property name="sets"> <set> <value>MySQL</value> <value>Redis</value> </set> </property> </bean>

    对象的集合的注入

    <!--创建多个course对象--> <bean id="course1" class="com.atguigu.spring5.collectiontype.Course"> <property name="cname" value="Spring5框架"></property> </bean> <bean id="course2" class="com.atguigu.spring5.collectiontype.Course"> <property name="cname" value="MyBatis框架"></property> </bean> <!--注入list集合类型,值是对象--> <property name="courseList"> <list> <ref bean="course1"></ref> <ref bean="course2"></ref> </list> </property>

    使用util标签完成list集合注入提取

    <!--第一步:在 spring 配置文件中引入名称空间 util--> <?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:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <!--添加util名称空间--> <!--第二步:使用 util 标签完成 list 集合注入提取--> <!--把集合注入部分提取出来--> <!--1 提取list集合类型属性注入--> <util:list id="bookList"> <value>易筋经</value> <value>九阴真经</value> <value>九阳神功</value> </util:list> <!--2 提取list集合类型属性注入使用--> <bean id="book" class="com.atguigu.spring5.collectiontype.Book" scope="prototype"> <property name="list" ref="bookList"></property> </bean>

    4、IOC操作Bean管理(外部属性文件)

    方式一,直接配置数据库信息 : (1)配置Druid(德鲁伊)连接池 (2)引入Druid(德鲁伊)连接池依赖 jar 包

    <!--直接配置连接池--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/userDb"></property> <property name="username" value="root"></property> <property name="password" value="root"></property> </bean>

    方式二,引入外部属性文件配置数据库连接池: (1)创建外部属性文件,properties 格式文件,写数据库信息(jdbc.properties)

    prop.driverClass=com.mysql.jdbc.Driver prop.url=jdbc:mysql://localhost:3306/userDb prop.userName=root prop.password=root

    把外部 properties 属性文件引入到 spring 配置文件中 —— 引入 context 名称空间

    <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 http://www.springframework.org/schema/context/spring-context.xsd"><!--引入context名称空间--> <!--引入外部属性文件--> <context:property-placeholder location="classpath:jdbc.properties"/> <!--配置连接池--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${prop.driverClass}"></property> <property name="url" value="${prop.url}"></property> <property name="username" value="${prop.userName}"></property> <property name="password" value="${prop.password}"></property> </bean> </beans>

    五、Bean作用域

    1、什么是bean

    在Spring中,那些组成应用程序的主体及由Spring IoC容器所管理的对象,被称之为bean。简单地讲,bean就是由IoC容器初始化、装配及管理的对象

    2.类别

    1、singleton Bean以单例方式存在,是默认值

    2、prototype 每次从容器中取出一个对象,都返回一个新的实例,即每次调用getBean()的时候等同于new xxxBean()

    3、request 每次http请求创建一个新的bean

    4、session 同一个http session共享一个Bean

    3、配置

    如何设置单实例还是多实例

    <bean id="book" class="com.atguigu.spring5.collectiontype.Book" scope="prototype"><!--设置为多实例--> <property name="list" ref="bookList"></property> </bean> 在spring配置文件bean标签里面有属性(scope)用于设置单实例还是多实例scope属性值 第一个值 默认值,singleton,表示是单实例对象 第二个值 prototype,表示是多实例对象singleton和prototype区别 第一 singleton单实例,prototype多实例 第二 设置scope值是singleton时候,加载spring配置文件时候就会创建单实例对象 设置scope值是prototype时候,不是在加载spring配置文件时候创建 对象,在调用getBean方法时候创建多实例对象

    六、Bean生命周期

    1、生命周期 :从对象创建到对象销毁的过程

    2、bean生命周期 (1)通过构造器创建bean实例(无参数构造) (2)为bean的属性设置值和对其他bean引用(调用set方法) (3)调用bean的初始化的方法(需要进行配置初始化的方法) (4)bean可以使用了(对象获取到了) (5)当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁的方法)

    3、bean的后置处理器,bean生命周期有七步 (1)通过构造器创建bean实例(无参数构造) (2)为bean的属性设置值和对其他bean引用(调用set方法) (3)把bean实例传递bean后置处理器的方法postProcessBeforeInitialization (4)调用bean的初始化的方法(需要进行配置初始化的方法) (5)把bean实例传递bean后置处理器的方法 postProcessAfterInitialization (6)bean可以使用了(对象获取到了) (7)当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁的方法)

    七、Bean的自动装配

    自动装配是使用spring满足bean依赖的一种方法。spring会在应用上下文中为某个bean寻找其依赖的bean。

    Spring中bean有三种装配机制,分别是: 在xml中显式配置在java中显式配置隐式的bean发现机制和自动装配。

    第三种就是自动化的装配bean。Spring的自动装配需要从两个角度来实现,或者说是两个操作:

    组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI 组件扫描和自动装配组合发挥巨大威力,使得显示的配置降低到最少。

    1、byName

    autowire byName (按名称自动装配)

    <bean id="user" class="com.kuang.pojo.User" autowire="byName"> </bean>

    2、byType

    autowire byType (按类型自动装配)

    使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一的异常。

    八、使用注解

    Spring 针对 Bean 管理中创建对象提供注解 下面四个注解功能是一样的,都可以用来创建 bean 实例 (1)@Component (2)@Service (3)@Controller (4)@Repository

    1、在spring配置文件中引入context文件头

    xmlns:context="http://www.springframework.org/schema/context" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd

    2、基于注解方式实现对象创建 (1)引入依赖 (2)开启组件扫描

    <!--开启组件扫描 1 如果扫描多个包,多个包使用逗号隔开 2 扫描包上层目录 --> <context:component-scan base-package="com.atguigu"></context:component-scan>

    (3)创建类,在类上面添加创建对象注解

    //在注解里面 value 属性值可以省略不写, //默认值是类名称,首字母小写 //UserService -- userService @Component(value = "userService") //注解等同于XML配置文件:<bean id="userService" class=".."/> public class UserService { public void add() { System.out.println("service add......."); } }

    (4)开启组件扫描细节配置

    <!--示例 1 use-default-filters="false" 表示现在不使用默认 filter,自己配置 filter context:include-filter ,设置扫描哪些内容 --> <context:component-scan base-package="com.atguigu" use-defaultfilters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/><!--代表只扫描Controller注解的类--> </context:component-scan> <!--示例 2 下面配置扫描包所有内容 context:exclude-filter: 设置哪些内容不进行扫描 --> <context:component-scan base-package="com.atguigu"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/><!--表示Controller注解的类之外一切都进行扫描--> </context:component-scan>

    3、基于注解方式实现属性注入 @Autowired:根据属性类型进行自动装配 @Qualifier:根据名称进行注入,这个@Qualifier 注解的使用,和上面@Autowired 一起使用 @Value:注入普通类型属性

    @Service public class UserService { //定义 dao 类型属性 //不需要添加 set 方法 //添加注入属性注解 @Autowired private UserDao userDao; public void add() { System.out.println("service add......."); userDao.add(); } } //Dao实现类 @Repository //@Repository(value = "userDaoImpl1") public class UserDaoImpl implements UserDao { @Override public void add() { System.out.println("dao add....."); } } //定义 dao 类型属性 //不需要添加 set 方法 //添加注入属性注解 @Autowired //根据类型进行注入 //根据名称进行注入(目的在于区别同一接口下有多个实现类,根据类型就无法选择,从而出错!) @Qualifier(value = "userDaoImpl1") private UserDao userDao; @Value(value = "abc") private String name

    九、完全注解开发

    @Configuration //作为配置类,替代 xml 配置文件 @ComponentScan(basePackages = {"com.atguigu"}) public class SpringConfig { }
    Processed: 0.017, SQL: 10