spring 详解三 IOC(spring实例化及后处理器)

news2025/1/12 17:19:38

Spring实例化基本流程

Spring在容器初始化的时候,读取XMl配置,将其封装成BeanDefinition(Bean定义)对象,描述所有bean的信息

BeanDefinition会注册存储到beanDefinitionMap集合中

Spring框架遍历beanDefinitionMap,使用反射创建Bean实例对象

创建好之后的对象存储在singletonObjects的map集合中,当getBean时,从该map中取出实例bean对象返回

Spring配置文件中的配置项都能在BeanDefinition对象中找到 

BeanDefinition是一个接口,我们使用RootBeanDefinition即可

 Spring中的两个后处理器

Spring中提供两个后处理器,让我们能够介入实例化流程,动态注册BeanDefinition,动态修改BeanDefinition,以及动态修改Bean的作用

BeanFactoryPostProcessor:Bean工厂后处理器,在beanDefinitionMap填充完毕,还未反射创建对象之前执行

BeanPostProcessor:Bean后处理器 ,在Bean实例化之后,填充至singletonObjects之前执行,一但添加至singletonObjects意味着不能改变

一个在还未创建对象之前,一个在创建对象之后

Bean工厂后处理器 BeanFactoryPostProcessor

BeanFactoryPostProcessor是一个接口,实现了该接口的类只要交由spring容器管理的话,那么spring就会回调该接口的方法,用于对BeanDefinition注册和修改

package com.tech.test.processor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;

public class MyBeanFactoryProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("BeanDefinitionMap填充完毕之后执行该方法");
        // 创建一个BeanDefinition 
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
        rootBeanDefinition.setBeanClassName("com.tech.test.test.bean.DI");
        // 查看继承关系图ConfigurableListableBeanFactory就是DefaultListableBeanFactory
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
        // 注册Bean
        defaultListableBeanFactory.registerBeanDefinition("userService",rootBeanDefinition);
        
    }
}
 <bean id="userService"  name="aaa,bbb"  class="com.tech.test.service.impl.UserServiceImpl" ></bean>
<bean  class="com.tech.test.processor.MyBeanFactoryProcessor "></bean>

需要在配置文件中配置交给spring管理,这个示例 我们动态的修改对象userService为DI对象,当我们getBean时,Bean已经被修改为DI对象

spring提供了专门注册BeanDefinitionMap的接口,BeanDefinitionRegistryPostProcessor,看下继承关系,它是BeanFactoryPostProcessor 的子接口

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.beans.factory.support;

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

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
    void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry var1) throws BeansException;
}

演示相同功能 

package com.tech.test.processor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;

public class MyNoCastProcessor implements BeanDefinitionRegistryPostProcessor {

    // 执行顺序早于postProcessBeanFactory 简记为 谁在上边谁先执行
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        // 创建一个BeanDefinition
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
        rootBeanDefinition.setBeanClassName("com.tech.test.test.bean.DI");
        // 注册Bean
        beanDefinitionRegistry.registerBeanDefinition("userService",rootBeanDefinition);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }
}
<bean id="userService"  name="aaa,bbb"  class="com.tech.test.service.impl.UserServiceImpl" ></bean>

<bean id="process" class="com.tech.test.processor.MyNoCastProcessor"></bean>

示例:定义自定义注解实现注册对象,配置就不列举啦,需要在对象未创建之前加入Bean定义信息

自定义注解

package com.tech.test.anotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyComponent {

    String value();
}

 加上注解

package com.tech.test.testbean;


import com.tech.test.anotation.MyComponent;

@MyComponent("ceshi")
public class TestAnnotation {
}

 解析注解

package com.tech.test.processor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;

public class ParseMyComponentProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        // 这里的全限定类名和注解中的名称应该扫描包得到,这里暂时写死
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
        rootBeanDefinition.setBeanClassName("com.tech.test.testbean.TestAnnotation");
        beanDefinitionRegistry.registerBeanDefinition("ceshi",rootBeanDefinition);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }
}

 测试注解

package com.tech.test.springtest;

import com.tech.test.testbean.DI;
import com.tech.test.testbean.TestAnnotation;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestParseAnnotation {

    public static void main(String[] args) {
        // 创建ApplicationContext,加载配置文件,实例化容器
        ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 获取Bean
        TestAnnotation testAnnotation = classPathXmlApplicationContext.getBean(TestAnnotation.class);

        System.out.println(testAnnotation);
    }
}

Bean后处理器BeanPostProcessor

Bean后处理器 ,在Bean实例化之后,填充至singletonObjects之前执行,一但添加至singletonObjects意味着不能改变

 示例:为spring中的Bean执行方法添加时间,执行开始之前加入时间,执行之后加入时间,这里使用jdk动态代理做增强

package com.tech.test.processor;

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

import java.lang.reflect.Proxy;
import java.util.Date;

public class MyBeanProcessor implements BeanPostProcessor {


    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

        Object proxyBean = Proxy.newProxyInstance(
                bean.getClass().getClassLoader(),
                bean.getClass().getInterfaces(),
                (proxy, method, args) -> {
                    System.out.println("方法" + method.getName() + "开始时间" + new Date());

                    // 执行目标方法
                    Object invoke = method.invoke(bean, args);

                    System.out.println("方法" + method.getName() + "结束时间" + new Date());
                    return invoke;
        });
        return proxyBean;
    }
}
<bean  class="com.tech.test.processor.MyBeanProcessor"></bean>

测试结果

package com.tech.test.springtest;

import com.tech.test.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestApplicationContext {
    public static void main(String[] args) {

        ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

        UserService userService =(UserService) classPathXmlApplicationContext.getBean("userService");


        userService.getUser();

    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/732825.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

pycharm如何给一串中文快捷加引号(方法二)

点击上方“Python爬虫与数据挖掘”&#xff0c;进行关注 回复“书籍”即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 商人重利轻别离&#xff0c;前月浮梁买茶去。 大家好&#xff0c;我是皮皮。 一、前言 前几天在Python白银群【此类生物】问了一个Pycharm基础的问题&a…

SpringBoot配置动态定时任务

1.配置ScheduledTask 主要是实现SchedulingConfigurer&#xff0c;动态传入cron。 package com.hzl.boot.config;import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Propert…

使用promise函数封装post请求,封装aes加解密方法,并进行请求头aes加密,封装sm2国密加解密,进行请求体数据加密,响应数据解密。

export default {async post(url, params { header:{}, data:{} }, showLoading true){if(showLoading){uni.showLoading({title:"加载中",mask:true})}let options{header:{...params.header},url:globalParams.basepathurl.url,data:{...params.data}}//渠道 ae…

Devops系列五(CI篇之pipeline libraray)jenkins将gitlab helm yaml和argocd 串联,自动部署到K8S

一、说在前面的话 本文是CI篇的上文&#xff0c;因为上一篇已经作了总体设计&#xff0c;就不再赘述&#xff0c;有需要的请看前文。 我们将演示&#xff0c;使用CI工具–jenkins&#xff0c;怎么和CD工具–argocd串联&#xff0c;重点是在Jenkins该怎么做。准备工作和argocd等…

C++常用库函数 5.输入和输出函数

函数名&#xff1a;fclose 函数原型&#xff1a;int fclose(FILE *stream)&#xff1b; 参数&#xff1a;streamFILE 结构的指针。 所需头文件&#xff1a;<cstdio> 返回值&#xff1a;如果该流成功关闭&#xff0c;fclose 返回0。如果出错&#xff0c;则返回 EOF。 功…

AI在金融领域的应用

AI金融领域 信贷业务 个人信贷单笔数额小、数量大&#xff0c;需要大量的人力和时间投入&#xff0c;信贷审核的数据也呈现出分散化、碎片化的特点。同时传统金融机构和互联网金融公司的风控环节中&#xff0c;普遍存在信息不对称、成本高、时效性差、效率低等问题&#xff0c…

动态规划之343 整数拆分(第6道)

题目&#xff1a; 给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0c;并使这些整数的乘积最大化。 返回 你可以获得的最大乘积 。 示例&#xff1a; 解法&#xff1a; 其实可以从1开始遍历 j &#xff0c;然后有两种…

Mysql之视图,索引,备份与恢复

目录 一&#xff0c;视图 1.视图是什么&#xff1f; 2.视图的重要性&#xff1f; 3.那些地方使用视图&#xff1f; 4.基本语法 二&#xff0c;索引 1.索引是什么&#xff1f; 2.索引的重要性&#xff1f; 3.索引的种类&#xff1a; 4.那些地方使用索引&#xff1f; 5.…

Gateway服务集成Nacos2021.0.4错误解决

问题 gateway服务集成nacos&#xff0c;启动后报错&#xff1a; Caused by: com.alibaba.nacos.shaded.io.grpc.netty.shaded.io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information:; 版本&#xff1a; jdk:1.8 spring-b…

10_Linux中断

目录 Linux中断API函数 中断号 上半部与下半部 软中断 tasklet 工作队列 设备树中断信息节点 获取中断号 修改设备树文件 按键中断驱动程序编写 编写测试APP Linux中断API函数 先来回顾一下裸机实验里面中断的处理方法: 1.使能中断,初始化相应的寄存器。 2.注册中…

windows配置启动若依前后端项目

一、后端 1、环境准备 JDK8、Redis、Mysql、Maven【并配置镜像源】 以上工具全部使用msi/exe安装&#xff0c;并勾选添加到环境变量&#xff0c;如果没有添加到环境变量可以参考其他博主关于每种怎么配置的情况 mysql新增一个目录名为ry-vue的空数据库 2、前往若依官网下载…

MAC M1上docker rocketmq简单环境搭建和代码

工作了这么多年&#xff0c;rocketmq还没有用过&#xff0c;由于现在的工作中涉及到了&#xff0c;周六吃完午饭就开始搞&#xff0c;结果到现在3点钟才把环境弄好&#xff0c;测试代码搞起。 整个流程分成两步 安装简单的rocket环境起springboot项目测试 参考文章&#xff…

C++STL库常用库函数总结

文章目录 1.vector, 变长数组&#xff0c;倍增的思想 size() 返回元素个数empty() 返回是否为空clear() 清空front()/back() 访问第一个元素/最后一个元素push_back()/pop_back() 插入/弹出最后一个元素begin()/end() 开始元素迭代器/结尾元素迭代器[]支持…

【kafka面试题2】如何保证kafka消息的顺序性

【kafka面试题】如何保证kafka消息的顺序性 一、整体策略 如何保证kafka消息的顺序性呢&#xff0c;其实整体的策略就是&#xff1a;我们让需要有序的消息发送到同一个分区Partition。 为什么说让有序的消息发送到同一个分区Partition就行呢&#xff0c;&#xff0c;下面我们…

tidb之旅——生成列

作者&#xff1a; 有猫万事足 原文来源&#xff1a; https://tidb.net/blog/15d0fbf6 新的问题 之前弄好了TiDB集群&#xff0c;也弄好了dm集群&#xff0c;把写入流量整个切入了TiDB集群运行起来了。但是有个别比较大的日志表&#xff0c;OLAP查询的表现还是不太行。正好7…

Node中的模块引擎EJS

1.安装EJS 2.导入EJS const ejsrequire("ejs") 3.使用ejs渲染 let outer"法外狂徒" let resultejs.render(我是<%outer %>,{outer:outer}) let str我是<%outer %> let resultejs.render(str,{outer:outer}) 说明&#xff1a; 在模板中&#xf…

SpringBoot前后端分离项目,打包、部署到服务器详细图文流程

文章目录 实施步骤一、修改配置文件地址1.修改MySQL配置2.修改Redis配置3.修改日志路径和字符集配置 二、将源码压缩并上传服务器1.上传前端文件2.上传后端文件&#xff08;同上&#xff09; 三、前端项目打包1.安装依赖2.项目打包 四、后端项目打包1.项目打包&#xff08;jar包…

【软件架构设计】支持大规模系统的设计模式和原则

今天&#xff0c;即使是小型初创公司也可能不得不处理数 TB 的数据或构建支持每分钟&#xff08;甚至一秒钟&#xff01;&#xff09;数十万个事件的服务。所谓“规模”&#xff0c;通常是指系统应在短时间内处理的大量请求/数据/事件。 尝试以幼稚的方式实现需要处理大规模的服…

Linux(Ubuntu)+Qt+C++与OpenCV窗体程序使用

程序示例精选 Linux(Ubuntu)QtC与OpenCV窗体程序使用 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对<<Linux(Ubuntu)QtC与OpenCV窗体程序使用>>编写代码&#xff0c;代码整洁&am…

ChatGPT实战:短视频文案、脚本创作

你还在拼脑力输出视频脚本吗&#xff1f;AI时代&#xff0c;该提高提高生产力了&#xff0c;机器一天的视频出货量能赶上以往几个月的工作量&#xff0c;人力怎么可能卷的过机器&#xff1f; 使用ChatGPT创作视频脚本可以带来一些好处&#xff1a; 创意激发&#xff1a;ChatGPT…