Spring中的IOC(控制反转)

一、IOC的理论推导?

我自己的理解:IOC(控制反转):由控制反转两部分组成;

控制:就是控制权,

反转:将控制权从一个人的手中,转到另一个人手中。

以前一个接口,有多个实现,用户想要访问不同是业务,需要程序员手动调换接口,

现在,通过使用set方法注入实现类的方式,让用户自己管理和访问。

 这里就相当于以前用户想要使用业务,业务的控制权在程序员手中,程序员实现了什么接口,用户才能使用什么业务;现在就是,用户自己手中有接口实现类,用户想要使用什么业务就直接注入对应的接口实现类,然后,程序去帮用户创建对应的接口实现类的对象

  • 之前,程序是主动创建对象,控制权在程序员手中,

  • 使用set注入之后,程序员不在具有主动性,而变成了被动的接收对象!

这样就将创建对象的控制权从程序员控制转变成用户自己控制。

二、IOC的本质

控制反转IOC(Inversion of Control)是一种设计思想,DI(依赖注入)是一种实现IOC的一种方法,也有人认为DI只是IOC的另一种说法,没有IOC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序员自己控制,控制反转后,将对象的创建转移给了第三方,个人认为所谓的控制反转就是,获取依赖对象的方式反转了。

这种思想,本质上解决了问题,我们程序员不用再去管理对象的创建了。系统的耦合性大大降低了,可以更加专注的在业务的实现上。

三、为什么学习Spring的IOC?

现在我们知道了,以前都是程序员在代码中将所需的对象直接new出来,现在通过IOC思想将创建对象这个过程交给了Spring容器来帮我们创建我们自己需要的业务对象。

而我们需要学习的就是Spring如何去帮我们创建的对象。IOC如何实现解耦的过程。

四、Spring中的IOC是如何实现的?

控制反转是一种通过描述(XMl或注解)并通过第三方产生或获取特定对象到的方式,在Spring中实现控制反转的是IOC容器,其实现方法是依赖注入(Dependency Injection ,DI) 。

依赖注入三种方式:构造器注入,set注入,拓展方式注入

 4.1 先学习如何通过xml创建对象

1.下标赋值

    //第一种:用下标赋值
	<bean id="user" class="com.lx.pojo.User">
        <constructor-arg index="0" value="java"/>
    </bean>
2.通过类型创建
    //第二种方式:通过类型创建,不建议使用
	<bean id="user" class="com.lx.pojo.User">
        <constructor-arg type="java.lang.String" value="java"/>
    </bean>
3.通过参数名
    //第三种方式:直接通过参数名设置
    <bean id="user" class="com.lx.pojo.User">
        <constructor-arg name="name" value="狂神说java"/>
    </bean>

总结:在配置文件加载的时候,容器中管理的对象已经初始化了!

4.2 通过xml获取指定对象的方式

 采用XML方式配置Bean的时候,Bean的定义信息和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。

代码实现:

1.pojo实体类

public class Hello {
    private String str;

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }

    @Override
    public String toString() {
        return "Hello{" +
                "str='" + str + '\'' +
                '}';
    }
}

配置类: beans.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"
       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">
       <!--  使用Spring来创建对象,在Spring这些称为Bean
        类型    变量名 = new 类型();
        Hello   hello=new Hello()
        bean=对象           相当于 new Hello();
        id = 变量名
        class :pojo的全路径
        class = new 的对象;
        property  相当于给对象的属性设置一个值。
        name:起别名,可以取多个别名,只需要用分隔符把他分开(空格,‘,’,‘;’等)
        scope:作用域(单例模式,原型模式等)
        -->
    <bean id="hello" class="com.lx.pojo.Hello" name="hello2 h2,s" scope="singleton">
        <property name="str" value="Spring"/>
    </bean>
     <!--起别名,如果添加了别名,我们也可以使用别名来获取对象-->
    <alias name="hello" alias="hello2"/>


</beans>

测试类:通过bean获取对象

    public static void main(String[] args) {
        //获取Spring的上下文对象
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //我们的对象都在Spring中管理了,我们要使用,直接去里面取出来使用就可以了!!!
        Hello hello = (Hello) context.getBean("hello");
        System.out.println(hello.toString());

    }

4.3 在学IOC容器的实现方法:依赖注入

依赖注入的三种方式:构造器注入,set注入,拓展方式注入

构造器注入:就是通过new 构造器()去创建。

Set方式注入【重点】

  • 依赖注入:set注入!

    • 依赖:bean对象的创建依赖于容器!

    • 注入:bean对象中的属性,由容器来注入!

代码实现:

1.pojo实体类

public class Address {
    private String address;

    public String getAddress() {
        return address;
    }

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

2.真实测试对象

public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobby;
    private Map<String,String> card;
    private Set<String> games;
    private String wife;
    private Properties info;
}

3.配置文件:beans.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"
       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">
      <bean id="student" class="com.lx.pojo.Student">
<!--          第一步:普通值-->
          <property name="name" value="测试"/>
      </bean>


</beans>

4.测试类

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Student student = (Student) context.getBean("student");
        System.out.println(student.getName());
    }
}

上面的测试只是注入了Student的其中name属性,还有其他属性需要注入;

5.完善注入信息:注入的属性对应的是上面的Student实体类

     <bean id="address" class="com.lx.pojo.Address">
         <property name="address" value="西安"/>
     </bean>

      <bean id="student" class="com.lx.pojo.Student">
<!--          第一步:普通值-->
          <property name="name" value="测试"/>
<!--          注入Bean类型-->
          <property name="address" ref="address"/>
<!--          注入数组类型-->
          <property name="books">
              <array>
                  <value>西游记</value>
                  <value>水浒传</value>
                  <value>红楼梦</value>
                  <value>三国演义</value>
              </array>
          </property>
<!--          List注入-->
          <property name="hobby">
              <list>
                  <value>打篮球</value>
                  <value>游泳</value>
              </list>
          </property>
<!--          Map注入-->
          <property name="card">
              <map>
                  <entry key="身份证" value="87879854458756985"/>
                  <entry key="银行卡" value="648755495654565548"/>
              </map>
          </property>
<!--          Set注入-->
          <property name="games">
              <set>
                  <value>LOL</value>
                  <value>QQ飞车</value>
              </set>
          </property>
<!--          String的空指针注入-->
          <property name="wife">
              <null/>
          </property>
<!--          properties-->
          <property name="info">
              <props>
                  <prop key="driver">79</prop>
                  <prop key="url">456</prop>
                  <prop key="username">123</prop>
                  <prop key="password">4615</prop>
              </props>
          </property>
      </bean>

以上的是set最原始的注入方式,我们需要了解第三方提供的set注入方式:c命名空间和p命名空间

他们都只是在xml配置文件注入属性对象时使用:

c命名空间:

<?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:c="http://www.springframework.org/schema/c"
       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">

<!--         使用p命名空间注入,可以直接注入属性的值,property-->
       <bean id="user" class="com.lx.pojo.User" p:name="测试p命名空间" p:age="18"/>

<!--       使用c命名空间,前条件:实体类有相应的有参构造器,通过构造器注入:Constructor-->
    <bean id="user2" class="com.lx.pojo.User" c:name="c命名空间测试" c:age="18"/>
</beans>

 4.4 自动装配

自己的理解:现在我们创建一个实体类,需要在xml配置文件中去注入相关属性值,现在出现了一种情景:有三个实体类,有两个实体类(cat,dog)作为另外一个实体类(people)中的属性。这三个实体类都在xml配置文件中创建一个<bean>,但是没有注入属性,但是依然想使用people这个实体类去使用另外两个实体类中的方法,该怎么办?

代码重现情景模式:

1.猫  的pojo实体类 

2.狗 的pojo实体类

3.人 的pojo实体类

4.配置文件:

<?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:context="http://www.springframework.org/schema/context"
       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/context
						http://www.springframework.org/schema/context/spring-context.xsd
 					    http://www.springframework.org/schema/util
						http://www.springframework.org/schema/util/spring-util.xsd">


    <bean id="dog" class="com.lx.pojo.Dog"/>
    <bean id="cat" class="com.lx.pojo.Cat"/>
    <!--autowire="byType"  :手动注解注入-->
    <bean id="people" class="com.lx.pojo.People"/>

 这个时候就需要用到Bean的自动注入:让Spring容器帮我们去注入属性。

有个前提:你需要让Spring帮你注入属性,前提一定要将这个属性以bean的形式注册到配置文件中,否则会注入失败。

因此我们就要学习bean的自动装配的两种方式:通过xml文件配置和通过注解配置

xml文件配置:又分两种:byName和byType

1.byName进行自动装配;

<?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">
    <bean id="dog" class="com.lx.pojo.Dog"/>
    <bean id="cat" class="com.lx.pojo.Cat"/>

    <bean id="people" class="com.lx.pojo.People" autowire="byName"/>

</beans>

2.byType进行自动装配。

<?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">
    <bean id="dog" class="com.lx.pojo.Dog"/>
    <bean id="cat" class="com.lx.pojo.Cat"/>

    <bean id="people" class="com.lx.pojo.People" autowire="byType"/>

</beans>

小结:

  • byName的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致。

  • byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的bean id

  • byType的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致。

注解配置

jdk 1.5支持注解,Spring2.5就支持注解了!

要使用注解须知:

1.导入约束:context约束

2.配置注解的支持:<context:annotation-config/>

3.配合@Autowired进行使用

使用Autowired 我们可以不用编写Set方法了,前提是你这个自动装配的属性在IOC(spring)容器中存在,且符合名字byName!

代码理解:

1.首先在你想要使用注解自动配置的属性或者set方式上直接添加@Autowired注解就行

public class People {
    private String name;
    @Autowired
    private Dog dog;
    @Autowired
    private Cat cat;

    public People(@NonNull String name) {
        this.name = name;
    }

    public People() {
    }

    public People(String name, Dog dog, Cat cat) {
        this.name = name;
        this.dog = dog;
        this.cat = cat;
    }
}

2.在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"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       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/context
						http://www.springframework.org/schema/context/spring-context.xsd
 					    http://www.springframework.org/schema/util
						http://www.springframework.org/schema/util/spring-util.xsd">

    <!--    开启注解-->
    <context:annotation-config/>

    <bean id="dog" class="com.lx.pojo.Dog"/>
    <bean id="cat" class="com.lx.pojo.Cat"/>
    <!--autowire="byType"  :手动注解注入-->
    <bean id="people" class="com.lx.pojo.People"/>
</beans>

扩展:

 @NonNull    字段标记了这个注解,说明这个字段可以为null,

//如果显示定义了Autowired的required属性为false,说明这个对象可以为null,否则不许为空
@Autowired(required = false)
private Dog dog;

如果@Autowired自动装配环境比较复杂,自动装配无法通过一个注解【@Autowired】完成时,我们可以使用@Qualifier搭配使用。

指定唯一的bean对象注入。

@Autowired
@Qualifier(value = "dog222")

@Resoure 注解和@Autowired效果一致

使用他时,如果bean的id是对应且唯一的,可以有多个bean,或者id不对应,但是后面的class是唯一的也可以使用。

public class People {
    private String name;
    @Resource(name = "dog222")
    private Dog dog;
    @Resource
    private Cat cat;
}

小结:

@Resoure@Autowired的区别?

1.@Resoure是java的,@Autowired是来自spring的

2.java的注解,属性较多,type无法分辨时可以用name分辨;

spring的注解,一个属性,type无法分辨时需要借助@Qualifier注解才能使用 使用@Autowired方式最好使用构造函数的方式注入。

3.都是用来自动转配的,都可以放在属性字段上

4.@Autowired 通过byType的方式实现的,而且必须要求这个对象存在!【常用】

@Resoure默认通过byName的方式实现,如果找不到名字,则通过Type实现,如果两个都找不到的情况下,就报错!【常用】

5.执行顺序不同:@Autowired自动装配通过类型,名字

如果Autowired不能唯一的自动装配,则需要通过@Qualifier(value=“ ”)

@Resoure:自动装配通过名字,类型

五、使用注解开发

上面全都需要自己将实体类对应的<bean>一个一个的手动注册到xml配置文件中,现在只需要在实体类前添加一个注解@Component(组件),就相当于在xml配置文件中进行了<bean>注册。大大简化了开发过程。

使用注解开发的前提

在Spring4之后,要使用注解开发,必须要保证aop的包导入了

 

使用注解开发步骤:

1.使用注解需要导入context约束,添加注解的支持和你注解使用在那个包下,开启包扫描使注解生效完成,<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"
       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">
    <!--  1.  开启注解-->
    <context:annotation-config/>
    <!--  2.  指定要扫描的包,这个包下的注解就会生效-->
    <context:component-scan base-package="com.lx.pojo"/>
    
</beans>

 2.在实体类中添加注解,将实体类交给Spring去管理

//等价于    <bean id="user" class="com.lx.pojo.User"/>
//@Component  组件
@Component
public class User {
   //相当于        <property name="name" value="lx"/>
   @Value("lx")
    public String name ;
    
    public void setName(String name) {
        this.name = name;
    }
}

测试使用:

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        User user = context.getBean("user", User.class);
        System.out.println(user.name);
    }

3.衍生的注解

@Component有几个衍生注解。我们在web开发中,会按照mvc三层架构分层!

  • dao 【@Repository】

  • service 【@Service】

  • controller 【@Controller】

这四个注解功能都是一样的,都是代表某个注解注册到Spring中,装配bean。

小结

xml与注解:

  • xml更加万能,适用于任何场合!维护简单方便

  • 注解 不是自己类使用不了,维护相对复杂!

xml与注解最佳实践:

  • xml用来管理bean

  • 注解只负责完成属性的注入

  • 我们在使用的过程中,只需要注意一个问题:必须让注解生效,就需要开启注解的支持


第一次正式发表博客,如果各位网友发现了有什么问题,可以在评论区进行留言讨论,相互学习。

本博客是我通过观看哔哩哔哩up主的视频进行学习的:如有不懂,可通过链接进行学习:1、Spring简介_哔哩哔哩_bilibili

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值