【Spring】二、IoC(上)(xml配置)

IoC(上)(xml配置)

Spring通过IoC容器来进行管理、所有的JAVA对象的实例化和初始化,控制对象之间的依赖关系,通过IoC进行管理的对象叫做Java Bean,其在本质上与自己new出来的对象没有区别。

IoC是一种思想,不是一种技术,其将创建对象和维护对象之间关系的权利交出去,降低了耦合度,提高了扩展性。

IoC中的抽象类 BeanDefinitionReader 所实例化的方法,会通过Bean的信息通过BeanFactory+反射的方式对java bean进行实例化,再初始化,最终得到实例对象(使用contex.getBean()可以获取对象)。

依赖注入

DI(依赖注入)实现了控制反转的思想

依赖注入是指在spring创建对象的过程中,将对象依赖属性通过配置注入。

依赖注入常使用set注入或构造注入的方式进行。

IoC容器使用BeanFactory进行实现,但该接口不对开发人员开放,其子接口ApplicationContext面相spring的使用者。

Bean管理的两种方式

基于xml配置文件进行Bean管理

将之前在子模块的POM.xml文件中的以来配置修改到父工程的POM.xml文件中。

在Java中创建一个User类:

package com.qinghe.spring6.iocxml;

public class User {
    private String name;
    private Integer age;

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

在Bean.xml中创建一个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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="user" class="com.qinghe.spring6.iocxml.User"></bean>
</beans>

Bean的获取

创建一个ApplicationContext对象,根据该ApplicationContext对象获取需要的Bean

  • 根据bean.xml中的id进行获取
  • 根据类型进行获取
  • 根据id和类型获取
        //创建一个ApplicationContext对象,用来获取Bean
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");

        //1 利用context对象获取Bean对象(根据id)
        User user1 = (User)context.getBean("user");
        System.out.println("根据id获取Bean:" + user1);

        //2 利用类型获取Bean对象
        User user2 = context.getBean(User.class);
        System.out.println("根据类型获取Bean:" + user2);

        //3 利用id和类型获取Bean对象
        User user3 = context.getBean("user", User.class);
        System.out.println("根据id和类型获取Bean:" + user3);

若UserDao.class获取到的是一个接口,则会自动获取它的实现类(前提是实现类在bean.xml中进行过配置),但若在bean.xml中配置过多个UserDao的实现类,则无法自动获取(不知道要的是哪个)

        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        
        //如果通过类型获取的是一个接口,则获取到的自动是他的实现类userDaoImpl
        UserDao userDao = context.getBean(UserDao.class);
        System.out.println(userDao);
        userDao.run();
    }

依赖注入

基本类型依赖注入

依赖注入是指向类中的属性注入数值,有利用set进行注入与利用构造器进行注入等方式

  • 基于set方法进行依赖注入

    在bean中对属性要生成set方法,在配置文件中进行相应的配置,在测试文件中使用IoC进行创建对象时就会由spring自动进行依赖注入,得到一个有属性值的对象。

    bean-di.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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <!--    进行类的配置与依赖的注入-->
        <bean id="book" class="com.qinghe.spring6.iocxml.di.Book">
    <!--        property标签调用set方法注入具体的依赖-->
            <property name="bname" value="芜湖起飞"></property>
            <property name="author" value="大司马"></property>
        </bean>
    </beans>
    
  • 基于构造器进行注入

    在配置文件中进行相应的配置、标签为constructor-arg。

    <!--    基于构造器进行依赖注入-->
        <bean id="bookCon" class="com.qinghe.spring6.iocxml.di.Book">
    <!--        构造器注入的方式-->
            <constructor-arg name="bname" value="红楼梦"></constructor-arg>
            <constructor-arg name="author" value="曹雪芹"></constructor-arg>
        </bean>
    

若要赋null,则应该在property标签下使用null标签

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

特别的,若要在属性中赋"<“或”>"则应该使用xml实体(转义)使用&lt;表示<, 使用&gt;表示>。(别忘记分号)

<property name="others" value="&lt;&gt;"></property>

更特别的,xml支持使用CDATA区来对符号(>,<)进行解析,解析的结果会完全成立为CDATA区内的结果,不会被误识别。

    <property name="others">
        <value>[!CDATA[a > b]]</value>
    </property>

对象类型依赖注入

若需要注入每个对象类型的数据,则要提前在bean中声明好,再进行注入

  • 引入外部bean的方式
    <bean id="dept" class="com.qinghe.spring6.iocxml.ditest.Dept">
        <property name="dname" value="安保部"></property>
    </bean>
    <bean id="emp" class="com.qinghe.spring6.iocxml.ditest.Emp">
<!--        ref属性可以将一个已经在xml中配置完成的类所创建的对象作为参数传递给另一个类-->
        <property name="dept" ref="dept"></property>
        <property name="ename" value="马冬梅"></property>
        <property name="age" value="18"></property>
    </bean>

这种通过ref属性引入另一个Bean标签的方式来注入对象的方式叫做通过引入外部bean的方式进行对象类型的依赖注入。

  • 内部Bean方式进行依赖注入
    <bean id="emp2" class="com.qinghe.spring6.iocxml.ditest.Emp">
        <property name="dept">
            <bean id="dept2" class="com.qinghe.spring6.iocxml.ditest.Dept">
                <property name="dname" value="财务部"></property>
            </bean>
        </property>
        <property name="ename" value="mary"></property>
        <property name="age" value="3"></property>
    </bean>

在一个Bean中创建另一个Bean的方式叫做内部Bean的方式进行依赖注入

  • 级联赋值

    级联赋值可以在xml文件中实现对已有属性的赋值:

        <bean id="dept" class="com.qinghe.spring6.iocxml.ditest.Dept"></bean>
        <bean id="emp" class="com.qinghe.spring6.iocxml.ditest.Emp">
          <property name="ename" value="tom"></property>
            <property name="age" value="999"></property>
            <property name="dept" ref="dept"></property>
            <!-- 使用级联赋值进行部门信息的更新操作 -->
            <property name="dept.dname" value="使用级联赋值更新了部门信息"></property>
        </bean>
    

数组类型依赖注入

若bean对象中存在一个数组,要通过如下配置方式对数组进行依赖注入

    <bean id="dept" class="com.qinghe.spring6.iocxml.ditest.Dept">
        <property name="dname" value="数组测试部"></property>
    </bean>
    <bean id="emp" class="com.qinghe.spring6.iocxml.ditest.Emp">
        <property name="ename" value="Huying"></property>
        <property name="age" value="18"></property>
        <property name="dept" ref="dept"></property>
        <!-- 对数组类型的成员变量进行赋值 -->
        <property name="loves">
            <array>
                <value>吃饭</value>
                <value>睡觉</value>
                <value>赖床</value>
            </array>
        </property>
    </bean>

集合类型依赖注入

  • List型依赖注入方式:
<!--    注入emp类型对象-->
    <bean id="emp1" class="com.qinghe.spring6.iocxml.ditest.Emp">
        <property name="ename" value="huying"></property>
        <property name="age" value="18"></property>
    </bean>
<!--    再引入一个emp类型的对象-->
    <bean id="emp2" class="com.qinghe.spring6.iocxml.ditest.Emp">
        <property name="ename" value="yinghu"></property>
        <property name="age" value="81"></property>
    </bean>

<!--    注入一个dept类型的对象-->
    <bean id="dept" class="com.qinghe.spring6.iocxml.ditest.Dept">
<!--        注入普通属性-->
        <property name="dname" value="List部"></property>
<!--        注入list类型的属性(若list保存的是对象,则要用ref标签,若保存的是普通的数据类型,则可以使用value标签)-->
        <property name="empList">
            <list>
                <ref bean="emp1"></ref>
                <ref bean="emp2"></ref>
            </list>
        </property>
    </bean>
  • Map型依赖注入的方式
   <bean id="student" class="com.qinghe.spring6.iocxml.dimap.Student">
        <property name="sid" value="1200"></property>
        <property name="sname" value="张三"></property>
<!--        在student对象之中注入map,-->
        <property name="teacherMap">
            <map>
<!--                每一个键值对使用entry标签注入-->
                <entry>
                    <key>
                        <value>000001</value>
                    </key>
<!--                    对象类型的属性要用ref标签注入-->
                    <ref bean="teacher1"></ref>
                </entry>
                <entry>
                    <key>
                        <value>000002</value>
                    </key>
                    <ref bean="teacher2"></ref>
                </entry>
            </map>
        </property>
    </bean>

<!--    注入两个teacher类型的普通对象用于演示-->
    <bean id="teacher1" class="com.qinghe.spring6.iocxml.dimap.Teacher">
        <property name="teacherId" value="110"></property>
        <property name="teacherName" value="西门"></property>
    </bean>

    <bean id="teacher2" class="com.qinghe.spring6.iocxml.dimap.Teacher">
        <property name="teacherId" value="111"></property>
        <property name="teacherName" value="上官"></property>
    </bean>
  • 引入bean类型的方式进行list、map的注入

    在使用bean类型引入的方式进行注入时,需要提前对命名空间进行配置:

    在beans标签的属性中添加xmlns:util="http://www.springframework.org/schema/util"

    并在xsi:schemaLocation中添加两行网址:

                       http://www.springframework.org/schema/util
                       http://www.springframework.org/schema/util/spring-util.xsd
    

最终效果(bean-diref.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: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">

<!--    util:list标签在外引入list-->
    <util:list id="lessonList">
        <ref bean="lesson1"></ref>
        <ref bean="lesson2"></ref>
    </util:list>

<!--    util:map标签在外注入map-->
    <util:map id="teacherMap">
<!--        注入120021 - teacher1的键值对-->
        <entry>
            <key>
                <value>120021</value>
            </key>
            <ref bean="teacher1"></ref>
        </entry>
        <entry>
            <key>
                <value>120012</value>
            </key>
            <ref bean="teacher2"></ref>
        </entry>
    </util:map>

<!--    创建一个student对象-->
    <bean id="student" class="com.qinghe.spring6.iocxml.dimap.Student">
        <property name="sid" value="10086"></property>
        <property name="sname" value="金毛"></property>
<!--        注入生成的list和map-->
        <property name="lessonList" ref="lessonList"></property>
        <property name="teacherMap" ref="teacherMap"></property>
    </bean>

<!--    创建两个teacher对象进行准备-->
    <bean id="teacher1" class="com.qinghe.spring6.iocxml.dimap.Teacher">
        <property name="teacherId" value="001"></property>
        <property name="teacherName" value="上官"></property>
    </bean>
    <bean id="teacher2" class="com.qinghe.spring6.iocxml.dimap.Teacher">
        <property name="teacherId" value="002"></property>
        <property name="teacherName" value="西门"></property>
    </bean>

<!--    创建两个Lesson对象进行准备-->
    <bean id="lesson1" class="com.qinghe.spring6.iocxml.dimap.Lesson">
        <property name="lesson" value="屠龙剑法"></property>
    </bean>
    <bean id="lesson2" class="com.qinghe.spring6.iocxml.dimap.Lesson">
        <property name="lesson" value="走为上计"></property>
    </bean>
</beans>

p命名空间注入

在beans的属性配置中添加一行:

xmlns:p="http://www.springframework.org/schema/p"

就引入了p命名空间,可以在bean的配置中快速进行属性以及数据的配置

    <bean id="studentp" class="com.qinghe.spring6.iocxml.dimap.Student"
          <!-- 使用p空间进行配置,-ref代表引入外部bean标签 -->
          p:sid="002" p:sname="Dasima" p:lessonList-ref="lessonList" p:teacherMap-ref="teacherMap">
    </bean>

引入外部属性文件

通常在开发过程中,手动进行配置xml文件是相当复杂且难以维护的,故添加引入外部属性文件的方式进行管理

  • 添加演示使用依赖:mysql、druid

        <dependencies>
    <!--        mysql数据库依赖-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.32</version>
            </dependency>
    
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.0.31</version>
            </dependency>
        </dependencies>
    
  • 配置jdbc.properties文件

jdbc.user=root
jdbc.password=123456
jdbc.url=jdbc:mysql://loaclhost:3306/spring?serverTimezone=UTC
jdbc.driver=com.mysql.cj.Driver
  • 配置命名空间:

添加这几样命名空间的配置

xmlns:context="http://www.springframework.org/schema/context"       

http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
  • 添加文件的引入以及属性的配置
<!--    引入外部属性文件,之后可以在属性添加中进行操作-->
    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>

<!--    进行依赖注入,使用${}符号可以动态表示-->
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${jdbc.url}"></property>
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <property name="username" value="${jdbc.user}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>

这样就配置好了数据库的信息,若要修改数据库信息则只需要修改jdbc.properties文件,不再需要进入.xml文件中进行配置

关于Bean

Bean的作用域

Spring中可以配置Bean的scope属性来配置Bean的作用域,singleton代表该对象在IoC容器中始终为单例,在IoC容器初始化时进行创建

prototype代表这个bean在IoC容器中有多个实例,在获取bean时才进行创建。

若是singleton则会在ApplicationContext对象创建时就创建了注入的对象(这体现在日志信息中)(scope默认为singleton)。

而proptotype会在.getBean()时才创建对象。

若是在WebApplicationContext环境下还有另外两种作用域

request指在一次请求中有效、session指在一个会话范围内有效

Bean的生命周期

  1. 调用无参构造器创建对象
  2. 为bean设置内部属性(调用set方法)
  3. bean后置处理器(初始化前)(调用spring文件中的某一个BeanPostProcess接口的一个实现类,该实现类的两个方法中的postProcessBeforeInitialization方法会在作为后置处理器先调用)
  4. bean对象初始化(会调用指定的初始化方法(该方法可以在bean标签中通过init-method属性设置))(该方法可以在类中设置)
  5. bean后置处理器(初始化后)(调用spring文件中的某一个BeanPostProcess接口的一个实现类,该实现类的两个方法中的postProcessAfterInitialization方法会在作为后置处理器后调用)
  6. bean对象创建完成、可以调用了
  7. bean对象销毁(会调用指定固定销毁方法,(该方法可以在bean标签中通过destroy-method属性设置))(该方法可以在类中设置)
  8. IoC容器关闭

ClassPathXmlApplicationContext中有.close()方法可以对对象进行销毁

注意,后置处理器中的方法也可以自己定义,要自己建立一个BeanPostProcessor接口的实现类并且重写两个后置处理器的方法,之后在xml文件夹中进行如下配置:

<bean id="起一个名字" class="实现类的全路径"></bean>

后置处理器的自定义:

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

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("5 bean后置处理器,初始化之后执行");
        System.out.println(beanName + "::" + bean);
        return bean;
    }
}

FactoryBean

FactoryBean是spring中的一个接口,实现了这个接口的类要实现两个方法:

    @Override
    public User getObject() throws Exception {
        return new User();
    }

    @Override
    public Class<?> getObjectType() {
        return User.class;
    }

在xml文件中正常配置这个java类。

其中特殊的是,FactoryBean创建的是getObject()方法中返回的对象,而不是本身类的对象。

xml自动装配

xml文件中的配置不需要自己编写,Bean标签下的autowire属性可以自动在配置文件中找到合适的bean并配置到自己需要的属性中。

autowire有 byType、byName两种方法。

byType会根据自身bean需要的类型在配置文件(IoC容器)中寻找合适的对象。

byName会根据其他bean的id与自己需要的属性的属性名(自己定义的那个名字)来寻找合适的对象并进行注入。

    <bean id="userController" class="com.qinghe.spring6.iocxml.auto.controller.UserController" autowire="byType">

    </bean>

    <bean id="userService" class="com.qinghe.spring6.iocxml.auto.service.UserServiceImpl" autowire="byType">

    </bean>

    <bean id="userDao" class="com.qinghe.spring6.iocxml.auto.dao.UserDaoImpl">

    </bean>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值