Spring - IOC

achong
2022-05-15 / 0 评论 / 49 阅读 / 正在检测是否收录...

[TOC]

一、IOC

控制反转IOC就是对象创建的由谁来控制。

  • 正转:由程序员进行对象的创建和依赖注入称之为正传。就是程序员说了算。
Student.stu = new Student( );        ===>程序员创建对象

stu.setName("张三");        ===>程序员进行赋值

stu.setAge(18);    
  • 反转:由Spring容器创建对象和依赖注入称为反转,将控制权从程序员手上夺走,由Spring管理,称之为反转。
<bean id="stu" class="com.achong.entity.Student">        ===>Spring容器负责对象的创建

​    <property name="name" value="张三">                                        ===>Spring容器依赖注入值,也就是对对象赋值

​    <property name="age" value="20">

</bean>

二、Bean管理

Bean管理是指两个操作:Spring创建对象 和 Spring给对象的属性注入值。

Bean管理有两种实现方式:基于XML配置文件 和 基于注解 。

三、IOC接口

  1. IOC思想基于IOC容器完成,IOC容器底层就是对象工厂。
  2. Spring提供IOC容器实现的两种方式:BeanFactory和ApplicationContext

    1. BeanFactory

    IOC容器的基本实现,是Spring内部使用的接口,一般不提供开发人员使用。

    1. ApplicationContext

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

    1. 两者的区别是:BeanFactory在加载配置文件的时候不会创建对象,在获取对象的时候采取创建对象;而ApplicationContext会在配置文件加载的时候就把对象创建好。

四、 基于XML配置文件的Bean管理

4.1.两种方式创建对象

方式一:创建对象并注入值

  • Bean标签是创建对象

    • id是对象名称,名称唯一 ;class是对象的完全包名。
  • propertory标签是为对象的属性注入值。若不需要注入则该标签不用写。

    • name是属性名,value是属性值。

注意:创建对象是调用无参构造方法,注入值是使用set方法。所以必须保证对象类里有这两种方法。

<!--创建学生对象,在容器启动的时候-->
    <bean id="stu" class="com.achong.entity.Student">
        <property name="name" value="张三"></property>
        <property name="age" value="18"></property>
    </bean>

取出对象

​ ClassPathXmlApplicationContext( )方法读取xml配置文件。

​ getBean( )方法取出创建好的对象。参数名为xml里对应Bean标签的id。

    @Test
    public void TestSpringStudent(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        Student stu = (Student) ac.getBean("stu");
        System.out.println(stu );
    }

方式二:创建对象并注入值

此方式调用的是带参的构造方法创建对象。

  1. 使用 构造方法 的 参数名称 注入值。

        <bean id="school" class="com.achong.entity.School">
            <constructor-arg name="name" value="广东工程职业技术学院"></constructor-arg>
            <constructor-arg name="address" value="广东省清远市清城区"></constructor-arg>
        </bean>
  2. 使用 构造方法 的 下标 注入值。

        <bean id="stu" class="com.achong.entity3.Student">
            <constructor-arg index="0" value="2005"></constructor-arg>
            <constructor-arg index="1" value="achong"></constructor-arg>
            <constructor-arg index="2" value="18"></constructor-arg>
            <constructor-arg index="3" ref="school"></constructor-arg>
        </bean>
  3. 使用 构造方法 的 参数 的 顺序 注入值。

    <bean id="stu" class="com.achong.entity4.Student">
        <constructor-arg value="2005"></constructor-arg>
        <constructor-arg value="achong"></constructor-arg>
        <constructor-arg value="18"></constructor-arg>
        <constructor-arg ref="school"></constructor-arg>
    </bean>

4.2. 三种方式注入属性值

  • 简单类型注入

​ 简单类型指的是八大基本数据类型。使用value属性注入。上面的例子就是简单类型注入。

  • 引用类型注入

​ 引用类型指的是另一个对象。使用ref属性注入。

  • 集合类型注入

​ 集合类型注入指数组,List,Map。

例如User类里包含另一个Address类。这时候就需要引用类型注入。

代码实现 - 引用类型注入

<!--    创建学校对象-->
    <bean id="school" class="com.achong.entity2.School">
        <property name="name" value="广东工程职业技术学院"></property>
        <property name="address" value="广东省清远市清城区中宿路"></property>
        
    </bean>
<!--    创建学生对象-->
    <bean id="stu" class="com.achong.entity2.Student">
        <property name="name" value="achong"></property>
        <property name="age" value="20"></property>
        <property name="school" ref="school"></property>
    </bean>

代码实现 - 集合类型注入

<bean id="stu" class="com.achong.entity.Student">
<!--数组类型-->
    <property name="courses">
        <array>
            <value>java</value>
            <value>Mysql</value>
        </array>
    </property>
    <!--List类型注入-->
    <property name="maps">
        <list>
            <value>张三</value>
            <value>李四</value>
        </list>
    </property>
    <!--Map类型注入-->
    <property name="sets">
        <set>
            <value>Mysql</value>
            <value>Redis</value>
        </set>
    </property>
</bean>

添加util约束空间,把list提取出来。提取出来的集合独立,可供多个Bean使用。

    <util:list id="bookList">
        <value>java</value>
        <value>Mysql</value>
        <value>Servlet</value>
    </util:list>

    <bean id="stu" class="com.achong.entity5.Student">
        <property name="courseList" ref="bookList"></property>
    </bean>

内部Bean写法

    <bean id="stu" class="com.achong.entity2.Student">
        <property name="name" value="achong"></property>
        <property name="age" value="20"></property>
        <property name="school">
            <bean id="school" class="com.achong.entity2.School">
                <property name="name" value="广东工程职业技术学院"></property>
                <property name="address" value="广东省清远市"></property>
            </bean>
        </property>
    </bean>

4.3 属性值包含空值、特殊符号

空值

<property name="address">
    <null/>
</property>

特殊符号

​ 第二个中括号里面的内容为输入值。

<property name="address">
    <vlaue><[!CDATA[<<广东省>>]]></vlaue>
</property>

五、基于注解的Bean管理

也称为DI(Dependency Injection),它是IOC的具体实现的技术。

使用注解管理bean,可以省去在xml配置文件里写很多行代码,为xml减负。

5.1 创建对象的注解

  1. @Component("指定的名称"):可以创建任意对象。
  2. @Controller("指定的名称"):专门用来创建控制器的对象(Servlet),这种对象可以接收用户的请求,可以返回处理结果给客户端。
  3. @Service("指定的名称"):专门用来创建业务逻辑层的对象,负责向下访问数据访问层,处理完成后的结果返回给界面层。
  4. Repository("指定的名称"):专门用来创建数据访问层的对象,负责数据库中的增删改查所有操作。

四个注解的功能一模一样,可以混用,但是不建议,因为这本来就是用来区分三层结构的,value也可以不写,不写的话,创建的对象的名字按照驼峰命名法来命名。

  1. @Resource( ): 可以根据类型注入,根据名称注入。但是因为这个包是java拓展的而不是Spring提供的,所以不建议使用。

5.2 属性值注入的注解

  1. 值类型的注入

    1. @Value:用来给简单类型注入值。相当于构造函数赋值。
  2. 引用类型的注入

    1. @Autowired:使用类型注入值,从整个Bean工厂中搜索同源类型的对象进行注入。
    2. @Autowired、@Quelifier:使用名称注入值,从整个Bean工厂中搜索相同名称的对象进行注入。

5.3实现步骤

  1. 添加包扫描

只扫描指定包。指定包下面的,带有指定注解的类将被创建。

<context:component-scan base-package="com.achong.entity"></context:component-scan>
  1. 创建对象并注入

    @Component
    public class Student {
        @Value("2005")
        private int id;
        @Value("achong")
        private String name;
        @Value("18")
        private int age;
        
        @Autowired
        private School school; 
        }
  1. 添加测试类测试

    @Test
    public void Test01(){
     ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
     Student stu = (Student) ac.getBean("student");
     System.out.println(stu);
    }

注意:在有父子类的情况下,使用按类型注入,就意味着有多个可注入的对象,此时按照名称进行二次筛选,选中与被注入对象相同名称的对象进行注入。

所以,如果有父子类,建议使用按名称注入。

5.4 细节

批量包扫描, 逗号隔开

<context:component-scan base-package="com.achong.entity , com.achong.entity2 , com.achong.entity3"></context:component-scan>

自定义包扫描规则

<!--
    use-default-filters 表示不使用默认扫描规则
    include-filter 设置扫描哪些内容,这里表示 只扫描Controller这个注解
-->
    <context:component-scan base-package="com.achong" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
    <!--

        exclude-filter 设置哪些内容不扫描,这里表示Controller这个注解不会被扫描
    -->
    <context:component-scan base-package="com.achong">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

5.4 配置类替代xml

上面的方法需要使用到xml配置文件。但是,使用配置类可以替代配置文件。

步骤:

  1. ​ 创建一个空白类,添加相应注解

    @Configuration      //标记为配置类,替代xml文件
    @ComponentScan(basePackages = {"com.achong.entity4"})   //扫描路径
    public class SpringConfig {
    
    }
  2. 添加测试方法测试。

注意:原本的

new AnnotationConfigApplicationContext(SpringConfig.class)

​ 应改成

new AnnotationConfigApplicationContext(SpringConfig.class);

    @Test
    public void Test04(){
        ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
        Student student = (Student) ac.getBean("student");
        System.out.println(student);
    }
0

评论 (0)

取消
粤ICP备18061175号-3