你了解Spring BeanFactoryAware嘛

2023-11-17

    其实再写这篇文章之前呢,我是看Spring IOC源码,可是老师啃不动。那么就从外围开始吧。在Spring生命周期的探索当中,其中网上主流的做法就是让我们的Bean实现一大波接口,到目前为止,这些接口的名称一个也没有记住,Spring的这个名称太长啦。其中有这么一个接口BeanFactoryAware。什么意思呢?

    在我之前的文章中为大家介绍过,那就是Spring的Bean是无知觉的。类似于Http请求的无状态一般。Bean是要注入在Spring容器当中的,也就是BeanFactory以及ApplicationContext这两个容器。为了使得Bean存在意识感,那么就要实现一些类Aware接口。而Aware接口也恰好是意识、直觉的意思。

    下面的代码是我演示实现了这个接口之后的一些操作:

        首先我们看看BeanFactoryAware接口的架构:

public interface BeanFactoryAware extends Aware {


    void setBeanFactory(BeanFactory beanFactory) throws BeansException;

}

        这个Aware接口就是意识的意思。BeanFactoryAware就是让我们的Bean在容器中有存在感。知道老子在炼丹炉中一样。看BeanFactoryAware就一个方法,setBeanFactory,传的参数很简单,就是BeanFactory容器。

public class Car implements BeanFactoryAware{
    private String brand;
    private String color;
    private int maxSpeed;

    private BeanFactory beanFactory;

    public String getBrand() {
        return brand;
    }

    public void setBrand(final String brand) {
        System.out.println("调用Car的setBrand属性");
        this.brand = brand;
    }

    @Override
    public void setBeanFactory(final BeanFactory beanFactory) throws BeansException {
        System.out.println("调用BeanFactoryAware的setBeanFactory方法--->");
        this.beanFactory=beanFactory;
    }

    @Override public String toString() {
        return "Car{" +
                "brand='" + brand + '\'' +
                ", color='" + color + '\'' +
                ", maxSpeed=" + maxSpeed +
                '}';
    }
}

    上述的Bean很简单,就是三个字段,外加一个BeanFactory接口。实现了setBeanFactory方法。其中的brand设置了setter方法。下面是我的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">
    <bean id="car" class="com.gosaint.domain.Car"/>
</beans>
    @Test
    public void testLife(){
        ApplicationContext applicationContext=
                new ClassPathXmlApplicationContext("classpath:spring/spring-beans.xml");
        Car car = (Car) applicationContext.getBean("car");
        car.setBrand("奔驰");
        System.out.println(car);

    }

    获取结果如下:

调用BeanFactoryAware的setBeanFactory方法--->

调用Car的setBrand属性

Car{brand='奔驰', color='null', maxSpeed=0}

    可以清楚的看到,在调用brand的setter方法之前,是调用了BeanFactoryAware接口的setBeanFactory()方法的。其实上述的代码也很好理解,可能大家要问,什么时候beanFactory实例化的呢。其实在上述的代码中,在通过ClasspathXmlApplicationContext获取容器的时候,读取配置文件,定位到Bean,实例化对象之后就开始讲BeanFactory注入到Car这个Bean当中啦。

        但是我这样做只是用来探究这个接口的实际含义,其实Spring是不推荐这样做的,就是不推荐我们的Bean去实现这个接口。一旦我们的bean实现了这个接口,那么Bean就和Spring框架产生了严重的耦合。

        思考一个问题,就是我们在平时使用Spring Bean的时候是怎么使用的?是不是一般就是在xml中配置,然后直接使用@Autowired来使用。实现了该接口我们是不是可以直接从Spring容器中获取相关的对象?

@Service
public class BeanFactoryHelper implements BeanFactoryAware {

    private  BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    public  Object getBean(String beanName){

     if(beanFactory == null){
            throw new NullPointerException("BeanFactory is null!");
        }
     return beanFactory.getBean(beanName); 
  } 
}

此时是不是可以直接调用getBean("XXX")去获取呢?我再来设想一个场景:假设我有一个Service的接口,恰好实现了这和接口,就如上述的代码所示;比如说我有2个业务处理对象,他们都继承了我的BeanFactoryHelper对象,但是具体处理的时候要哪家业务的对象呢?这个依赖于用户的选择。 你可以注入2个BeanFactoryHelper实例,然后用if --else来搞,不过那样太坨了。每增加一个业务你都需要改代码。繁琐的操作如下:

public void testLife2(){
        ApplicationContext applicationContext=
                new ClassPathXmlApplicationContext("classpath:spring/spring-beans.xml");
        BeanFactoryHelper helper =
                (BeanFactoryHelper) applicationContext.getBean("beanFactoryHelper");
        helper=new Demo001();
        handler(helper);
    }
    public void handler(Object obj){
        if(obj instanceof Demo001){
           //TODO 处理001的业务 
        }else if(obj instanceof Demo002){
            //TODO 处理002的业务  
        }
    }

以后若是变动,还要添加代码。如果实现BeanFactoryAware,那么一切都好说,因为Spring实例化之后,我们只需要根据bean的名称获取对象即可。不会去实例化每一个对象。下面的代码是我之前项目中的一个片段:

 1public class ControlServiceImpl implements IControlService, BeanFactoryAware {
 2    private BeanFactory factory;
 3
 4    @Override
 5    public void setBeanFactory(BeanFactory factory) {
 6        this.factory = factory;
 7    }
 8    @Override
 9    public OutputObject execute(InputObject inputObject) {
10        System.out.println("--------------ControlServiceImpl.execute()方法---------");
11
12        OutputObject outputObject = new OutputObject(ControlConstants.RETURN_CODE.IS_OK);
13        try {
14            outputObject.setReturnCode(ControlConstants.RETURN_CODE.IS_OK);
15            if (inputObject != null) {
16                Object object = factory.getBean(inputObject.getService());
17                Method mth = object.getClass().getMethod(inputObject.getMethod(), InputObject.class, OutputObject.class);
18                mth.invoke(object, inputObject, outputObject);
19            } else {
20                throw new Exception("InputObject can't be null !!!");
21            }
22        } catch (Exception e) {
23            // 异常处理
24
25        } finally {
26
27        }
28        return outputObject;
29    }
30}

作为后台service的统一入口:我实现了这个BeanFactoryAware接口。然后通过factory.getBean(Object)去动态的获取每一个Service。然后反射动态调用service中的方法,这样的实现是不是很好!其实我们要根据自身的业务场景去灵活的解决我们的问题。虽然说这样代码耦合度太高,但是现在那个项目离开Spring还能单独存活呢?当然是有的,可是目前主流开发都是离不开Spring的。

总结:1 实现BeanFacoryAware接口,是在Bean实例化后开始调用,在Setter方法之前调用。2 实现了BeanFacoryAware接口,可以使得bean获取到容器的内部信息,从而进行某些定制化的操作。3 实现了实现了BeanFacoryAware接口,可以使得Bean在容器中有意识,这样的目的是2中所说的。

一个人生气蓬勃的时候决不问为什么生活,只是为生活而生活——为了生活是桩美妙的事而生活。 from 《约翰·克里斯朵夫》

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

你了解Spring BeanFactoryAware嘛 的相关文章

随机推荐

  • 企业微信如何简单实现定时发送文件到群:企业微信群机器人操作(Java代码实现)

    前言 不知道小伙伴们的公司组织架构通勤用的啥软件 我公司用的企业微信 然后业务销售部那边需要每天统计销售数据报表然后发在群里 我是开发 我不配在群里 知道这个背景以后 产品给我们的需求是 直接统计数据按照业务那边的报表模板直接生成销售报表
  • ARM-A架构入门基础(三)MMU

    14天学习训练营导师课程 周贺贺 ARMv8 ARMv9架构 快速入门 1 MMU Memory Management Unit 内存管理单元 MMU的意义在于将软件程序的虚拟地址转换为真实的物理地址 2 MMU种类 Secure EL1
  • 数据结构——图解循环队列长度计算问题

    队列定义是这样的 define MAXSIZE 10 typedef struct ElemType data MAXSIZE int front rear SeqQueue 一个队列 一个存放元素的数组 一个队头指针 一个队尾指针 fro
  • np.array与list的内存大小比较

    1 np array与list 比较 a 1 2 3 4 需要4个指针和四个数据 增加了存储和消耗cpu a np array 1 2 3 4 只需要存放四个数据 读取和计算更加方便 2 np array与list所占内存 def test
  • sqlserver语言转mysql_SQLSERVER 脚本转MYSQL 脚本的方法总结

    标签 1 MYSQL中SQL脚步都要以分号 结尾 这点比SQLSERVER要严谨 2 所有关键字都要加上 比如 Status 替换成 Status 按是有个 的键 3 SQLSERVER的dbo 在mysql中不支持 都要去掉 4 isnu
  • java field static_Java基础之关键字static

    static是Java中的一个关键字 用来修饰成员变量与成员方法 还可以用于编写静态代码块 对于被static修饰的东西 JVM在加载类的时候 就给这些变量在内存中分配了一定的空间 即在编译阶段时就为这些成员变量的实例分配了空间 一 静态变
  • 机器学习入门之流浪地球

    机器学习入门之流浪地球 1 引言 2 问题描述 3 问题分析 4 问题求解 4 1 数据集 4 2 模型构造 4 3 损失函数 4 4 梯度下降 4 5 模型训练 4 6 预测 4 7 完整实现代码 5 总结与思考 1 引言 我国里程碑式科
  • 求n边形周长的k等分点坐标(今日头条)

    题目 本题来自今天头条的笔试 有一个n边形 P0 P1 Pn 每一条边皆为垂直或水平线段 现给定数值k 以P0为起点将n边形的周长分为k段 每段的长度相等 请打印出k等分点的坐标 T0 T1 Tk 的坐标 分析 1 可以计算出从第0个点 到
  • 线程池ExecutorService

    1 线程池创建方式 1 通过Executors创建线程池 import java util concurrent ExecutorService import java util concurrent Executors public cl
  • Ubuntu18.04未安装Qt报qt.qpa.plugin could not load the Qt platform plugin xcb问题的解决方法

    在Ubuntu 18 04开发机上安装了Qt 5 14 2 当将其可执行程序拷贝到另一台未安装Qt的Ubuntu 18 04上报错 拷贝可执行程序前 使用ldd将此执行程序依赖的动态库也一起拷贝过去 包括Qt5 14 2 5 14 2 gc
  • JS ES6 单链表2种插入尾部方式

    一种是类里加一个指向尾部最后一个元素指针 通过他添加一个元素到队列最后 一种是每次增一个元素都从头开始遍历直到最后一个 然后添加 打开出来有单链表结构是一样的 除了上面的 多了一个队尾指针 class Node 单个结点 data next
  • Cadence 生成gerber文件,嘉立创下单助手解析不了PCB板的问题

    概述 最近由于公司的原因 使用Cadence EDA工具绘制一块 TMC2300电机驱动板 遇到一些问题 在这记录一下坑 也方便遇到这个问题的硬件攻城狮得到解决 1 EDA Cadence 17 4 在生成gerber文件时 使用CAM35
  • type_traits技术与C++

    引言 一个方法实现过程中 业务逻辑很多都是相似的 但是与具体的特化类型的不同有一定的差异 这个时候可以采用特化模板的方式实现 不同的类型使用不同的特化实现 但是这种情况造成一定的业务逻辑的冗余 而trait技术可以将特化类型通过封装 以一个
  • windows10进行Colmap配置

    colmap下载 https demuc de colmap 新的colmap按照官网的编译方式仅需要预装好CMake Boost QT5 CUDA和CGAL 1 CMake CMake安装最简单 去官网下载好压缩包解压即可 建议下载新版
  • 使用sentencepiece模型替换词表

    最近在用DeBERTa模型跑一些下游任务 了解到了sentencepiece模型 用于替代预训练模型中的词表 sentencepiece 是google开源的文本Tokenzier工具 本身提供四种切分方法 包括 char word byt
  • Python爬虫三国演义

    爬取三国全篇内容 定位目标 https www shicimingju com book sanguoyanyi html 在这里插入代码片import requests from bs4 import BeautifulSoup f op
  • 100天精通Python(可视化篇)——第86天:matplotlib绘制不同种类炫酷热力图参数说明+代码实战

    文章目录 专栏导读 一 热力图介绍 1 介绍 2 参数说明 二 绘制热力图 1 普通热力图 2 添加坐标轴和标题 3 添加热力标尺 4 添加色块数值
  • 虚析构和纯虚析构

    问题 多态使用时 如果子类中有属性开辟到堆区 那么父类指针在释放时无法调用到子类的析构代码 解决方式 将父类的析构改为虚析构或纯虚析构 可以解决父类指针释放子类对象 都需要具体的实现函数 虚析构和纯虚析构的区别 如果是纯虚析构 该类属于抽象
  • 【踩坑】解决maven的编译报错Cannot connect to the Maven process. Try again later

    背景 新公司新项目 同事拷给我maven的setting配置文件 跑项目编译发现maven报 Cannot connect to the Maven process Try again later If the problem persis
  • 你了解Spring BeanFactoryAware嘛

    其实再写这篇文章之前呢 我是看Spring IOC源码 可是老师啃不动 那么就从外围开始吧 在Spring生命周期的探索当中 其中网上主流的做法就是让我们的Bean实现一大波接口 到目前为止 这些接口的名称一个也没有记住 Spring的这个