IOC和DI

IOC和DI

IOC(inversion of Control) 控制反转容器

如何理解控制反转?

将对象的创建,配置和维护交给第三方管理,解决了依赖的耦合度,大大降低。

由容器来进行创建,配置和维护等工作,用户需要调用对象,就可以在IOC容器中获取。

对象于对象之间的依赖关系在spring中如何解决

Spring中对象在创建之后,需要依赖其他对象时,就需要依赖注入DI(Dependecy injection)

控制反转是将对象交给外部管理,依赖注入问题也可以交给IOC容器进行管理

IOC核心在于:对象不由使用方双方管理,而是交予第三方管理。

优点为:

  1. 资源集中管理,实现资源的可配置和维护
  2. 降低使用资源双方的依赖程度,降低耦合度。

Spring控制依赖

  1. 增加一个spring的配置文件
  2. 解析XML文件获取管理对象,反射
  3. 将解析的bean放入BeanFactory工厂类
  4. 在工厂类中通过反射创建处person类

IOC容器介绍

解决对象的创建和对象之间的依赖关系。
在这里插入图片描述

ApplicationContext容器中的接口的继承关系,ApplicationContext是BeanFactory的子接口之一,即BeanFactory是Spring IOC容器定义的最底层的接口,ApplicationCentext是BeanFactory的高级实现之一,是对BeanFactory功能做了许多的扩展。

BeanFactory

BeanFactory是最底层的IOC容器实现

现在已经不用了

//获取IOC容器
XmlBeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("application.xml"));

ApplicationContext

是IOC的高级使用,对BeanFectory的扩展,实际过程中使用此类

ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");

主要使用的三种创建IOC的方式

ClassPathXmlApplicationContext

相对路径读取classpath中的资源,读本项目下

ClassPathXmlApplicationContext("application1.xml");
FileSystemXmlAplicationContext

读取指定路径下的资源

new FileSystemXmlApplicationContext("全路径");
XmlWebAplicationContext

需要在Web环境下读取资源,读取网络中的IOC路径

其他创建

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JJafCqMI-1617965911879)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20210311183001548.png)]

BeanFactory和ApplicationContext的关系和区别使用和作用点

BeanFactory是最底层的IOC容器实现,而ApplicationContext 而是BeanFactory的拓展,是IOC的高级使用

作用:BeanFactory 负责读取bean配置文档,管理bean的加载,实例化,维护bean之间的依赖关系,负责bean的声明周期

而ApplicationContext除了满足以上的功能外,还提供了完整的框架功能 1.国际化支持 2.资源访问 3.事件传递

使用:

BeanFactory

//获取IOC容器
XmlBeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("application.xml"));

AoolicationContext

ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");

Bean的实例化方式

Spring容器装配Bean的方式主要是两种

  1. 基于XML配置方式
  2. 基于注解的方式,实际使用最多
基于XML配置方式装配Bean

Bean的装配实例化方式

基于无参构造函数创建对象重点
//id 类名   class 包路径
<bean id="Student" class="org.example.Student"></bean>

必须确保Student的构造函数时无参的

package org.example;
public class Student {
    
public Student() {
    this.name = name;
    this.sex = sex;
    this.age = age;
}
}
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
Student student = (Student)context.getBean("Student");
student.setName("张三");
System.out.println(student.getName());
基于静态工厂方式创建对象

在确定实现类中没有无参构造

给定静态工厂类来获取Student类

package org.example;
public class Student {
  public Student(String name,String sex , int age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
    public static Student getStudent(){
        return new Student("张三","男",20);
    }
}
<!--基于静态工厂方式实例化bean-->
    <bean id="Student" class="org.example.Student" factory-method="getStudent"/>

class属性指定的静态工厂类的全路径 ,factory-method属性即对应的方法,当前获取Student类在静态工厂下提供的getStudent方法可获取该对象

app实现

ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
Student student = (Student)context.getBean("Student");
student.setName("张三");
System.out.println(student.getName());
基于普通工厂方法实现Bean
package org.example;

public class Student {
    private String name;
    private String sex;
    private int age;

public Student getStudent(){
    return new Student();
}
}

配置Bean信息

<bean id="factoty" class="org.example.Student"/>
    <bean id="Student" factory-bean="factoty" factory-method="getStudent"/>
基于注解的方式装配Bean

比XML形式装配bean会更加简单

application配置文件引入context
<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    
    <!--开启注解扫描:在指定的包路径下所有的类名,属性等上的注解都会进行扫描-->
    <context:component-scan base-package="org.example"/>

    <!--开启注解扫描:扫描属性上的注解:不推荐使用-->
    <!--<context:annotation-config></context:annotation-config>-->
</beans>

注意:使用标签一定要引入context约束,该约束下才提供

在交给IOC容器管理的类上添加注解
package org.example.bean;
import org.springframework.stereotype.Component;

//@Component("Student") 与下面等同
@Component(value = "Student")
//等同于<bean id = "person" class = "org.example.bean.Student"></bean>
//默认给定的名称为类名首字母小写
public class Student {
    private String name;
    private String sex;
    private int age;
}

需要给定名字 不然默认时类名首字母小写

通过IOC获取对象
ApplicationContext context = new ClassPathXmlApplicationContext("application2.xml");
Student student = (Student)context.getBean("Student");
student.setName("zs");
System.out.println(student.getName());
四种注解类型标记Bean

使用注解在配置文件中指定扫描的包路径或者类路径后,交给IOC管理得类上添加注解即可

@Component 通用的标注的注解 连接前端

@Repository 对dao层实现类进行标注 连接数据库

@Service 对service层实现类进行标注

@Controller 对Controller层实现类进行标注 让组件扫描将这个类别识别为一个组件

@Component 是 Spring 提供的通用的组件注解

@Repository、@Service 、@Controller都是Component其衍生出来,功能都是一样的,可以互换,

主要是为了区分被注解的类处在不同的业务层

Spring中DI

DI-Dependency injection 依赖注入 组件之间的依赖关系由容器在运行时决定,IOC动态的为某个依赖注入到组件中。

那么他们之间 谁注入谁? IOC的作用是什么? 为什么要依赖?注入什么?

容器:IOC 组件(某个特定的类) 资源(组件依赖的内容)

谁依赖于谁:应用程序依赖于IOC容器

为什么需要依赖:应用程序需要IOC容器提供组件需要的外部资源

谁注入谁:IOC容器注入应用程序需要的资源,组件依赖的资源

注入什么:注入了某个对象所需要的外部资源

基于XML配置文件注入
基于有参构造函数注入依赖

给定User对象,定义有参构造

public class User1 {
    private Integer id;
    private String name;
    private String passwd;
    private String address;

    //    有参构造函数
    public User1(Integer id, String name, String passwd, String address) {
        this.id = id;
        this.name = name;
        this.passwd = passwd;
        this.address = address;
    }
    }

xml文件配置注入依赖

使用

注意value只支持基本类型作为string,自定义类型使用的是标签

<!--基于XML形式的依赖注入:有参构造-->
<bean id="user" class="org.example.service.User1">
    <!--注入属性-->
    <constructor-arg name="id" value="1"></constructor-arg>
    <constructor-arg name="name" value="张三"></constructor-arg>
    <constructor-arg name="address" value="address"></constructor-arg>
    <constructor-arg name="passwd" value="passwd"></constructor-arg>
    
    
</bean>

app实现

ApplicationContext  context =new ClassPathXmlApplicationContext("application.xml");
User1 user = (User1) context.getBean("user");
System.out.println(user);
基于set方法注入依赖
public class User2 {
    private Integer id;
    private String name;
    private String passwd;
    private String address;
    
    public User2() {
        this.id = id;
        this.name = name;
        this.passwd = passwd;
        this.address = address;
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPasswd() {
        return passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User1{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", passwd='" + passwd + '\'' +
                ", address='" + address + '\'' +
                '}';
    }

set方法注入依赖使用注解

xml配置

<!--基于XML形式的依赖注入-->
<bean id = "user2" class="org.example.service.User2">
    <property name="id" value="1"></property>
    <property name="passwd" value="passwd"></property>
    <property name="address" value="address"></property>
    <property name="name" value="张三"></property>
</bean>

app实现

ApplicationContext  context =new ClassPathXmlApplicationContext("application.xml");
        User2 user2 = (User2) context.getBean("user2");
        System.out.println(user2);

注入数据基本类型,自定义类型 Spring中还支持List,map,set,array等类型的数据注入

自定义类型注入依赖

前提得先注入自定义类型的依赖

<bean id = "student" class = "org.example.bean.Student"></bean>
<bean id="user" class="org.example.service.User1">
    <!--注入属性-->
    <constructor-arg name="id" value="1"></constructor-arg>
    <constructor-arg name="name" value="张三"></constructor-arg>
    <constructor-arg name="address" value="address"></constructor-arg>
    <constructor-arg name="passwd" value="passwd"></constructor-arg>
</bean>
注入集合类型
<!--注入List类型-->
<property name="list">
    <list>
        <value>12</value>
        <value>13</value>
    </list>
</property>
     <!--注入map类型数据-->
<property name="ms">
    <map>
      <entry key="a" value="1"/>
      <entry key="b" value="2"/>
    </map>
</property>
基于注解的注入

在对应需要的依赖上添加注解@Autowired

@Value注入普通的类型属性

@Resource 注入的是对象类型

@Autowired 注入对象类型

@Service(value = "UserLogin")
public class UserLogin {
    @Autowired
     private LoginText loginText;

     public void login(String name){
         User2 user2 = new User2(1,"zs","passwd","xa");
         loginText.printLogin(user2);
     }
}

@Service(value = "LoginText")
public class LoginText {
    public void printLogin(User2 user2){
        System.out.println(user2.getName()+"欢迎登陆");
    }
}
@Component(value = "user2")
public class User2 {

    private Integer id;
    private String name;
    private String passwd;
    private String address;
    //private Student student;

    private List<String> list;

    public User2(){

    }
    public User2(Integer id, String name, String passwd, String address) {
        this.id = id;
        this.name = name;
        this.passwd = passwd;
        this.address = address;
    }
    //以下是一些get和set方法
    }

可以看到user2中(idea) 有一个无参构造,再删除掉无参构造时,有参构造会报出错误,而且编译报错。

问题

--------------------------问题----------------------------------------------------------------------------

在注解形式中:Spring的反射要求这个bean必须要有一个无参构造器

可能在idea中不支持带参数的注解注入

通常在javaBean中,一般参数在四个以上的,不推荐使用带参数的构造函数赋值,多使用get/set方法。

------------------------------------------------------------------------------------------------------------

@Resource和@Autowired的区别?

关系:

  1. @Resource和@Autowired都是用来做bean的注入时使用
  2. @Resource和@Autowired有时可以互相替换使用,当都作为bean注入使用时,在接口仅有一个实现类时,两个注解的修饰效果相同,可以相互替换

不同点:

  1. @Resource是Java自己的注解,@Resource有两个属性较为重要 name,type,spring使用name解析为根据bean中的名称定位,使用type时解析为根据类型定位,如果没有给定属性值,Spring的反射机制通过byName来自动注入属性

  2. @Autowired是spring提供的注解,@Autowired在spring2.5后引入的只能根据type进行注入,不用name,如果涉及到type无法识别注入对象时(比如,有多个相同类型的类时),只使用Autowired是无法注入的,需要借助其他注解才能完成注入,比如@Primary @Qualifler,通过它指定哪个是真正需要注入的。@Autowired只有一个属性required,默认值为true,为true时,找不到就抛异常,为false时,找不到就赋值为null。

依赖解析过程

在spring中的依赖解析过程:

  1. ApplicationContex通过配置的元数据来创建和初始化,这些元数据描述了所有的bean,元数据的信息可以通过注解,xml或者Java代码来描述。
  2. 对于每一个bean,他的依赖属性,构造方法或者是静态工厂方法等形式来表达,bean被创建好之后这些以来会提供给他。
  3. 每一个属性或构造方法都要被设置实际定义,或者是对容器的另一个bean(自定义类型)的引用。
  4. 每个属性或者构造方法上的值的实际定义都会被转化为当前实例bean的实际的值。

在容器创建的过程中,spring容器会验证每一个bean的配置,在实际创建bean之前,bean的属性不会被设置,单例和被设置为首先加载的bean会在容器初始化后就创建出来,其他的bean只会在需要的时候才会创建,创建bean过程可能会引起一系列的bean被创建,

循环依赖

A -->B A依赖B

B -->A 而B又依赖A

解决:这些类可以通过set注入,避免使用构造方法注入

A B

构造函数构造A ,依赖B 创建顺序:B-A

Set方法创建A, 注入B 创建顺序:A-B

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值