Spring-IOC容器学习笔记

IOC(概念和原理)

1、什么是IOC

​ (1)控制反转,把对象的创建和对象之间的调用过程,交给Spring进行管理

​ (2)使用IOC的目的:为了耦合度降低

2、IOC底层原理

​ (1)主要技术:xml解析、工厂模式、反射

3、画图展示IOC底层原理

image
image

IOC(接口)

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

2、Spring提供IOC容器实现的两种方式:(两个接口)

​ (1)BeanFactory:IOC容器基本实现,是Spring内部使用的接口,不提供开发人员使用

​ *加载配置文件时不会创建对象,在获取对象(使用)时采取创建对象

​ (2)ApplicationContext:BeanFactory的子接口,提供更多更强大的功能,一般由开发人员使用。

​ *加载配置时就会创建配置文件中配置的对象

3、ApplicationContext接口实现类

image

IOC操作Bean管理概述

1、什么是Bean管理

​ Bean管理指的是两个操作

​ (1)Spring创建对象

​ (2)Spring注入属性

2、Bean管理操作的两种方式

​ (1)基于xml配置文件方式实现

​ (2)基于注解方式实现

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

1、基于xml方式创建对象

​ (1)在Spring配置文件中,使用bean标签,标签里边添加对应属性,就可以实现对象创建

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

​ (2)bean标签中的属性

​ id:对象的别名(唯一标识)

​ class:对象类的全路径

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

2、基于xml方式注入属性

​ (1)DI:依赖注入,就是注入属性

​ *DI是IOC的一种具体实现

​ (2)在spring配置文件中配置对象创建,配置属性注入

​ 第一种方式:创建对象,set注入

<!--配置对象创建-->
<bean id="book" class="com.fs.spring5.Book">
    <!--使用property完成属性注入
        name:属性名称
        value:要注入的值
    -->
    <property name="bookName" value="Java Core"></property>
    <property name="bookAuthor" value="abc"></property>
</bean>

​ 第二种方式:有参构造注入

<bean id="order" class="com.fs.spring5.Order">
            <constructor-arg name="orderName" value="显卡"></constructor-arg>
            <constructor-arg name="orderAddress" value="cn"></constructor-arg>
<!--            <constructor-arg index="0" value=""></constructor-arg>-->
        </bean>

​ 第三种方式:p名称空间注入

​ ①:添加p名称空间在配置文件中

<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"
       
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

​ ②:进行属性注入,在bean标签里操作

<bean id="book" class="com.fs.spring5.Book"
      p:bookName="三体" p:bookAuthor="刘慈欣"></bean>

IOC操作Bean管理(xml注入其他类型属性)

1、字面量

​ (1)null值

<property name="bookAuthor">
	<!--null值-->
    <null></null>
</property>

​ (2)属性值包含特殊符号

<!--属性值包含特殊符号
    1.把特殊符号(例如<>)进行转义(&lt;&gt;)
    2.把带特殊符号内容写到CDATA中
-->
<property name="bookAuthor">
    <value><![CDATA[<<aaa>>]]></value>
</property>

2、注入属性-外部bean

​ (1)创建两个类,service 类和dao类

service:

public class UserService {

    public void add(){
        System.out.println("service add......");
    }
}

dao:

public interface UserDAO {
    public void update();
}

daoImpl:

public class UserDAOImpl implements UserDAO{

    @Override
    public void update() {
        System.out.println("DAO update......");
    }
}

​ (2)在service中调用dao里面的方法

public class UserService {

    //创建UserDAO类型属性,生成set方法

    private UserDAO userDAO;

    public void setUserDAO(UserDAO userDAO) {
        this.userDAO = userDAO;
    }

    public void add(){
        System.out.println("service add......");
        userDAO.update();
    }
}

​ (3)在spring配置文件中进行配置

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

3、注入属性-内部bean和级联赋值

以部门表与员工表为例

​ (1)一对多关系,部门和员工。一个部门有多个员工,一个员工只属于一个部门。

​ (2)创建部门和员工实体类

/**
 * 部门实体类
 * @author sdl98
 * @create 2022-06-20 10:14
 */
public class Dept {

    private String deptName;

    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }
}
/**
 * 员工实体类
 * @author sdl98
 * @create 2022-06-20 10:15
 */
public class Emp {
    private Integer id;
    private String empName;
    private Dept dept;

    public void setId(Integer id) {
        this.id = id;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }
}

​ (3)在spring配置文件中进行配置

<bean id="emp" class="com.fs.spring5.bean.Emp">
    <property name="id" value="1"></property>
    <property name="empName" value="admin"></property>
    <property name="dept">
        <bean id="dept" class="com.fs.spring5.bean.Dept">
            <property name="deptName" value="IT"></property>
        </bean>
    </property>
</bean>

4、注入属性-级联赋值

(1)第一种写法

<bean id="emp" class="com.fs.spring5.bean.Emp">
    <property name="id" value="1"></property>
    <property name="empName" value="admin"></property>
    <!--级联赋值-->
    <property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.fs.spring5.bean.Dept">
    <property name="deptName" value="IT"></property>
</bean>

(2)第二种写法

<bean id="emp" class="com.fs.spring5.bean.Emp">
    <property name="id" value="1"></property>
    <property name="empName" value="admin"></property>
    <!--级联赋值-->
    <property name="dept" ref="dept"></property>
    <property name="dept.deptName" value="hr"></property>
</bean>
<bean id="dept" class="com.fs.spring5.bean.Dept"></bean>

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

1、注入数组

2、注入List集合

3、注入Map集合

4、注入Set集合

5、在集合中设置对象类型值

用例类:

public class Student {
    //1.数组类型属性
    private String[] courses;
    //2.List集合类型
    private List<String> list;
    //3.Map集合类型
    private Map<String,String> map;
    //4.Set集合类型
    private Set<String> set;
    //学生所学的多门课程
    private List<Course> courseList;

    public void setCourseList(List<Course> courseList) {
        this.courseList = courseList;
    }

    public void setCourses(String[] courses) {
        this.courses = courses;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public void setSet(Set<String> set) {
        this.set = set;
    }

    @Override
    public String toString() {
        return "Student{" +
                "courses=" + Arrays.toString(courses) +
                ", list=" + list +
                ", map=" + map +
                ", set=" + set +
                ", courseList=" + courseList +
                '}';
    }
}
public class Course {
    private String courseName;
    private Integer courseId;

    public void setCourseName(String courseName) {
        this.courseName = courseName;
    }

    public void setCourseId(Integer courseId) {
        this.courseId = courseId;
    }

    @Override
    public String toString() {
        return "Course{" +
                "courseName='" + courseName + '\'' +
                ", courseId=" + courseId +
                '}';
    }
}

spring配置文件:

<!--集合类型注入-->
<bean id="student" class="com.fs.spring5.collectiontype.Student">
    <!--数组-->
    <property name="courses">
        <array>
            <value>java</value>
            <value>sql</value>
        </array>
    </property>
    <!--list集合-->
    <property name="list">
        <list>
            <value>张三</value>
            <value>三儿</value>
        </list>
    </property>
    <!--map集合-->
    <property name="map">
        <map>
            <entry key="1" value="java"></entry>
            <entry key="2" value="c++"></entry>
        </map>
    </property>
    <!--set集合-->
    <property name="set">
        <set>
            <value>MySql</value>
            <value>Redis</value>
        </set>
    </property>
</bean>

测试方法:

@Test
public void testStudent(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
    Student student = context.getBean("student", Student.class);
    System.out.println(student);
}

6、把集合注入部分提取出来

(1)在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:p="http://www.springframework.org/schema/p"
       
       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">
</beans>

(2)使用util标签完成List集合注入提取

<util:list id="bookList">
    <value>1</value>
    <value>a</value>
    <value>!</value>
</util:list>

<bean id="book" class="com.fs.spring5.collectiontype.Book">
    <property name="list" ref="bookList"></property>
</bean>

IOC操作Bean管理(FactoryBean)

Spring 有两种类型 bean,一种普通 bean,另外一种工厂 bean(FactoryBean)

1、普通 bean:在配置文件中定义 bean 类型就是返回类型

2、工厂 bean:在配置文件定义 bean 类型可以和返回类型不一样

​ 第一步 创建类,让这个类作为工厂 bean,实现接口 FactoryBean

​ 第二步 实现接口里面的方法,在实现的方法中定义返回的 bean 类型

public class MyBean implements FactoryBean<Course> {

    @Override
    public Course getObject() throws Exception {
        Course course = new Course();
        course.setCourseId(1);
        course.setCourseName("AA");
        return course;
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        return FactoryBean.super.isSingleton();
    }
}

IOC操作Bean管理(bean作用域)

1、在 Spring 里面,默认情况下,bean 是单实例对象,如下测试代码

@Test
public void testBook(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
    Book book1 = context.getBean("book", Book.class);
    Book book2 = context.getBean("book", Book.class);
    System.out.println(book1);
    System.out.println(book2);
}

结果为:

	com.fs.spring5.collectiontype.Book@4bb4de6a
	com.fs.spring5.collectiontype.Book@4bb4de6a

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

通过bean中scope标签可以设置

​ 第一个值 默认值,singleton,表示是单实例对象

​ 第二个值 prototype,表示是多实例对象

在上方测试中设置bean标签为

<bean id="book" class="com.fs.spring5.collectiontype.Book" scope="prototype">
        <property name="list" ref="bookList"></property>
    </bean>

再次测试结果为

	com.fs.spring5.collectiontype.Book@4bb4de6a
	com.fs.spring5.collectiontype.Book@7ba18f1b

singleton 和 prototype 区别

第一 singleton 单实例,prototype 多实例

第二 设置 scope 值是 singleton 时候,加载 spring 配置文件时候就会创建单实例对象 设置 scope 值是prototype 时候,不是在加载 spring 配置文件时候创建 对象,在调用 getBean 方法时候创建多实例对象

IOC操作Bean管理(bean生命周期)

1、生命周期

​ 从对象创建到对象销毁的过程

2、bean 生命周期

(1)通过构造器创建 bean 实例(无参数构造)

(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)

(3)调用 bean 的初始化的方法(需要进行配置初始化的方法)

(4)bean 可以使用了(对象获取到了)

(5)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)

3、演示bean的生命周期

实体类:

public class Order {

    private String orderName;

    //无参构造器
    public Order() {
        System.out.println("调用无参构造创建bean实例");
    }

    public Order(String orderName) {
        this.orderName = orderName;
    }

    public void setOrderName(String orderName){
        this.orderName = orderName;
        System.out.println("调用set方法设置属性的值");
    }
    public void initMethod(){
        System.out.println("执行初始化方法");
    }
    public void destroyMethod(){
        System.out.println("执行销毁方法");
    }
}

xml配置文件:

<bean id="order" class="com.fs.spring5.bean.Order" init-method="initMethod" destroy-method="destroyMethod">
    <property name="orderName" value="手机"></property>
</bean>

测试方法:

    @Test
    public void testMyBean4() {
//        ApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
        Order order = context.getBean("order", Order.class);
        System.out.println(order);

        //手动销毁bean
        context.close();
    }

结果(对应bean生命周期的五步):

	调用无参构造创建bean实例
	调用set方法设置属性的值
	执行初始化方法
	com.fs.spring5.bean.Order@12c8a2c0
	执行销毁方法

4、加上bean的后置处理器,bean生命周期有七步

(1)通过构造器创建 bean 实例(无参数构造)

(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)

(3)把bean实例传递给bean后置处理器(postProcessBeforeInitialization)

(4)调用 bean 的初始化的方法(需要进行配置初始化的方法)

(5)把bean实例传递给bean后置处理器(postProcessAfterInitialization)

(6)bean 可以使用了(对象获取到了)

(7)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)

5、添加后置处理器效果

(1)创建类,实现接口 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;
    }
}

(2)在xml配置文件中配置后置处理器

<!--配置后置处理器-->
<bean id="myBeanPost" class="com.fs.spring5.bean.MyBeanPost"></bean>

(3)再次执行测试方法,展示七步生命周期

调用无参构造创建bean实例
调用set方法设置属性的值
初始化之前执行的方法
执行初始化方法
初始化之后执行的方法
com.fs.spring5.bean.Order@18bf3d14
执行销毁方法

IOC操作Bean管理(xml自动装配)

1、自动装配的概念

​ 根据指定装配规则(属性名称或者属性类型),Spring 自动将匹配的属性值进行注入

2、自动装配过程

​ bean 标签属性 autowire,配置自动装配

​ autowire 属性常用两个值:

​ byName 根据属性名称注入 ,注入值 bean 的 id 值和类属性名称一样

​ byType 根据属性类型注入

(1)根据属性名称自动注入

<bean id="emp" class="com.fs.spring5.autowire.Emp" autowire="byName"></bean>
	<bean id="dept" class="com.fs.spring5.autowire.Dept"></bean>

(2)根据属性类型自动注入

<bean id="emp" class="com.fs.spring5.autowire.Emp" autowire="byType"></bean>
	<bean id="dept" class="com.fs.spring5.autowire.Dept"></bean>

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

1、直接配置数据库信息

​ (1)导包

​ (2)配置druid连接池

<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:13306/spring"></property>
    <property name="username" value="root"></property>
    <property name="password" value="abc123"></property>
</bean>

2、引入外部配置文件配置数据库连接池

(1)创建外部属性文件,properties 格式文件,写数据库信息

prop.driverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql://localhost:13306/spring
prop.username=root
prop.password=abc123

(2)把外部 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: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>

IOC操作Bean管理(基于注解方式)

1、什么是注解

​ (1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值)

​ (2)注解可以作用在类,方法,属性等之上

​ (3)使用注解的目的:简化xml配置

2、Spring针对Bean管理中创建对象提供的注解

​ (1)@Component

​ (2)@Service

​ (3)@Controller

​ (4)@Repository

*这四个注解都可以用来创建bean实例

3、基于注解方式创建对象

*注解的原理和AOP思想有关

​ (1)引入aop依赖

image

​ (2)开启组件扫描

*IDEA可以自动配置命名空间,需要导入jar包,然后<component-scan ,选择提示即可

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

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

@Service(value = "userService")
public class UserService {

    public void add(){
        System.out.println("service add...");
    }
}

​ (4)测试

@Test
public void testService(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
    UserService userService = context.getBean("userService", UserService.class);
    System.out.println(userService);
    userService.add();
}

4、开启组件扫描配置细节

use-default-filters="false" 表示现在不使用默认filter,自己配置filter
context:include-filter 设置扫描哪些内容

<context:component-scan base-package="com.fs" use-default-filters="false">
    <context:include-filter type="annotation"
                            expression="org.springframework.stereotype.Service"/>
</context:component-scan>

context:exclude-filter 设置不扫描哪些内容

<context:component-scan base-package="com.fs">
    <context:exclude-filter type="annotation"
                            expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

5、基于注解方式实现属性注入

(1)@AutoWired:根据属性类型进行自动装配(注入)

​ 第一步 把service和dao对象创建,在service和dao类添加创建对象注解

​ 第二步 在service注入dao对象,在service类添加dao类型属性,在属性上使用此注解

(2)@Qualifier:根据属性名称进行注入

​ 此注解需要与@Autowired一起使用

@Autowired
@Qualifier(value = "UserDaoImpl1")
private UserDao userDao;

​ @Autowired 会先根据类型匹配, 如果多个同类型对象,会根据对象名字进行匹配。可以不需要 @Qualifier

(3)@Resource:可以根据类型,也可以根据名称,默认根据名称注入,通过@Resource(name=?)或@Resource(type=?)设置,这是一个jdk自带的注解,在后续jdk版本中被删除

(4)@Value:注入普通类型

@Value(value = "acc")
private String userName;

6、完全注解开发

(1)创建配置类,替代配置文件

@Configuration  //将当前类作为配置类,用此类替代xml配置文件
@ComponentScan(basePackages = {"com.fs"})
public class SpringConfig {
}

(2)测试类写法更改为

@Test
public void testService(){
    ApplicationContext context = new 
    
    AnnotationConfigApplicationContext(SpringConfig.class);
    
    UserService userService = context.getBean("userService", UserService.class);
    System.out.println(userService);
    userService.add();
}
posted on 2022-06-26 17:40  我可是条大鲨鱼  阅读(32)  评论(0)    收藏  举报