Spring最好的一篇文章——IOC容器

1. IOC的概念及原理

⭐ 什么是IOC?

(1) 控制反转, 就是把对象创建和对象之间的调用过程,交给Spring进行管理。
(2) 使用IOC的目的: 为了降低耦合度——解耦。
(3) 上面的入门案例就是IOC的实现

⭐ IOC底层原理

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

⭐ IOC(接口)

  1. IOC思想基于IOC的容器完成,IOC容器底层就是对象工厂
  2. Spring提供IOC容器实现两种方式:(两个接口)
    (1) BeanFactory, IOC容器的基本实现,是Spring内部的使用接口,不提供给开发人员使用。
    (2) ApplicationContext:BeanFactory接口的子接口。提供更多强大的功能,一般由开发人员调用使用。
  3. ApplicationContext接口实现类有很多实现类。

2. Bean 管理操作实现的两种方式(xml配置文件实现)

⭐ 什么叫Bean管理?

Bean 管理指的是两个操作—— ☀ Spring创建对象、☀ Spring注入属性

2.1 基于xml方式创建对象

(1) 创建实体类
(2) spring的xml配置文件中配置bean标签

	<?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">
	
	<bean id="user" class="com.jzq.spring5.pojo.User"></bean>
	</beans>

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

2.2 基于xml方式注入属性

DI: 依赖注入,就是注入属性.

(1)使用set方法进行注入.

⭐ 创建对应实体类,以及对应成员属性的set方法
⭐ 这类注入必须有无参构造器

	package com.jzq.spring5.pojo;

	public class Book {
	    private String name;
	    private int age;
	
	
	    public String getName() {
	        return name;
	    }
	
	    public void setName(String name) {
	        this.name = name;
	    }
	
	    public int getAge() {
	        return age;
	    }
	
	    public void setAge(int age) {
	        this.age = age;
	    }
	
	    public void show() {
	        System.out.println(this.getName() + ":" + this.getAge());
	    }
	}
				

⭐ 在spring配置文件配置对象创建,配置属性注入。

	<?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">
	
	
	    <!-- set 方法注入属性 -->
	    <bean id="book" class="com.jzq.spring5.pojo.Book">
	        <!-- 使用property 完成属性注入
	             name: 类里面属性名称
	             value: 向属性注入的值
	        -->
	        <property name="name" value="天龙八部"></property>
	        <property name="age" value="15"></property>
	    </bean>
	</beans>

(2) 使用有参构造进行注入

⭐ 创建对应的实体类,要有构造方法

	package com.jzq.spring5.pojo;
	
	public class User {
	    public int age;
	
	    public void show() {
	        System.out.println("hello,spring5");
	    }
	}

⭐ 在spring配置文件中进行配置

	<?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">
	
	    <bean id="user" class="com.jzq.spring5.pojo.User"></bean>
	
	    <!-- set 方法注入属性 -->
	    <bean id="book" class="com.jzq.spring5.pojo.Book">
	        <!-- 使用property 完成属性注入
	             name: 类里面属性名称
	             value: 向属性注入的值
	        -->
	        <property name="name" value="天龙八部"></property>
	        <property name="age" value="15"></property>
	    </bean>
	
	    <!--  通过有参构造注入属性  -->
	    <bean id="orders" class="com.jzq.spring5.pojo.orders">
	        <constructor-arg name="uuid" value="4d5s45da4sdsa445sa"></constructor-arg>
	    </bean>
	</beans>

(3) 使用p名称空间注入(了解——set实现)

⭐ 使用p名称空间注入,可以简化基于xml配置方式
第一步 添加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="bookp" class="com.jzq.spring5.pojo.Book" p:name="11" p:age="151"></bean>

2.3 xml注入其他类型属性(空值或特殊符号)

⭐1.字面量

(1)null值

<!--  注入空值  -->
<property name="addree">
	<null></null>
</property>

(2)属性包含特殊符号

<!--  注入特殊符号  -->
<property name="addree">
	<value><![CDATA[<<济南>>]]></value>
</property>

2.4 xml注入外部bean

1 . 先写好逻辑层和Mapper层结构
⭐IOC容器创建的UserService对象可以调用UserMapper中操作数据库的方法。

在这里插入图片描述

2 . 注意看一下UserService中如何实现UserMapper实现类.
⭐ 通过xml注入(set方式),将UserMapperImpl对象注入到UserService的对象中。因为UserService中的是UserMapper的接口,所以注入实现类对象时,其实是一种多态的形式!具体注入方式看第三条的xml关系。

在这里插入图片描述

3 . 配置外部bean注入的xml
⭐ xml注入属性UserService,属性为userMapper。 由于注入的并不是一个值,而是一个对象类型(UserMapper),所以用ref进行绑定,而不是value。其中ref绑定的是一个UserMapperImpl实现类的bean的id值。

<!--  注入外部bean  -->
    <bean id="userservice" class="com.jzq.spring5.service.UserService">
        <!--  为它用到的属性注入  -->
        <property name="userMapper" ref="userMapperIpml"></property>
    </bean>

    <bean id="userMapperIpml" class="com.jzq.spring5.mapper.UserMapperImpl"></bean>

2.5 注入属性-内部bean

⭐ 一对多的关系
1.注意两个实体类之间的联系, 每个员工类中都有一个部门成员属性

	private int age;
    private String name;
    Department department;

xml的配置如下

<!--注入内部bean测试-->
    <bean id="worker" class="com.jzq.spring5.pojo.Workers">
        <property name="name" value="贾俊贤"></property>
        <property name="age" value="15"></property>
        <property name="department">
        	<!--注入属性内部bean-->
            <bean id="department" class="com.jzq.spring5.pojo.Department">
                <property name="name" value="协和部"></property>
            </bean>
        </property>
    </bean>

2.6 级联注入

⭐ 第一种方案

xml如下

<!--  测试级联注入  -->
    <bean id="worker2" class="com.jzq.spring5.pojo.Workers">
        <property name="name" value="贾俊贤2"></property>
        <property name="age" value="19"></property>
        <property name="department" ref="department2"></property>
    </bean>
    <!--  外部的级联的类  -->
    <bean id="department2" class="com.jzq.spring5.pojo.Department">
        <property name="name" value="协和部2"></property>
    </bean>

⭐ 第二种方案

这张方案需要设置访问器(get)

 public Department getDepartment() {
        return department;
    }

xml如下


    <!--  测试级联注入  -->
    <bean id="worker3" class="com.jzq.spring5.pojo.Workers">
        <property name="name" value="贾俊贤3"></property>
        <property name="age" value="19"></property>
        <property name="department" ref="department3"></property>
        <property name="department.name" value="协和部3"></property>
    </bean>
    <!--  外部的级联的类  -->
    <bean id="department3" class="com.jzq.spring5.pojo.Department">
    </bean>

2.7 注入array、list、map、set属性

⭐ 这里只是最简单的元素注入
xml 如下

<bean id="ceshi" class="com.jzq.spring5.popj.TestLei">
        <!--测试数组注入属性-->
        <property name="array">
            <array>
                <value>xxx</value>
                <value>xxxx</value>
                <value>xxxxx</value>
            </array>
        </property>

        <!--测试集合注入属性-->
        <property name="list">
            <list>
                <value>大厦大火傻大个</value>
                <value>dsadadssadas</value>
            </list>
        </property>

        <!--测试map注入-->
        <property name="map">
            <map>
                <entry key="姓名" value="xx"></entry>
                <entry key="年龄" value="58"></entry>
            </map>
        </property>

        <!--测试set-->
        <property name="set">
            <set>
                <value>大撒大撒单d</value>
                <value>dsadsdas</value>
            </set>
        </property>
    </bean>

2.8 注入List对象泛型

⭐ 第一种方式: 这种方式通过 ref链接到对象

	<bean id="ceshi" class="com.jzq.spring5.popj.TestLei">
        <!--测试集合对象-->
        <property name="bookList">
            <list>
                <ref bean="b1"></ref>
                <ref bean="b2"></ref>
            </list>
        </property>
    </bean>

    <bean id="b1" class="com.jzq.spring5.popj.Book">
        <property name="books">
            <list>
                <value>d7sad7sad7as7</value>
                <value>d7sad7sad7as7</value>
                <value>d7sad7sad7as7</value>
            </list>
        </property>
    </bean>

    <bean id="b2" class="com.jzq.spring5.popj.Book">
        <property name="books">
            <list>
                <value>233123</value>
                <value>d7213231237</value>
                <value>d7sad21323127sad7as7</value>
            </list>
        </property>
    </bean>

2.9 集合注入值抽取

⭐ 在spring中引入命名空间util:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:util="http://www.springframework.org/schema/util"
       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
                            http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
 

⭐ 使用抽取出的数值进行注入

<!--提取出list集合类型属性注入-->
    <util:list id="book">
        <value>dasdsadsad</value>
        <value>dsadsdsd7s8d7sd8</value>
    </util:list>
    <!--使用提取出来的list注入值-->
    <bean id="books" class="com.jzq.spring5.popj.Book">
        <property name="books" ref="book"></property>
    </bean>

2.10 工厂bean

通过配置工厂bean返回具体实例
⭐ 工厂类:要实现 FactoryBean 接口

package com.jzq.spring5.popj;

import org.springframework.beans.factory.FactoryBean;

import javax.swing.*;
import java.util.ArrayList;
import java.util.List;

public class Mybean implements FactoryBean<Book> {
    @Override
    public boolean isSingleton() {
        return false;
    }

    @Override
    public Book getObject() throws Exception {
        Book book = new Book();
        List<String> list = new ArrayList<>();
        list.add("dsaadad");
        list.add("dsaadad");
        list.add("dsaadad");
        book.setBooks(list);
        return book;
    }

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

xml 配置如下:

<!--  测试工厂bean  -->
    <bean id="myBean" class="com.jzq.spring5.popj.Mybean"></bean>

2.11 bean的作用域

⭐ bean是单实例还是多实例?

在Spring中,设置创建的bean实例默认是单实例对象。

⭐ 如何设置bean是单实例还是双实例?

在bean标签内设置scope为singleton为单实例。
设置为prototype为多实例。

⭐ singleton单实例和prototype多实例区别

singleton: 默认, spring加载配置文件就创建实例对象。
prototype: 在调用getBean的时候创建实例对象。

<bean id="books" class="com.jzq.spring5.popj.Book" scope="prototype">
	<property name="books" ref="book"></property>
</bean>

2.12 bean的生命周期

⭐ bean的整个运行顺序

  1. 通过构造器创建bean实例(无参构造)
  2. 为bean的属性设置值,和对其他bean的引用(调用set方法)
  3. 如果加了bean的后置处理器: 把bean实例传递bean后置处理器的方法postProcessBeforeInitialization
  4. 调用bean的初始化方法(需要在bean标签配置初始化参数:init-method )
  5. 如果加了bean的后置处理器: 把bean实例传递bean后置处理器的方法postProcessAfterInitialization
  6. bean创建实例(获取到对象)
  7. 当容器关闭的时候,调用bean的销毁方法(需要进行配置销毁的参数:destroy-method)

⭐实体类如下:

package com.jzq.spring5.popj;

public class Orders {
    private int uid;

    // 运行无参构造
    public Orders() {
        System.out.println("第一步执行了无参构造");
    }

    public int getUid() {
        return uid;
    }

    public void setUid(int uid) {
        this.uid = uid;
        System.out.println("第二步执行了赋值set");
    }

    public void initMethod() {
        System.out.println("第三步执行初始化函数(需要在bean配置)");
    }

    public void destoryMethod() {
        System.out.println("第五步执行了销毁函数(需要在bean配置)");
    }

}

⭐ bean的后置处理器类:

package com.jzq.spring5.popj;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPost implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化bean前执行(配置了bean后置处理器)");

        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化bean后执行(配置了bean后置处理器)");

        return bean;
    }
}

⭐ xml下的bean配置如下:

	<bean id="order" class="com.jzq.spring5.popj.Orders" init-method="initMethod" destroy-method="destoryMethod">
        <property name="uid" value="7878"></property>
    </bean>

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

2.13 xml自动装配

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

  1. 根据属性名自动注入

设置autowire参数为byType

	<bean id="c2" class="com.jzq.spring5.popj.C2" autowire="byName"></bean>

    <bean id="c1" class="com.jzq.spring5.popj.C1"></bean>
    <bean id="c3" class="com.jzq.spring5.popj.C1"></bean>
  1. 根据属性类型自动注入

设置autowire参数为byType
⭐注意参数注入不要有多个相同类型的需要注入的bean

	<bean id="c2" class="com.jzq.spring5.popj.C2" autowire="byType"></bean>

    <bean id="c1" class="com.jzq.spring5.popj.C1"></bean>

2.14 外部属性文件

例如数据库连接
通过context命名空间引入

⭐db.properties文件

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://x.x.x.x:3306/mybatis?userSSL=true&useUnicode=true&charaterEncoding=UTF-8"
username="xxxxxxx"
password="xxxxxxxxxx"

⭐ xml引入如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       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
                            http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsd">

    <!--引入外部属性文件-->
    <context:property-placeholder location="db.properties"/>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${driver}"></property>
        <property name="url" value="${url}"></property>
        <property name="username" value="username"></property>
        <property name="password" value="password"></property>
    </bean>
</beans>

3. Bean 管理操作实现的两种方式(基于注解方式实现)

⭐什么是注解?

注解是代码特殊标记,格式: @注解名称(属性名=属性值, …)。
使用注解的地方,注解作用在类上,方法上,属性上。
使用注解目的:简化xml配置

⭐spring针对bean管理中的创建对象提供的注解

  1. @Component
  2. @Service
  3. @Controller
  4. @Repository
    上面的四个注解功能一致,都是用来创建bean实例,只是在不同层去使用!

⭐使用注解应该配置的xml(扫描包)?

配置context
通过<context:component-scan>标签的base-package参数设置扫描的包,多个包的时候可以通过逗号隔开,或者写上层目录包

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       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
                        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
   <!--<context:component-scan base-package="com.jzq.ddd.popj, com.jzq.ddd.test"></context:component-scan>-->
    <context:component-scan base-package="com.jzq.ddd"></context:component-scan>

</beans>

3.1 bean基于注解创建对象

实体类
@Component(value = “book”) == xml里的 <bean id=“book”>

package com.jzq.ddd.popj;


import org.springframework.stereotype.Component;

@Component(value = "book")
public class Book {
    private String title;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public void show() {
        System.out.println("wxq大傻瓜");
    }
}

3.2 组件扫描的配置

默认的 <context:component-scan> 下 是use-default-filters=“true”,支持所有的注解扫描。设置为false时,我们可以自动去配置需要扫描的注解
<context:include-filter> 是扫描某注解
<context:exclude-filter> 是除了某注解外扫描,这里注意不要声明use-default-filters=“false”

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       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
                        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!--<context:component-scan base-package="com.jzq.ddd.popj, com.jzq.ddd.test"></context:component-scan>-->
    <!--<context:component-scan base-package="com.jzq.ddd"></context:component-scan>-->

    <!--  设置需要扫描的注解  -->
    <context:component-scan base-package="com.jzq.ddd" use-default-filters="false">
        <!--<context:include-filter>  指的是扫描什么注解-->
        <!--<context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>-->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <context:component-scan base-package="com.jzq.ddd">
        <!--<context:exclude-filter>  指的是不扫描什么注解-->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    </context:component-scan>
</beans>

3.3 基于注解实现属性注入

⭐ 介绍注解

@AutoWired: 根据属性类型进行自动装配 ⭐ 多个实现类的时候不可以使用。
@Qualifier: 根据属性名称进行注入, 注意要和实现类的注解@Repository(value = “xxx”) 一致。
@Resource: 也可以通过类型注入,也可以通过属性名注入,不是spring的注解,来源于javax.annotation.Resource。
@Value: 注入普通基本类型

⭐ 注意外部类要@Repository(value = “xxx”)注解

package com.jzq.ddd.mapper;

import org.springframework.stereotype.Repository;

@Repository(value = "userMapperImpl01")
public class UserMapperImpl implements UserMapper {

    @Override
    public void querySql() {
        System.out.println("查询到你要的数据了:" );
    }
}

⭐ 注入属性注解案例

package com.jzq.ddd.service;

import com.jzq.ddd.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

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

    // 值类型

    @Value(value = "书世俗叔叔世俗叔叔")
    private String date;

    // 根据值类型去注入属性,如果有多个实现类的话这种方式将会报错
    @Autowired
    @Qualifier(value = "userMapperImpl01")
    private UserMapper userMapper;

    @Autowired
    // 根据属性名称进行注入
    // 注意点1: 和@Autowired同时使用
    // 注意点2: 实现类要用注解@Repository(value = "c2")
    @Qualifier(value = "c2")
    private UserMapper userMapper2;


    public void show(){
        System.out.println(userMapper);
        userMapper.querySql();
        userMapper2.querySql();
        System.out.println(date);
    }
}

3.4 全注解开发

配置类

package com.jzq.ddd.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = {"com.jzq.ddd"})
// 这句话实际等于  <context:component-scan base-package="com.jzq.ddd"></context:component-scan>
public class Config {
}

使用时注意: new AnnotationConfigApplicationContext(配置类.class)

 @Test
    public void test03() {
        /*
            全部注解开发
         */
        ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        UserService userService = context.getBean("userService", UserService.class);
        userService.show();
    }
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值