一、Bean 的注入

@Configuration
@Import({User.class, ImportSelectorDemo.class, ImportBeanDefinitionRegistrarImpl.class})   // id 默认为 User 的全类名
public class SpringConfig {

    /**
     * 容器添加组件的方式
     * 1.component-scan + @Controller/@Service/@Repository/@Component
     * 2.@Bean
     * 3.@Import
     *      a.@Import({User.class})   // id 默认为 User 的全类名
     *      b.@Import({ImportSelectorImpl.class})   // 将 ImportSelectorImpl::selectImports 返回值导入容器
     *      c.@Import({ImportBeanDefinitionRegistrarImpl.class})  // 使用 
     *							ImportBeanDefinitionRegistrar::registerBeanDefinitions 自行注入 bean
     * 4.使用 FactoryBean
     *      a.需要将 FactoryBean 加入容器才能使该 FactoryBean 生效
     *      b.通过 FactoryBean 的 ID 值获取到的 Bean 对象为 FactoryBean::getObject 创建的对象
     *        如果需要获取 FactoryBean 本身,需要在 FactoryBean 的 ID 值前加前缀 "&"
     */
    @Bean(value = "person")
    public Person getPerson() {
        return new Person(1, "Lee", 53);
    }

    @Bean
    public UserFactoryBean userFactoryBean() {
        return new UserFactoryBean();
    }
}

// 使用 @Import({ImportSelectorImpl.class}) 注入组件
public class ImportSelectorImpl implements ImportSelector {

    /**
     * @param importingClassMetadata    使用该 ImportSelector 的类的所有注解信息
     * @return  需要导入到容器中的所有组件的全类名
     */
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.blackpearl.entities.Color"};
    }
}

// 使用 @Import({ImportBeanDefinitionRegistrarImpl.class}) 注入组件
public class ImportBeanDefinitionRegistrarImpl implements ImportBeanDefinitionRegistrar {

    /**
     * @param importingClassMetadata    使用该 ImportBeanDefinitionRegistrar 的类的所有注解信息
     * @param registry  使用 registry.registerBeanDefinition 手动注册 bean
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        RootBeanDefinition beanDefinition = new RootBeanDefinition(Red.class);
        registry.registerBeanDefinition("red", beanDefinition);
    }
}

/**
 * FactoryBean<T> 范性的类型即为需要加入容器的组件类型
 */
public class UserFactoryBean implements FactoryBean<User> {

    /**
     * 返回一个 User 对象并加入容器
     * 使用 FactoryBean<T>::getObject 注入容器
     */
    @Override
    public User getObject() throws Exception {
        return new User("admin", "admin");
    }

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

    @Override
    public boolean isSingleton() {
        return true;
    }
}

二、Bean 的生命周期

1、自定义 Bean 对象的 init / destroy 方法

/**
 * Bean 的生命周期大致概括为
 *      Bean 创建 => Bean 初始化 => Bean 销毁
 *      根据 Bean 的 Scope 不同,Bean 的创建时机也不相同,Spring 支持自定义 Bean 的初始化和销毁方法
 *
 * 指定 Bean 的初始化和销毁方法
 * 1.xml 中可以指定 init-method="" destroy-method="" 定制 Bean 的初始化和销毁方法
 * 2.@Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
 * 3.让 Bean 对象 implements InitializingBean => 实现 Bean 初始化方法
 *               implements DisposableBean   => 实现 Bean 销毁方法
 * 4.给 Bean 对象中的方法标注 @PostConstruct => 实现 Bean 初始化方法
 *                    标注 @PreDestroy    => 实现 Bean 销毁方法
 */
@ComponentScan(basePackages = {"com.blackpearl.entities"})
@Configuration
public class BeanLifeConfig {

    class Car {

        public void initMethod() {
            System.err.println("Car::initMethod()");
        }

        public void destroyMethod() {
            System.err.println("Car::destroyMethod()");
        }

    }
    
    // 使用 @Bean 属性指定初始化和销毁方法
    @Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
    public Car car() {
        return new Car() ;
    }
}

/** 
 * 使用 InitializingBean::afterPropertiesSet => init-method
 * 使用 DisposableBean::destroy => destroy-method
 */
@Component
public class Cat implements InitializingBean, DisposableBean {
  
    @Override
    public void destroy() throws Exception {
        System.err.println("Cat::destroy()");
    }

    // 初始化方法
    @Override
    public void afterPropertiesSet() throws Exception {
        System.err.println("Cat::afterPropertiesSet()");
    }
}

/** 
 * 使用 @PostConstruct => init-method
 * 使用 @PreDestroy => destroy-method
 */
@Component
public class Dog {

    @PostConstruct
    public void initMethod() {
        System.err.println("Dog::initMethod()");
    }

    @PreDestroy
    public void destroyMethod() {
        System.err.println("Dog::destroyMethod()");
    }
}

2、interface BeanPostProcessor

1、使用方式
/**
 * Bean 的生命周期:
 * Bean 的构造(Bean 对象创建)
 *      单实例:容器启动时创建 Bean
 *      多实例:每次获取时创建对象
 *
 * BeanPostProcessor::postProcessBeforeInitialization
 *
 * Bean 的初始化:
 *      对象创建完成并完成赋值,调用指定的 Bean 初始化方法
 *
 * BeanPostProcessor::postProcessAfterInitialization
 *
 * Bean 的销毁:
 *      单实例:容器销毁时执行指定的 Bean 销毁方法
 *      多实例:不会调用销毁方法
 *
 * 使用 interface BeanPostProcessor 的 postProcessBeforeInitialization => Bean 对象初始化方法执行之前执行
 *                                    postProcessAfterInitialization  => Bean 对象初始化方法执行之后执行
 */
@Component
public class BeanPostProcessorImpl implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.err.println(beanName + " 对象自定义初始化方法之前执行");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.err.println(beanName + " 对象自定义初始化方法之后执行");
        return bean;
    }
}
2、原理解析

Bean 的创建流程位于 AbstractAutowireCapableBeanFactory::doCreateBean

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
        implements AutowireCapableBeanFactory {


    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {

        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        // 如果 Bean 对象为单实例
        if (mbd.isSingleton()) {
            // 先尝试从缓存中获取
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            // 获取失败则执行 Bean 对象构造方法 => 创建 Bean 对象
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }

        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            // 为创建的 Bean 对象进行属性赋值
            populateBean(beanName, mbd, instanceWrapper);
            // 执行 Bean 对象的初始化方法
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {}

        // Register bean as disposable.
        try {
            // 将单实例 Bean 对象加入到 list 中,在容器销毁时会调用这个 list 中所有 Bean 对象的销毁方法
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {}

        return exposedObject;
    }

    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) 
    {
      
        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            // 执行容器中所有的 BeanPostProcessor 执行其 postProcessBeforeInitialization 方法 
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        try {
            // 执行 Bean 对象的初始化方法
            invokeInitMethods(beanName, wrappedBean, mbd);
        }
        catch (Throwable ex) {}
        if (mbd == null || !mbd.isSynthetic()) {
            // 执行容器中所有的 BeanPostProcessor 执行其 postProcessAfterInitialization 方法 
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

        return wrappedBean;
    }
}

三、Bean 的属性赋值

/**
 * 使用 @PropertySource(value = {"***"}) 将外部配置文件中配置的 k:v 值加载保存至环境(Environment)变量中
 * 加载完外部配置文件后可以使用 "${}" 获取其中的配置项的值
 */
@PropertySource(value = {"classpath:pig.properties"})
@Configuration
public class ValueConfig {

    @Bean
    public Pig pig() {
        return new Pig();
    }
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Pig {
		// @Value 的 value 表达式支持 普通string / #{} / ${}
    @Value(value = "#{20 - 3}")
    private Integer id;
    @Value(value = "乔治")
    private String name;
    @Value(value = "${pig.age}")
    private Integer age;

}

四、Bean 的自动装配

1、@Autowired / @Resource / @Inject

@Controller
public class ControllerDemo {

    /**
     * 使用 @Autowired 进行自动注装配组件
     * 1.默认按照类型在容器中查找对应的组件 => applicationContext.getBean(UserService.class)
     * 2.如果有多个类型相同的组件,则使用 属性名 作为 id 在容器中查找对应的组件 => 
     *			applicationContext.getBean("userService")
     * 3.使用 @Autowired 自动注入组件默认必须注入成功,否则报错
     *      使用 @Autowired(required = false) 修改为装配失败不报错
     *
     * 使用 @Qualifier(value = "***") 指定装配组件的 id 值
     *
     * 使用 @Primary 指定装配该类型的组件时,优先使用哪个组件进行注入
     *      @Qualifier 优先级大于 @Primary
     *      即指定 @Qualifier,后者就会失效
     *
     * @Resource 和 @Inject 的功能和 @Autowired 类似均可以完成自动注入功能
     * 1.@Resource 默认按 属性名 进行自动装配,不支持 @Primary 同时不支持 required 属性修改
     * 2.@Inject 默认按 类型 进行自动装配的,不支持 required 属性修改
     * 3.@Autowired          => org.springframework.***  Spring 独有
     *   @Resource / @Inject => javax.***                javax  规范
     */
    @Autowired
    @Qualifier(value = "userService")
    private UserService userService;

    @Resource
    private UserDao userDao;

    @Inject
    private PersonDao personDao;
}
  • @Autowired 的使用
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
public @interface Autowired {}
  • ElementType.CONSTRUCTOR:构造器使用的方法参数默认会从容器中获取
    容器中的 Bean 在容器启动会调用其无参构造器创建对象,再进行赋值操作
    如果类只存在一个有参构造器,构造器的参数即使不指定 @Autowired 默认也会从容器中获取
  • ElementType.METHOD:方法参数默认会从容器中获取
    @Bean 标注的方法的方法参数即使不使用 @Autowired 同样会从容器中获取
  • ElementType.PARAMETER:指定该参数的值需要从容器中获取
  • ElementType.FIELD:自动将容器中的组件注入到该变量

2、自动装配 Spring 容器底层应用组件

自定义组件如果需要注入 Spring 容器底层组件,需要实现 ***Aware 接口,这些接口定义的方法会在 Bean 对象执行初始化方法之前执行,注入 Spring 容器底层应用组件

1、使用方式
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {

    private String username;
    private String password;

    /**
     * BeanNameAware::setBeanName
     * @param name 当前 Bean 在容器中的 name
     */
    @Override
    public void setBeanName(String name) {
        System.err.println("class Red => " + name);
    }

    /**
     * ApplicationContextAware::setApplicationContext
     * @param applicationContext Spring 容器
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.err.println("Spring IOC => " + applicationContext);
    }

    /**
     * EmbeddedValueResolverAware::setEmbeddedValueResolver
     * @param resolver 表达式解析器,解析 #{} ${}
     */
    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        System.err.println("ValueResolver => " + resolver);
    }
}
2、原理解析

每一个 ***Aware 接口均会通过 ***Processor 在 Bean 执行初始化方法之前执行 ***Aware 接口定义的方法

@Override
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
   if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
         bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
         bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
      // 如果 Bean 未 implements 这些 ***Aware 接口,直接返回
      return bean;
   }
	
   // 否则执行 ***Aware 接口定义的方法
   invokeAwareInterfaces(bean);

   return bean;
}

/**
 * 根据 Bean 对象 implements 的 Aware 接口的不同,执行其中的 set*** 方法传入 Spring 底层容器组件
 */
private void invokeAwareInterfaces(Object bean) {
   if (bean instanceof EnvironmentAware) {
      ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
   }
   if (bean instanceof EmbeddedValueResolverAware) {
      ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
   }
   if (bean instanceof ResourceLoaderAware) {
      ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
   }
   if (bean instanceof ApplicationEventPublisherAware) {
      ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
   }
   if (bean instanceof MessageSourceAware) {
      ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
   }
   if (bean instanceof ApplicationContextAware) {
      ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
   }
}

3、使用 @Profile 指定 Bean 的加载环境

@Profile 可以用于指定 Bean 对象被加载至 Spring 容器的环境,不指定 @Profile,默认在任何环境都会加载这个 Bean 对象

@Configuration
@Profile(value = {"default"})
public class SpringConfig {

    /**
     * 指定 @Bean 方法上的 @Profile(value = {"dev"}) 的 Bean 对象仅在环境满足的情况下进行加载
     *      不指定则任何环境下均会加载该 Bean 对象
     * 指定配置类上的 @Profile,类中的所有配置项仅在环境满足的情况下进行配置
     *
     * 如何切换环境:
     * 1.使用虚拟机参数 -Dspring.profiles.active = ***
     * 2.改变 Spring 容器配置类的获取方式
     *      AnnotationConfigApplicationContext applicationContext
     *                 = new AnnotationConfigApplicationContext(SpringConfig.class);
     *           =>     AnnotationConfigApplicationContext applicationContext 
     *								 					= new AnnotationConfigApplicationContext();
     *                  applicationContext.getEnvironment().setActiveProfiles("dev");
     *                  applicationContext.register(SpringConfig.class);
     *                  applicationContext.refresh();
     */
    @Profile(value = {"default"})
    @Bean(value = "person")
    public Person getPerson() {
        return new Person(1, "Lee", 53);
    }

    @Profile(value = {"dev"})
    @Bean
    public User user() {
        return new User();
    }
}