2、Spring-IOC的基本配置使用1、容器概述2、b

1、容器概述

  ApplicationContext是Spring IoC容器实现的代表,它负责实例化、配置和组装Bean。容器通过读取配置元数据获取有关实例化、配置和组装哪些对象的说明 。配置元数据可以使用XML、Java注解或Java代码来呈现。它允许你处理应用程序的对象与其他对象之间的互相依赖关系。

1.1 配置元数据(参考上一篇文章)

    a、xml配置文件,一撸到底

    b、xml和注解混用阶段

    c、完全抛弃xml,使用javaConfig的方式进行开发。

1.2 容器的实例化

    对象在Spring容器创建完成的时候就已经创建完成,不是需要用的时候才创建

1.3 容器的使用

    ApplicationContext是能够创建bean定义以及处理相互依赖关系的高级工厂接口,使用方法
T getBean(String name, Class requiredType)获取容器实例。 

// 创建spring上下文 加载所有的bean
ApplicationContext context = new ClassPathXmlApplicationContext("spring-ioc.xml");
// 获取bean
User user = context.getBean("user", User.class);
复制代码

2、bean的概述

2.1 命名bean

<bean class="com.tuling.entity.User" id="user" name="user2 user3,user4;user5"></bean>
<alias name="user" alias="user6"></alias>
复制代码

注意:user、user2、user3、user4、user5、user6是同一个对象

   @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-ioc.xml");
        User user = (User) context.getBean("user");
        User user2 = (User) context.getBean("user2");
        User user3 = (User) context.getBean("user3");
        User user4 = (User) context.getBean("user4");
        System.out.println(user);//com.zhl.entity.User@cb51256
        System.out.println(user2);//com.zhl.entity.User@cb51256
        System.out.println(user3);//com.zhl.entity.User@cb51256
        System.out.println(user4);//com.zhl.entity.User@cb51256
        User user6 = (User) context.getBean("user6");
        System.out.println(user6);//com.zhl.entity.User@cb51256
    }
复制代码

2.2 实例化 Bean

    2.2.1 使用构造器实例化(默认)

      该方法无法干预实例化过程

    2.2.2 使用静态工厂方法实例化

      a、配置文件    

<bean id="user" class="com.zhl.entity.User" factory-method="createUserInstance"></bean>
复制代码

      b、实体类中增加静态工厂方法

public class User {
    private Integer id;
    private String username;
    private String realname;
    
    public User() {
        System.out.println("2、创建了一个对象");
    }

    public static User createUserInstance(){
        System.out.println("1、先输出这一句");
        return new User();
    }
}
复制代码

2.2.3 使用实例工厂方法实例化

a、配置文件

<bean class="com.zhl.entity.User" id="user" factory‐bean="userFactory" factory‐method="createUserFactory" ></bean>
复制代码

b、实例工厂类

public class UserFactory{
    public User createUserFactory(){
        return new User();
    }
}
复制代码

3、依赖

3.1 依赖注入

    a、基于setter方法的依赖注入

  <!-- 基于setter方法的依赖注入
       1. 属性必须声明了set方法
       2. name是根据set方法的名字来的 比如方法名字是: setIdxx ‐》 name="idxx"
    -->
    <bean id="user" class="com.zhl.entity.User">
        <property name="id" value="1"></property>
        <property name="username" value="一右四分之一"></property>
        <property name="realname" value="还是一右四分之一"></property>
    </bean>
复制代码

    b、基于构造函数的依赖注入

  <!--基于构造函数的依赖注入
     1. 将会调用自定义构造函数来实例化对象,就不会调用默认的无参构造函数
     2. name是根据构造函数的参数名来的, 比如:User(String idxx) ‐> name="idxx"
     3. name属性可以省略 但是要注意参数的位置
     4. 如果非要把位置错开 可以使用 name 或者 index 或者 type
     5. index 是下标 从0开始
     6. type 在位置错开情况下只能在类型不一样的时候指定才有明显效果
     -->
    <bean id="user" class="com.zhl.entity.User">
        <constructor-arg name="id" value="1"></constructor-arg>
        <constructor-arg name="username" value="一右四分之一"></constructor-arg>
        <constructor-arg name="realname" value="也是一右四分之一"></constructor-arg>
    </bean>
复制代码
public class User {
    private Integer id;
    private String username;
    private String realname;

    public User() {
        System.out.println("创建了一个对象");
    }

    public User(Integer id,String username,String realname) {
        this.id = id;
        this.username = username;
        this.realname = realname;
    }
}
复制代码

3.2 依赖和配置的细节

    a、直接值(基本类型、String 等)

    b、对其他bean的引用

    c、内部bean

    d、集合

    e、null和空的字符串值

    f、使用P命名标签简化基于 setter 属性注入XML 的配置

    g、使用C命名空间,简化基于 构造函数的 xml

  <bean id="user" class="com.zhl.entity.User">
        <!--直接值(基本类型、String 等)-->
        <property name="id" value="1"></property>
        <!--设置null-->
        <property name="username">
            <null></null>
        </property>
        <property name="realname" value=""></property>
        <!--对其他bean的引用  引用外部Bean
        <property name="role" ref="role"></property>
        -->
        <!--使用内部bean 依赖注入其他bean-->
        <property name="role">
            <bean class="com.zhl.entity.Role">
                <property name="roleId" value="1"></property>
                <property name="roleName" value="管理员"></property>
            </bean>
        </property>

        <!--list 注入:
            如果泛型是基本数据类型<value>
            如果泛型是bean  <bean>-->
        <property name="hobbies">
            <list>
                <value>唱歌</value>
                <value>跳舞</value>
            </list>
        </property>
        <!--map 注入
            如果value是基本数据类型<entry key="1" value="Java"></entry>
            如果value是bean  value-ref-->
        <property name="course">
            <map>
                <entry key="1" value="Java"></entry>
                <entry key="2" value="数据库"></entry>
            </map>
        </property>
    </bean>
    <bean id="role" class="com.zhl.entity.Role"></bean>

    <!--使用p命名空间简化基于setter属性注入XML配置
        p:按Alt+Enter 自动加上命名空间
        设置基本数据类型   或者p:wife-ref 引用外部bean
        如果有集合类型 就不支持, 需要额外配置 <property>
    -->
    <bean id="user2" class="com.zhl.entity.User" p:id="1" p:username="一右四分之一" p:realname="一右四分之一" p:role-ref="role2">
        <property name="hobbies">
            <list>
                <value>唱歌</value>
                <value>跳舞</value>
            </list>
        </property>
    </bean>
    <!--使用c命名空间简化基于构造函数的XML 这种方式,类中必须自定义构造方法-->
    <bean id="role2" class="com.zhl.entity.Role" c:roleId="1" c:roleName="管理员"></bean>
复制代码

3.3 使用 depends-on 属性

  <!--使用depends‐on可以设置先加载的Bean 也就是控制bean的加载顺序-->
    <bean class="com.zhl.entity.User" id="user" depends-on="role"></bean>
    <bean id="role" class="com.zhl.entity.Role"></bean>
复制代码

3.4 懒加载 bean

  <!--使用lazy‐init设置懒加载
     默认为false: 在spring容器创建的时候加载(实例化)
     true: 在使用的时候(getBean)才会去加载(实例化)
    -->
    <bean id="user" class="com.zhl.entity.User" lazy-init="false">
        <property name="id" value="1"></property>
        <property name="username" value="一右四分之一"></property>
        <property name="realname" value="一右四分之一"></property>
    </bean>
复制代码

3.5 自动注入

    当一个对象中需要引用另外一个对象的时候,在之前的配置中我们都是通过 property标签来进行手动配置的,其实在spring中还提供了一个非常强大的功能就是自 动装配,可以按照我们指定的规则进行                   配置,配置的方式有以下几种:

    default/no:不自动装配

    byName:按照名字进行装配,以属性名作为id去容器中查找组件,进行赋 值,如果找不到则装配null;

    byType:按照类型进行装配,以属性的类型作为查找依据去容器中找到这个组件,如果有多个类型相同的bean对象,那么会报异常,如果找不到则装配null;

    constructor:按照构造器进行装配,先按照有参构造器参数的类型进行装配,没有就直接装配null;如果按照类型找到了多个,那么就使用参数名作为id继续匹 配,找到就装配,找不到就装配null;

          通过将autowire-candidate 属性设置为false,避免对bean定义进行自动装配;

          通过将其元素的primary属性设置为 true,将单个bean定义指定为主 要候选项。

  <!-- 自动注入
    byType 根据类型去自动匹配 当出现多个类型或者匹配到类型则会报错(spring会根据bean里面的所有对象属性的类型,只要它匹配到bean里面某一个类型跟属性类型吻合就会自动注入)
    byName 根据set方法的名字去自动匹配 (spring会根据bean里面的所有对象属性的set的名字,只要它匹配到bean里面某一个名字跟属性名字吻合就会自动注入)
    constructor 根据构造器去匹配
        优先会根据参数名字去匹配,假如参数名字没有匹配到,会根据参数类型去匹配
        会根据构造函数的参数进行完整的匹配注入: 如果构造函数的参数Person(Wife wife3,User user)  ioc容器里面必须要有同时有wife和user
        名字没有匹配到会根据类型匹配   类型假如出现多个会注入失败但是不会报错

        当根据类型匹配到多个 可以使用 1.设置某个bean为主要bean primary="true"
                                     2.设置不需要自动注入的bean autowire-candidate="false" 忽略自动注入
    -->
    <bean id="user" class="com.zhl.entity.User" autowire="byType">
        <property name="id" value="1"></property>
        <property name="username"  value="一右四分之一"></property>
        <property name="realname"  value="一右四分之一"></property>
    </bean>
    <!--autowire-candidate="false" 忽略自动注入
    primary="true" 设置该bean为主要Bean(自动注入的时候,注入的是配置了 primary="true" 的Bean)-->
    <bean class="com.zhl.entity.Role" id="role1" p:roleId="1" p:roleName="管理员" primary="true"></bean>
复制代码
public class IocTest {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-ioc.xml");
        User user = (User) context.getBean("user",User.class);
        System.out.println(user.toString());//User{id=1, username='一右四分之一', realname='一右四分之一', role=com.zhl.entity.Role@727803de}
    }
}
复制代码

4、Bean 的作用域

4.1、Singleton(单例)的作用域

4.2、Prototype(原型)的作用域

  <!--作用域scope
    singleton 默认:单例 只会在Ioc容器种创建一次
    prototype 多例(原型bean) 每次获取都会new一次新的bean
    -->
    <bean id="user" class="com.zhl.entity.User" scope="singleton">
        <property name="id" value="1"></property>
        <property name="username" value="一右四分之一"></property>
        <property name="realname" value="一右四分之一"></property>
    </bean>
复制代码

5、自定义Bean的特性

5.1、生命周期回调

    a、初始化方法回调

    b、销毁方法回调

    c、在非web应用中关闭Spring Ioc容器

/**
 *  生命周期回调
 *  1. 使用接口的方式实现:
 *      1.初始化回调   实现InitializingBean   重写afterPropertiesSet 初始化会自动调用的方法
 *      2.销毁回调     实现DisposableBean   重写destroy   销毁的时候会自动调用的方法 
 *    3.什么时候销毁?
 *     在spring容器关闭的时候,或者使用 ConfigurableApplicationContext.registerShutdownHook 优雅地关闭
 *  2. 基于配置的方式实现
 */
public class User implements InitializingBean, DisposableBean {
    private Integer id;
    private String username;
    private String realname;
    private Role role;
    private List<String> hobbies;
    private Map<Integer,String> course;;

    public User() {
        System.out.println("创建了一个对象");
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("实例化User");
    }
    @Override
    public void destroy() throws Exception {
        System.out.println("销毁User");
    }
}
复制代码
<bean class="com.zhl.entity.User" id="user" init-method="afterPropertiesSet" destroy-method="destroy"></bean>
复制代码

6、Bean定义的继承

   <!--bean的继承 一个bean继承另一个bean
    可以使用parent属性指定父类bean
    如果想让父类bean不能被实例化 abstract="true"-->
     <bean class="com.zhl.entity.User" id="user" abstract="true">
         <property name="id" value="1"></property>
         <property name="username"  value="一右四分之一"></property>
         <property name="realname"  value="一右四分之一"></property>
     </bean>
     <bean class="com.zhl.entity.User" id="user2" parent="user" >
        <property name="realname" value="一右四分之一2世"></property>
     </bean>
复制代码
public class IocTest {
    @Test
    public void test(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-ioc.xml");
        User user = (User) context.getBean("user2",User.class);
        System.out.println(user.toString());//User{id=1, username='一右四分之一', realname='一右四分之一2世', role=null}
    }
}
复制代码