Spring IOC BeanFactory 容器 与 BeanFactoryAware 获取容器中指定的 Bean

目录

BeanFactory ( IOC 容)概述

BeanFactoryAware

ApplicationContextAware


BeanFactory ( IOC 容)概述

1、org.springframework.beans.factory.BeanFactory 是一个 Factory(工厂),也就是 IOC 容器/对象工厂,Spring 中所有的 bean 都是由 BeanFactory(也就是IOC容器)来进行管理的。

2、经常会使用 @Autowired、@Resource 注解来从 Spring 容器中获取实例,而这些实例恰恰都是 BeanFactory 管理。无论是以前用 xml 配置文件来配置 <bean>、还是后来使用 @Bean 注解,都是为了将对象交由 Spring 容器管理。

3、BeanFactory 作为 IOC 功能的顶级接口,提供了各种不同的实现,IOC 作为 Spring 的核心功能之一,所以这些 API 也是很常见的。

//这两行代码一定不陌生

BeanFactory bf = new ClassPathXmlApplicationContext("student.xml");
Student studentBean = (Student) bf.getBean("studentBean");

//BeanFactory 在 spring-beans-x.x.x.RELEASE.jar 包下

扫描二维码关注公众号,回复: 8562605 查看本文章

4、ApplicationContextBeanFactory 的扩展,功能得到了进一步增强,比如更易与 Spring AOP 集成、消息资源处理(国际化处理)、事件传递及各种不同应用层的 context 实现(如针对 web 应用的 WebApplicationContext )。

BeanFactory 接口常用方法
Object getBean(String name)

返回指定名称的 bean 实例,默认为单例。

如果没有具有指定名称的bean,则引发 NoSuchBeanDefinitionException

如果无法获取bean,则抛出 BeansException

<T> T getBean(String name, Class<T> requiredType)

在 get(String name) 的基础上加上了requiredType类型限制,可以是接口或超类。

如果bean不是所需类型,则引发BeannotofRequiredTypeException

<T> T getBean(Class<T> requiredType)

返回唯一匹配给定对象类型的bean实例(如果有).

bean 必须匹配参数RequiredType类型,可以是接口或超类

如果找到给定类型的多个bean,则引发nouniqueBeanDefinitionException

boolean containsBean(String name) 返回是否存在具有给定名称的bean.
boolean isSingleton(String name) 返回此bean是否是单例。如果没有具有给定名称的bean,则引发nosuchbeanDefinitionException
Class<?> getType(String name)

返回bean的类型,如果不能确定,则返回 NULL。

如果没有具有给定名称的bean,则引发nosuchbeanDefinitionException

BeanFactoryAware

1、对于 BeanFactory 管理的 Bean,怎么获取它然后使用呢?使用 @Autowired、@Resource 注解来注入是最常见的操作,也是必须掌握的技能。

2、 使用 @Autowired、@Resource 注解的类自己首先必须是 Spring 组件 @Component 才能注入,而有时候想在项目中的任意位置都能获取容器中的实例进行使用,比如想在某个 XxxUtils 中使用某个 @Service 标识的实例,这时把 XxxUtils 标识为 @Component ,然后使用 @Resource 注入实例,这种方式看起来没有使用代码直接从 BeanFactory 容器中获取实例方便。

3、显然只要拿到了 BeanFactory 对象,就可以使用它的 getBean 方法从容器中获取 bean 实例,而获取 BeanFactory 实例的一个最简单的方式就是实现 BeanFactoryAware 接口。

package org.springframework.beans.factory;
import org.springframework.beans.BeansException;

/**
 * BeanFactoryAware 接口只要一个方法
 */
public interface BeanFactoryAware extends Aware {
    
    /**初始化回调方法,spring 会自动将 BeanFactory 注入进行,我们接收之后即可使用 BeanFactory*/
    void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}

//BeanFactoryAware 在 spring-beans-x.x.x.RELEASE.jar 包下

编码演示

1、下面使用 Jdk 8 + Spring Boot 2.1.6(Spring 5.1.8 )进行演示,代码结构如下,详细说明在代码注释中。

浏览器访问 PersonController 中的方法,PersonController 中不再使用 @Autowired、@Resource 注解注入 PersonService,而是使用 BeanFactoryHelper 获取 PersonService 实例。

2、为了结构完整,定义一个 service 接口和它的实现类:

package wmx.com.springbootredisstudy.services;

public interface PersonService {
    void deleteAll();
}
package wmx.com.springbootredisstudy.services.iml;

import org.springframework.stereotype.Service;
import wmx.com.springbootredisstudy.services.PersonService;
import java.util.logging.Logger;

//@Service 注解没有指定名称时,默认为实现类 类名首字母小写的 personServiceImpl 
@Service
public class PersonServiceImpl implements PersonService {
    private Logger logger = Logger.getAnonymousLogger();
    @Override
    public void deleteAll() {
        logger.info("删除所有用户成功");
    }
}

3、自定义一个工厂类/工具类/助手类 实现 BeanFactoryAware 接口,有了它,则可以在项目中的任意位置传入 bean 名称或者类型来轻松获取容器中的实例:

package wmx.com.springbootredisstudy.factory;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.stereotype.Component;

/**
 * 1、实现 BeanFactoryAware 接口,重写 setBeanFactory(BeanFactory beanFactory)
 * 2、本类必须是 Spring 组件,所以加上 @Component 注解
 * 3、spring 容器启动实例化本类的时候,会自动执行回调方法 setBeanFactory(BeanFactory beanFactory) 将 BeanFactory 注入
 * 4、获取了 BeanFactory 之后,则可以使用它的任意方法了,比如各种 getBean
 */
@Component
public class BeanFactoryHelper implements BeanFactoryAware {
    private static BeanFactory beanFactory;
    /**
     * 重写 BeanFactoryAware 接口的方法
     * @param beanFactory :参数赋值给本地属性之后即可使用 BeanFactory
     * @throws BeansException
     */
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }
    /**
     * 根据名称获取容器中的对象实例
     * @param beanName :注入的实例必须已经存在容器中,否则抛异常:NoSuchBeanDefinitionException
     * @return
     */
    public static Object getBean(String beanName) {
        return beanFactory.getBean(beanName);
    }
    /**
     * 根据 class 获取容器中的对象实例
     * @param requiredType :被注入的必须已经存在容器中,否则抛异常:NoSuchBeanDefinitionException
     * @param <T>
     * @return
     */
    public static <T> T getBean(Class<T> requiredType) {
        return beanFactory.getBean(requiredType);
    }
    /**
     * 判断 spring 容器中是否包含指定名称的对象
     * @param beanName
     * @return
     */
    public static boolean containsBean(String beanName) {
        return beanFactory.containsBean(beanName);
    }
    //其它需求皆可参考 BeanFactory 接口和它的实现类
}

4、控制层代码如下:

package wmx.com.springbootredisstudy.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import wmx.com.springbootredisstudy.factory.BeanFactoryHelper;
import wmx.com.springbootredisstudy.services.PersonService;

import java.util.logging.Logger;

@RestController
public class PersonController {
    private Logger logger = Logger.getAnonymousLogger();
    /**
     * 删除所有用户:http://localhost:8080/person/deleteAll
     */
    @GetMapping("person/deleteAll")
    public String deleteAll() {
        logger.info("用户准备删除所有用户...");
        //PersonService personService = BeanFactoryHelper.getBean(PersonService.class);
        //上面是根据 bean 的类型获取实例,下面是根据 bean 的名称获取实例
        PersonService personService = (PersonService) BeanFactoryHelper.getBean("personServiceImpl");
        personService.deleteAll();
        return "delete success";
    }
}

ApplicationContextAware

1、上面已经说过 ApplicationContext 接口是 BeanFactory 接口的扩展,功能得到了进一步增强,能使用的方法也更多。

2、BeanFactory 对应 BeanFactoryAware,ApplicationContext 对应 ApplicationContextAware ,使用起来完全同理。

package wmx.com.springbootredisstudy.factory;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * 1、spring 容器启动的时候会自动创建 ApplicationContextHelper 实例
 * 2、然后调用 setApplicationContext 回调方法自动注入 ApplicationContext
 * 3、有了 ApplicationContext 就可以 getBean 了
 */
@Component
public class ApplicationContextHelper implements ApplicationContextAware {
    private static ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
    /**
     * 根据名称获取容器中的对象实例
     * @param beanName :注入的实例必须已经存在容器中,否则抛异常:NoSuchBeanDefinitionException
     * @return
     */
    public static Object getBean(String beanName) {
        return applicationContext.getBean(beanName);
    }
    /**
     * 根据 class 获取容器中的对象实例
     * @param requiredType :被注入的必须已经存在容器中,否则抛异常:NoSuchBeanDefinitionException
     * @param <T>
     * @return
     */
    public static <T> T getBean(Class<T> requiredType) {
        return applicationContext.getBean(requiredType);
    }
    /**
     * 判断 spring 容器中是否包含指定名称的对象
     * @param beanName
     * @return
     */
    public static boolean containsBean(String beanName) {
        return applicationContext.containsBean(beanName);
    }
}
发布了458 篇原创文章 · 获赞 884 · 访问量 92万+

猜你喜欢

转载自blog.csdn.net/wangmx1993328/article/details/98296914