Spring概述2-生命周期&后置处理器&注解装配

1 Spring的生命周期

  1. 调用空参构造创建实例

  2. 调用settter方法设置属性

  3. 调用init方法初始化对象

  4. 获取容器中设置的bean属性

  5. 调用destory方法销毁对象

2 bean的后置处理器

首先需要一个处理器对象,通过实现BeanPostProcessor接口

package com.yuyi.spring.lifecycle;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
 * Created on 2021/6/18.
 * <p>
 * Author: Lcywings
 * <p>
 * Description:
 */
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("--------- 3.0 后置处理器,执行init方法调用之前 -----------------------");
        Car car = (Car) bean;
        car.setFactory("广汽");
        System.out.println("***:" + bean.toString());
      
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("--------- 3.1 后置处理器,执行init方法调用之后 -----------------------");
        Car car = (Car) bean;
        car.setFactory("上汽");

        System.out.println("***:" + bean.toString());
      //这里注意返回获取的bean对象
        return bean;
    }
}

其次在容器中配置处理器

<!-- 初始化一个后置处理器,放入容器,才能生效-->
<bean class="com.yuyi.spring.lifecycle.MyBeanPostProcessor">

​ 注意:在容器中配置后置处理器后,后置处理器会依次处理所有调用的bean对象

3 自动装配

<?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="car" class="com.yuyi.spring.auto.Car">
        <property name="brand" value="奥迪A3"/>
        <property name="factory" value="一汽"/>
        <property name="price" value="210000.0"/>
    </bean>

    <!-- 初始化房子-->
    <bean id="house" class="com.yuyi.spring.auto.House">
        <property name="houseType" value="公寓"/>
        <property name="houseArea" value="43"/>
        <property name="housePrice" value="1150000.0"/>
    </bean>

    <!-- 初始化人-->
    <bean id="person" class="com.yuyi.spring.auto.Person" autowire="constructor">
        <property name="name" value="yuyi"/>
    </bean>
</beans>

容器中的bean可以配置autowire属性设置自动装配,有三种配置属性可选

  1. byType:根据类型自动装配:将类型匹配的 bean 作为属性注入到另一个 bean 中。若 IOC 容器 中有多个与目标 bean 类型一致的 bean,Spring 将无法判定哪个 bean 最合适该属性, 所以不能执行自动装配

  2. by Name:根据名称自动装配:必须将目标 bean 的名称和属性名设置的完全相同

  3. constructor:通过构造器自动装配:当 bean 中存在多个构造器时,此种自动装配方式将会很复杂。 不推荐使用

4 分层注解和组件扫描

分层注解四个标签:

  1. @Controller:控制层,此注解控制层注解,在mvc框架中,有特殊含义,不能随便用
  2. @Repository:持久层
  3. @Service:业务层
  4. @Component:工具层
组件扫描配置 : 将添加了四个分层注解的类,自动创建实例对象放入容器中,交给spring管理
  • base-package属性:指定扫描的基包(父包),Spring容器将会扫描这个基类包及其子包中的所有添加了分层注解的类。
  • 默认情况,增加了分层四个注解的类,在spring扫描到容器中,使用类名的首字母小写,作为bean的id值。相当于手写了一个:...
  • 如果不想使用类名首字母小写作为bean的id值,可以在四个分层注解上增加value属性,指定自定义id值
  • 强调:事实上 Spring 并没有能力识别一个组件到底是不是它所标记的类型即使将@Respository 注解用在一个表述层控制器组件上面也不会产生任何错误所以 @Respository、@Service、@Controller 这几个注解仅仅是为了让开发人员自己明确当前的组件扮演的角色。
  • 当需要扫描多个包时可以使用逗号分隔多个包的全路径
基本扫描配置:
<!-- <context:component-scan base-package="com.kgc.spring.annotation" use-default-filters="false"> -->
<context:component-scan base-package="com.kgc.spring.annotation"</context:component-scan>
包含扫描:
 <!-- 包含扫描:只扫描某类组件或者某些类,将其加入到容器中,默认情况,是基于base-package全部扫描,如果要进行指定扫描,必须让父标签默认过滤器失效 -->
<context:component-scan base-package="com.kgc.spring.annotation" use-default-filters="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
排除扫描:
<!-- 排除扫描:排除某类组件或者某些类,将其他没有排除的组件,添加到容器中,不需要关闭父标签的默认过滤器,仍然扫描所有,子标签排除自动生效 -->
<context:component-scan base-package="com.kgc.spring.annotation">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

5 组件装配

以前古老写法:private UserService userService = new UserServiceImpl();代码的耦合度高,不利于代码扩展和维护,实现类一旦修改,此处必须跟着改

@Autowired注解:

​ 可以实现bean的类型属性自动装配(自动从spring的容器中找对应的实例对象,注入到当前实体属性上,相当于自己new工作交给了spring,让它管理)

工作原理:

  • 首先会使用byType的方式,进行自动装配,如果能唯一匹配成功,装配成功,如果匹配了多个同类型的bean对象会再次尝试使用byName的方式进行唯一匹配,如果能唯一匹配成,则装配成功,否则装配失败,直接抛出异常。
  • 默认情况下,Autowired注解标注的实体属性,必须被装配,如果不是必须被装配属性,可以通过设置注解属性required=false,不会自动检查。
  • 如果有多个同类型的bean对象,可以使用Qualifier注解,指定需要装配的目标bean对象
  • Resource注解,也可以实现自动装配,但是这个不是spring的注解,是jdk提供的,实现自动装配原理,正好跟Autowired注解是相反的(先根据名称,再根据类型)
  • 实际开发过程中,一般一个接口都只会有一个实现类,所以通常都用Autowired注解自动装配

Q.E.D.