【03-02】SpringIOC配置Bean对象

一、Spring Bean的配置

由 Spring IoC 容器管理的对象称为 Bean,Bean 根据 Spring 配置文件中的信息被创建。所谓配置Bean就是告诉Spring的IOC容器将要去管理的对象。

1、传统方式(XML文件)

采用XML文件的形式进行配置,spring-context.xml

1.1 基础类

Person类:

	public class Emp{
	    private Integer id;
	    private String ename;
	    private String email;
	    private Double salary;
	    private Dept dept;
	    //相关set方法、get方法、构造方法...
	  }
	  
	public class Dept {
	    private Integer did;
	    private String dname;
	    private List<Emp> empList;
	    private Map<Integer,String> maps;
	    private Emp emp1;//部门领导
	     //相关set方法、get方法、构造方法...
	  }
	  
    public class Student implements InitializingBean, DisposableBean {
	    private Integer sid;
	    private String sname;
	 	//相关set方法、get方法、构造方法...
	 	@Override
	    public void destroy() throws Exception {
	        System.out.println("正在执行DisposableBean接口的bean销毁方法.......");
	    }
	
	    @Override
	    public void afterPropertiesSet() throws Exception {
	        System.out.println("正在执行InitializingBean接口的bean初始化方法.......");
	    }
	
	    public void inits(){
	        System.out.println("正在执行本地的bean初始化方法.......");
	    }
	
	    public void destorys(){
	        System.out.println("正在执行本地的bean销毁方法.......");
	    }
    }

1.2 配置文件

<?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="emp" class="org.example.pojo.Emp">
        <description>描述bean的信息</description>
    </bean>
    <alias name="emp" alias="EMP"><!--设置别名--></alias>
    <import resource="spring-ioc.xml"><!--导入其他spring的xml配置文件--></import>
</beans>
  • 标签
    • bean
      • 创建一个bean对象并放置在IOC容器内,对应某个类的一个实例对象;
    • alias
      • 用来给某个bean起别名(可以设置多个别名,用逗号或者空格或者分号来分隔即可),name对应某个bean的id值;
    • import
      • 可以使用import来导入其他spring的xml配置文件;
    • description
      • 该标签用于来描述某个bean的信息,在bean标签的内部使用;
  • 属性
    • id
      • bean对象的唯一标识符(名称),不可重复,在IOC容器中必须是唯一的;
      • 若id没有指定,Spring会自动将类的全局限定类名作为bean的名字;
    • class
      • 被创建对象的类的包路径,Spring会通过反射机制创建该类的对象;
      • 要求该类中必须存在无参构造方法;

1.3 依赖注入

1.3.1 基于setter方法的依赖注入
 	<bean id="emp1" class="org.example.pojo.Emp" primary="true">
        <property name="id" value="100001"></property>
        <property name="ename" value="唐僧"></property>
        <property name="email" value="123456@163.com"></property>
        <property name="salary" value="10000"></property>
    </bean>
  • 注意name属性对应的是set方法的名字
  • 例如:setId ——> name=“id” ===> setXxx ——> name=“xxx”
1.3.2 基于构造器方法的依赖注入
  	<bean id="emp2" class="org.example.pojo.Emp" autowire-candidate="false">
        <constructor-arg name="id" value="100002"></constructor-arg>
        <constructor-arg name="ename" value="孙悟空"></constructor-arg>
        <constructor-arg name="email" value="23456@163.com"></constructor-arg>
        <constructor-arg name="salary" value="9999"></constructor-arg>
        <!--<constructor-arg index="0" value="100003"></constructor-arg>-->
    </bean>
  • 注意:
    • (1)可以基于name属性来映射构造函数的参数;
    • (2)也可以省略name属性,直接使用value属性设置值,但是,要注意参数的顺序必须按照构造函数的参数顺序设置;
    • (3)还可以使用index属性来设置参数的下标,从下标从0开始;
1.3.3 复杂数据类型的依赖注入
	<bean id="dept1" class="org.example.pojo.Dept">
        <property name="did" value="1"></property>
        <!--设置null-->
        <property name="dname"><null></null></property>
        <!--设置“”-->
        <!--<property name="dname" value=""></property>-->

        <!--引用外部bean-->
        <!--<property name="emp1" ref="emp1"></property>-->
        <!--引用内部bean-->
        <property name="emp1">
            <bean class="org.example.pojo.Emp">
                <property name="id" value="1111111"></property>
                <property name="ename" value="如来佛祖"></property>
                <property name="email" value="11111111@163.com"></property>
                <property name="salary" value="10000000"></property>
            </bean>
        </property>
        <!--List注入-->
        <property name="empList">
            <!--注意:
                    (1)如果泛型是基本数据类型:则使用<value>员工1</value>
                    (2)如果泛型是对象:则使用<bean></bean>引用内部bean或者<ref></ref>去引用外部bean-->
            <list>
                <ref bean="emp1"></ref>
                <ref bean="emp2"></ref>
            </list>
        </property>
        <!--Map注入-->
        <property name="maps">
            <!--注意:
                   (1)如果value是基本数据类型:则使用<entry key="1" value="100人"></entry>
                   (2)如果value是对象:则使用<entry value-ref=""></entry>-->
            <map>
                <entry key="1" value="100人"></entry>
                <entry key="2" value="200人"></entry>
            </map>
        </property>
    </bean>
1.3.4 高级用法
  • depends-on:控制bean加载顺序(默认从配置文件中从上到下依次加载),当一个bean想让另一个bean先加载则可以用它来达到目的。可以使用设置多个值,逗号分隔。
    <bean id="stu1" class="org.example.pojo.Student" depends-on="dept1"></bean>
    
  • lazy-init懒加载,只有当使用到这个bean的时候才会被加载,而不是在spring容器加载的时候就被加载了。
    <bean id="stu2" class="org.example.pojo.Student" lazy-init="true"></bean>
    
  • scope:bean的作用域,可以设置bean是单例(singleton:不管加载多少次,从始至终只创建一次实例对象)还是多例(prototype:每次加载时,都会创建一个新的实例对象)。
    <bean id="stu3" class="org.example.pojo.Student" scope="prototype"></bean>
    
  • 自动注入
    • (1)byType:根据类型去自动匹配,当出现多个相同的类型时就会报错。
    • (2)byName:根据set方法的名字去自动匹配。
    • (3)constructor:根据构造器自动匹配。
      • a、会优先根据构造器中的参数的名称去匹配注入;
      • b、如果参数名称匹配失败,就会根据构造器的参数类型去进行完整的匹配注入,例如:Person(User user,Wife wife5),要保证IOC容器中同时都存在着两个参数的bean;
      • c、如果b中匹配到多个相同类型的bean时,则自动注入失败但不会报错;
      • d、当根据类型匹配到多个时,可以设置使用bean的优先级以及不参与自动注入;
      • e、primary="true " :设置某个bean被优先被自动注入;
      • f、autowire-candidate="false":设置某个bean不参与到任何的自动注入当中;
     <bean id="dept" class="org.example.pojo.Dept" autowire="constructor"></bean>
    
  • 生命周期函数回调
    • 方式一:接口实现的方式
      • (1)初始化方法:实现接口 InitializingBean 重写 afterPropertiesSet方法,初始化时会自动调用该方法;
      • (2)销毁方法:实现接口 DisposableBean 重写 destroy 方法 销毁的时候会自动调用该方法;
    • 方式二:指定具体的方法实现生命周期的回调
      • 在bean中创建两个对应初始化和销毁的方法;
      • 在配置文件中进行设置指定;
    <bean id="student" class="org.example.pojo.Student" init-method="inits" destroy-method="destorys"></bean>
    
    • 如果以上两种方式的实现都存在,它会先执行接口方式的实现,再执行自定义设置方式的方法。
1.3.5 配置第三方bean对象
 <!--引入外部资源文件-->
    <context:property-placeholder location="db.properties" ></context:property-placeholder>
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${db.username}"></property>
        <property name="password" value="${db.password}"></property>
        <property name="url" value="${db.url}"></property>
        <property name="driverClassName" value="${db.driver}"></property>
    </bean>

1.4 获取bean

  • 首先是加载Spring的IOC容器,加载方式有以下几种:
    • ApplicationContext 是Spring顶层的核心接口;
    • ClassPathXmlApplicationContext 会根据项目路径的xml配置文件来实例化Spring容器(可以同时加载多个配置文件中的bean,用逗号分隔不同的xml文件即可);
    • FileSystemXmlApplicationContext 会根据磁盘路径的xml配置文件来实例化Spring容器;
    • AnnotationConfigApplicationContext 会根据JavaConfig来配置实例化Spring容器;
  • 在容器实例化时,就会加载所有的bean;
  • 接着是获取bean,获取方式有以下几种:
    • 通过类的.class来获取bean ——> getBean(Emp.class)
    • 通过bean的名字或者id来获取bean ——> getBean("emp")
    • 通过类和bean的名字来获取bean ——> getBean("emp",Emp.class)
  ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-ioc.xml");
  Student student = (Student) applicationContext.getBean("student");

2、注解方式

  • 在之前的示例中,都是通过xml文件注册bean并进行属性赋值。其实,在企业开发中使用的最多的方式还是使用注解来快速将bean注册到容器中。

2.1 相关注解

  • @Controller 标记在控制层的类注册为bean组件
  • @Service 标记在业务逻辑层的类注册为bean组件
  • @Repository 标记数据持久层的类注册为bean组件
  • @Compoment 标记非三层的普通类注册为bean组件
  • 注意:
    • 上述注解应该使用在类中而不是接口(如果在接口中使用则在注入容器时会被忽略掉)中;
    • 使用上面的注解时会自动将类的类名的首字母小写然后作为bean的名称(id);

2.2 开启组件扫描

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

	<!--开启组件扫描-->
    <context:component-scan base-package="org.example" use-default-filters="true">
     
     <!-- 设置包含扫描具体的哪一个类-->
	<context:include-filter type="assignable" expression="org.example.impl.DeptServiceImpl"/>
     <!--设置排除扫描具体的哪一个组件-->
	<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>

    </context:component-scan>
</beans>
  • <context:component-scan base-package=“” use-default-filters=“”>
    • 作用:开启组件扫描
    • 属性
      • base-packsge:设置需要被扫描的包路径,多个值用逗号分隔,它会扫描当前包以及其子包;
      • use-default-filters:设置开启或者关闭全局扫描(默认开启);
  • <context:include-filter type=“” expression=“”>
    • 作用:包含扫描,设置需要包含扫描的选项;
    • 属性
      • type
        (1)annotation 根据注解的完整限定名设置排除/包含
        (2)assignable 根据类的完整限定名设置排除/包含
        (3)aspectj 根据切面表达式设置排除/包含
        (4)regx 根据正则表达式设置排除/包含
        (5)custom 根据接口org.springframework.core.type.TypeFilter设置排除/包含
      • expression:相关表达式或者某个类的全局限定名
  • <context:exclude-filter type=“” expression=“”>
    • 作用:排除扫描,设置排除扫描具体的哪一个组件;

2.3 依赖注入

@Service(value = "empService")
public class EmpServiceImpl {

    @Value("金融产业大脑")
    private String name;
    
    @Autowired
    @Qualifier("empDao2")
    private EmpDao empDaos;

    /**
     * 新增员工信息
     * @param emp
     */
    public void insertEmpInfo(Emp emp){
        empDaos.addEmp(emp);
        System.out.println(name);
    }
}
  • 在注解实现自动注入的过程中,会通过byType和byName两种方式来实现;
  • 默认优先按照类型去注入,如果匹配到多个类型就会去按照名称去匹配,如果没有匹配到名称,则就会报错;
	例如:
 	   @Autowired
       private EmpDao empDaos
       
	(1)它匹配到多个类型的EmpDao的bean时,就会按照empDaos的名称去匹配;
	(2)如果按名称去匹配没有发现id = empDaos的bean时,就会报错,此时有以下两种解决方案:
	     a、可以将属性的名称改成对应bean的id的名称,即:empDaos 修改为 empDao
	     b、可以去修改对应bean的id的名称为对应属性的名称,即:
	      @Repository(value = "empDaos")
    	  public class EmpDaoImpl2 implements EmpDao {}
    	 c、结合使用@Qualifier()注解,指定按某个名称去匹配,不按当前属性的名称empDaos去匹配
     		即:
 		  @Autowired
          @Qualifier("empDao")
          private EmpDao empDaos;
         d、可以通过@Primary 设置其中一个bean为主要的自动注入bean

2.4 生命周期函数回调

在类中使用注解自定义指定初始化和销毁方法:

 	 @PostConstruct
    public void init(){
        System.out.println("生命周期函数回调之初始化");
    }

    @PreDestroy
    public void destory(){
        System.out.println("生命周期函数回调之销毁");
    }

2.4 获取bean

 ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-ioc-annotation.xml");
 EmpServiceImpl empService = applicationContext.getBean("empService", EmpServiceImpl.class);
 empService.insertEmpInfo(new Emp());

3、JavaConfig方式

  • JavaConfig原来是 Spring 的一个子项目,它通过 Java 类的方式提供 Bean 的定义信息,在 Spring4 的版本,JavaConfig 已正式成为Spring4 的核心功能 。

3.1 容器配置

  • 创建一个Java配置类,在配置类中对容器和bean进行的相关配置;

    @Configuration //标识该类是一个配置类
    @ComponentScan(basePackages = "org.example") //设置组件扫描的目标包(当前包以及其子包)
    public class IocJavaConfig {}
    

3.2 配置第三方bean

@Configuration //标识该类是一个配置类
@ComponentScan(basePackages = "org.example") //设置组件扫描的目标包(当前包以及其子包)
@PropertySource({"classpath:db.properties"}) //引入外部属性资源文件,可以引入多个文件,它本身是个数组
@Import(MyImportBeanDefinitionRegistar.class)
public class IocJavaConfig {

    @Value("${db.username}")
    private String username;
    @Value("${db.password}")
    private String password;
    @Value("${db.url}")
    private String url;
    @Value("${db.driver}")
    private String driver;

    /**
     * (1)默认这个bean的id其实就是方法的名称 == dataSource,也可以通过name属性来重新设置bean的id
     * (2)将一个创建好的实例化对象交给Spring,这个过程其实是干预了Spring对bean的实例化过程
     * 自动依赖外部bean
     *     直接在方法里面写上需要依赖的参数即可,不需要格外使用自动注入的注解
     * 自动依赖内部bean
     *     直接调用方法即可
     */
    @Bean(name = "dbSource",initMethod = "",destroyMethod = "")
    @Scope("prototype")
    public DruidDataSource dataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setName(username);
        dataSource.setPassword(password);
        dataSource.setUrl(url);
        dataSource.setDriverClassName(driver);
        return dataSource;
    }
}

3.3 @Import注解的四大作用

  • 1、可以导入其他配置类 @Import(SpringConfig.class)
  • 2、可以将类注册为bean @Import(Student.class)
  • 3、通过导入ImportSelector的实现类,来注册多个bean @Import(MyImportSelector.class)
    @Component
    public class MyImportSelector implements ImportSelector {
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            //可以以字符串的形式注册多个Bean
            //字符串必须是类的完全限定名,所以,getBean必须要根据class类型来获取,无法通过名称来获取
            return new String[]{"org.example.pojo.Dept","org.example.pojo.Emp","org.example.pojo.Student"};
        }
    }
    
  • 4、导入ImportBeanDefinitionRegistrar实现类,可以注册多个BeanDefinition
    @Component
    public class MyImportBeanDefinitionRegistar implements ImportBeanDefinitionRegistrar {
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
            //指定它的类型
            beanDefinition.setBeanClass(Student.class);
            //注册bean
            registry.registerBeanDefinition("student",beanDefinition);
        }
    }
    

3.4 获取bean

 //加载Spring容器
 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(IocJavaConfig.class);
 Student student = applicationContext.getBean("student", Student.class);
 System.out.println(student);

二、Spring Bean的实例化

1.通过构造方法实例化Bean

Spring IoC容器能使用默认的无参构造方法,也能使用有参的构造方法,底层通过反射机制来实例化Bean对象。

2.通过工厂实例化Bean

  • 调用静态工厂方法创建bean是将对象创建的过程封装到静态方法中。当客户端需要对象时,只需要简单地调用静态方法,而无需关心创建对象的细节;
  • 要声明通过静态方法创建的bean,需要在bean的class属性里指定拥有该工厂的方法的类,同时在factory-method属性里指定工厂方法的名称。最后,使用元素为该方法传递方法参数;
    Cat类:
public class Cat {
    private String name;
    private int age;
 
    public Cat() {
    }
 
    public Cat(String name, int age) {
        this.name = name;
        this.age = age;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

CatStaticFactory.java:

/**
 * 一个用于创建cat对象的静态工厂
 */
public class CatStaticFactory {
    /**
     * 提供一个创建对象的静态方法
     */
    public static Cat getInstance(String name, int age){
        return new Cat(name, age);
    }
}

applicationContext.xml:

<!-- 静态工厂-->
<bean id="cat1" class="com.newcapec.factory.CatStaticFactory" factory-method="getInstance">
    <constructor-arg value="汤姆猫"/>
    <constructor-arg value="2"/>
</bean>

3.通过FactoryBean实例化Bean

  • Spring中有两种类型的bean,一种是普通bean,另一种是工厂bean,即FactoryBean;
  • 工厂bean跟普通bean不同,其返回的对象不是指定类的一个实例,其返回的是该工厂bean的getObject方法所返回的对象;

CatFactoryBean.java:

public class CatFactoryBean implements FactoryBean<Cat> {
    private String name;
    private int age;
 
    public void setName(String name) {
        this.name = name;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    /**
     * 获取对象
     */
    @Override
    public Cat getObject() throws Exception {
        return new Cat(name, age);
    }
 
    /**
     * 生成对象的Class类型
     */
    @Override
    public Class<?> getObjectType() {
        return Cat.class;
    }
 
    /**
     * 设置该对象是否为单例模式
     */
    @Override
    public boolean isSingleton() {
        return true;
    }
}

applicationContext.xml:

<!-- FactoryBean配置bean -->
<bean id="cat3" class="com.newcapec.factory.CatFactoryBean">
    <property name="name" value="加菲猫"/>
    <property name="age" value="5"/>
</bean>

4. 元素常用的属性或子元素

在 XML 配置的 元素中可以包含多个属性或子元素,常用的属性或子元素如下表所示:
在这里插入图片描述在这里插入图片描述

三、Spring容器

IoC 思想是基于 IoC 容器实现的,IoC 容器底层其实就是一个 Bean 工厂,Spring 框架为我们提供了两种不同类型的 IoC 容器,它们分别是 BeanFactoryApplicationContext

1.BeanFactory

  • BeanFactory 是 IoC 容器的基本实现,也是 Spring 提供的最简单的 IoC 容器。
  • 它提供了 IoC 容器最基本的功能,由 org.springframework.beans.factory.BeanFactory 接口定义。
  • BeanFactory 采用懒加载(lazy-load)机制,容器在加载配置文件时并不会立即创建对象,只有在获取(使用)这个对象时才会创建。

2.ApplicationContext

  • ApplicationContext 是 BeanFactory 接口的子接口,是对 BeanFactory 的扩展。
  • ApplicationContext 在 BeanFactory 的基础上增加了许多企业级的功能,例如 AOP(面向切面编程)、国际化、事务支持等。

3.ApplicationContext的主要实现类

  • ClassPathXmlApplicationContext:从类路径上加载配置文件;
  • FileSystemXmlApplicationContext:从文件系统中加载配置文件;
  • WebApplicationContext:专门为Web应用而准备的,它允许从相对于Web根目录的路径中完成初始化工作;

4.从容器中获取Bean

  • getBean(String name)方法,通过Bean的id名称从容器中获取Bean对象;
  • getBean(Class requiredType)方法,通过Bean的Class类型从容器中获取Bean对象;
  • getBean(String name, Class requiredType)方法,通过Bean的id和Class类型从容器中获取Bean对象;
注意:当IOC容器中存放着多个同类型对象时,不能通过Class类型来获取Bean对象。

BeanTest2测试类

public class BeanTest2 {
    @Test
    public void testGetBean() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        //1.参数为字符串类型
        Person p1 = (Person) ac.getBean("person1");
      
        //2.参数为Class类型,缺点:当IOC容器中存在多个此类型对象时,抛出异常
        Person person = ac.getBean(Person.class);
       
        //3.参数为字符串类型+Class类型
        Person p2 = ac.getBean("person2", Person.class);
    }
}

四、依赖注入

1.基于属性注入

  • 在 Spring 实例化 Bean 的过程中,IoC 容器首先会调用默认的构造方法(无参构造方法)实例化 Bean(Java 对象),然后通过 Java 的反射机制调用这个 Bean 的 setXxx() 方法,将属性值注入到 Bean 中。
  • 使用 Setter 注入的方式进行属性注入,大致步骤如下:
    (1)在 Bean 中提供一个默认的无参构造函数(如果没有带参构造函数),并为所有需要注入的属性提供一个 setXxx() 方法;
    (2)在 Spring 的 XML 配置文件中,使用 及其子元素 对 Bean 进行定义;
    (3)在 元素内使用 元素对各个属性进行赋值,使用name属性指定Bean的属性名称,value属性或子标签指定属性值。属性注入是实际应用中最常用的注入方式。

applicationContext.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">
 
    <!-- 通过setter方法注入属性值 -->
    <bean id="person" class="com.newcapec.bean.Person">
        <!--property标签:表示通过属性的set方法为属性赋值,也叫做依赖注入
                    属性:
        	          name: 对象中的属性名称
        	          value: 属性值                               -->
      <property name="name" value="张三"/>
      <property name="age" value="20"/>
      <property name="money"><value>3600.5</value></property>
    </bean>
</beans>

2.基于构造方法注入

  • 使用构造函数实现属性注入大致步骤如下:
    (1)在 Bean 中添加一个有参构造函数,构造函数内的每一个参数代表一个需要注入的属性;
    (2)在Spring 的 XML 配置文件中,通过 及其子元素 对 Bean 进行定义;
    (3)在 元素内使用 元素,对构造函数内的属性进行赋值,Bean 的构造函数内有多少个参数,就需要使用多少个 元素。
  • Car类:
public class Car {
    private String name;
    private String type;
    private double price;
    private int doors;
 
    public Car(String name, String type, double price, int doors) {
        this.name = name;
        this.type = type;
        this.price = price;
        this.doors = doors;
    }
 
    public Car(String name, String type, int doors) {
        this.name = name;
        this.type = type;
        this.doors = doors;
    }
 
    public Car(String name, String type, double price) {
        this.name = name;
        this.type = type;
        this.price = price;
    }
 
    public Car(String n, String t) {
        this.name = n;
        this.type = t;
    }
 
    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                ", type='" + type + '\'' +
                ", price=" + price +
                ", doors=" + doors +
                '}';
    }
}
  • applicationContext.xml:
    注意:如果该类中有多个构造方法,可以通过index、type或name对构造方法进行精确选取。
<?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="car1" class="com.newcapec.bean.Car">
        <!-- constructor-arg : 表示创建该类型的对象时,使用的构造方法的参数
                         属性:
                             value : 构造方法的参数值
                             index : 构造方法参数的索引
                             type : 构造方法参数的类型
                              name : 构造方法参数的名称            -->
          <constructor-arg value="宝马"/>
          <constructor-arg value="轿车"/>
          <constructor-arg value="360000"/>
          <constructor-arg value="4"/>
    </bean>
   <!-- 按索引匹配构造方法参数 -->
   <bean id="car2" class="com.newcapec.bean.Car">
          <constructor-arg value="越野" index="1"/>
          <constructor-arg value="奔驰" index="0"/>
          <constructor-arg value="4" index="3"/>
          <constructor-arg value="560000" index="2"/>
   </bean>
   <!-- 按类型匹配构造方法参数 -->
  <bean id="car3" class="com.newcapec.bean.Car">
         <constructor-arg value="大众" type="java.lang.String"/>
         <constructor-arg value="商务车" type="java.lang.String"/>
         <constructor-arg value="290000" type="double"/>
  </bean>
   <!-- 按参数名称匹配构造方法参数-->
  <bean id="car4" class="com.newcapec.bean.Car">
        <constructor-arg value="电动车" name="t"/>
        <constructor-arg value="特斯拉" name="n"/>
  </bean>  
</beans>

3.Autowire自动装配

  • 我们把 Spring 在 Bean 与 Bean 之间建立依赖关系的行为称为“装配”。 Spring 的 IOC 容器虽然功能强大,但它本身不过只是一个空壳而已,它自己并不能独立完成装配工作。还需要我们主动将 Bean 放进去,并告诉它 Bean 和 Bean 之间的依赖关系,它才能按照我们的要求完成装配工作。
  • Spring 的自动装配功能可以让 Spring 容器依据某种规则(自动装配的规则,有五种),为指定的 Bean 从应用的上下文(AppplicationContext 容器)中查找它所依赖的 Bean,并自动建立 Bean 之间的依赖关系。
  • Spring 的自动装配功能能够有效地简化 Spring 应用的 XML 配置,因此在配置数量相当多时采用自动装配降低工作量。
  • Spring 框架式默认不支持自动装配,要想使用自动装配,则需要对 Spring XML 配置文件中 元素的 autowire 属性进行设置。
  • Spring 共提供了 五种自动装配规则,它们分别与 autowire 属性的 5 个取值对应,具体说明如下表:
    自动装配规则

五、Bean的作用域

  • 默认情况下,所有的 Spring Bean 都是单例的,也就是说在整个 Spring 应用中,Bean 的实例只有一个。
  • 我们可以在 元素中添加 scope 属性来配置 Spring Bean 的作用范围。例如,如果每次获取 Bean 时,都需要一个新的 Bean 实例,那么应该将 Bean 的 scope 属性定义为 prototype,如果 Spring 需要每次都返回一个相同的 Bean 实例,则应将 Bean 的 scope 属性定义为 singleton。
  • Spring 5 共提供了 6 种 scope 作用域,如下表:
    在这里插入图片描述

1.Singleton

  • singleton 是 Spring 容器默认的作用域。当 Bean 的作用域为 singleton 时,Spring IoC 容器中只会存在一个共享的 Bean 实例。这个 Bean 实例将存储在高速缓存中,所有对于这个 Bean 的请求和引用,只要 id 与这个 Bean 定义相匹配,都会返回这个缓存中的对象实例。
  • 如果一个 Bean 定义的作用域为 singleton ,那么这个 Bean 就被称为 singleton bean。在 Spring IoC 容器中,singleton bean 是 Bean 的默认创建方式,可以更好地重用对象,节省重复创建对象的开销。
  • 在 Spring 配置文件中,可以使用 元素的 scope 属性,将 Bean 的作用域定义成 singleton,其配置方式如下所示:
<!-- singleton -->
<bean id="book" class="com.newcapec.bean.Book" p:id="101" p:name="西游记" p:price="98.5" p:author="吴承恩" scope="singleton"/>

2.Prototype

  • 如果一个 Bean 定义的作用域为 prototype,那么这个 Bean 就被称为 prototype bean。对于 prototype bean 来说,Spring 容器会在每次请求该 Bean 时,都创建一个新的 Bean 实例。
  • 从某种意义上说,Spring IoC 容器对于 prototype bean 的作用就相当于 Java 的 new 操作符。它只负责 Bean 的创建,至于后续的生命周期管理则都是由客户端代码完成的。
  • 在 Spring 配置文件中,可以使用 元素的 scope 属性将 Bean 的作用域定义成 prototype,其配置方式如下所示:
<!-- prototype -->
<bean id="book" class="com.newcapec.bean.Book" p:id="101" p:name="西游记" p:price="98.5" p:author="吴承恩" scope="prototype"/>

六、Bean的生命周期

  • 在传统的 Java 应用中,Bean 的生命周期很简单,使用 Java 关键字 new 进行 Bean 的实例化后,这个 Bean 就可以使用了。一旦这个 Bean 长期不被使用,Java 自动进行垃圾回收。
  • Spring 中 Bean 的生命周期较复杂,SpringIOC容器可以管理Bean的生命周期,Spring允许在Bean生命周期的特定点执行定制的任务,
    大致可以分为以下 5 个阶段:
    Bean 的实例化——> Bean 属性赋值——> Bean 的初始化——> Bean 的使用 ——> Bean 的销毁
  • Spring 根据 Bean 的作用域来选择 Bean 的管理方式,
    (1) 对于 singleton 作用域的 Bean 来说,Spring IoC 容器能够精确地控制 Bean 何时被创建、何时初始化完成以及何时被销毁;
    (2) 对于 prototype 作用域的 Bean 来说,Spring IoC 容器只负责创建,然后就将 Bean 的实例交给客户端代码管理,Spring IoC 容器将不再跟踪其生命周期。

1. Spring的生命周期流程

Spring Bean 的完整生命周期从创建 Spring IoC 容器开始,直到最终 Spring IoC 容器销毁 Bean 为止,其具体流程如下图所示。

2.Bean 生命周期的整个执行过程

  • Spring 启动,查找并加载需要被 Spring 管理的 Bean,对 Bean 进行实例化。
  • 对 Bean 进行属性注入。
  • 如果 Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的 setBeanName() 方法传入当前 Bean 的 id 值。
  • 如果 Bean 实现了 BeanFactoryAware 接口,则 Spring 调用 setBeanFactory() 方法传入当前工厂实例的引用。
  • 如果 Bean 实现了 ApplicationContextAware 接口,则 Spring 调用 setApplicationContext() 方法传入当前 ApplicationContext 实例的引用。
  • 如果 Bean 实现了 BeanPostProcessor 接口,则 Spring 调用该接口的预初始化方法 postProcessBeforeInitialzation() 对 Bean 进行加工操作,此处非常重要,Spring 的 AOP 就是利用它实现的。
  • 如果 Bean 实现了 InitializingBean 接口,则 Spring 将调用 afterPropertiesSet() 方法。
  • 如果在配置文件中通过 init-method 属性指定了初始化方法,则调用该初始化方法。
  • 如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的初始化方法 postProcessAfterInitialization()。此时,Bean 已经可以被应用系统使用了。
  • 如果在 中指定了该 Bean 的作用域为 singleton,则将该 Bean 放入 Spring IoC 的缓存池中,触发 Spring 对该 Bean 的生命周期管理;如果在 中指定了该 Bean 的作用域为 prototype,则将该 Bean 交给调用者,调用者管理该 Bean 的生命周期,Spring 不再管理该 Bean。
  • 如果 Bean 实现了 DisposableBean 接口,则 Spring 会调用 destory() 方法销毁 Bean;如果在配置文件中通过 destory-method 属性指定了 Bean 的销毁方法,则 Spring 将调用该方法对 Bean 进行销毁。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值