Spring的扩展点及实例

Spring中让人眼前一亮的11个小技巧 我们一说到spring,可能第一个想到的是IOC(控制反转) 和AOP(面向切面编程)。没错,它们是spring的基石,得益于它们的优秀设计,使得spring能够从众多优秀框架中脱颖而出。除此之外,我们在使用spring的过程中,有没有发现它的扩展能力非常强。由于这个优势的存在,让spring拥有强大的包容能力,让很多第三方应用能够轻松投入spring的怀抱。比如:rocketmq、mybatis、redis等。今天跟大家一起聊聊,在Spring中最常用的11个扩展点。 阅读详情

概述

本文介绍的spring扩展点都是基于spring中bean的生命周期扩展的。

源码分析参考:Spring中Bean的生命周期及源码详解

Spring的扩展点分为两类:

  • 某个bean专用扩展点:这个bean通过加注解或者实现接口来实现扩展,只这个bean生效。
    • 处理ApplicationContextAware接口的回调,即处理ApplicationContextAware接口的setApplicationContext方法
    • 初始化前,即处理@PostConstruct注解的方法
    • 初始化,即处理InitializingBean接口的afterPropertiesSet方法
  • 某些个bean的通用扩展点:通过实现可扩展接口来实现,所有的bean生效。
    • BeanFactoryPostProcessor:Spring容器启动时会将bean信息注册到BeanDefinition中,而BeanFactoryPostProcessor是一个扩展点,修改、新增BeanDefinition中的bean定义信息,添加自定义的元数据
    • BeanPostProcessor:BeanPostProcessor是应用于bean初始化前后的扩展点。Spring中的Aware接口回调、bean初始化前(InitializingBean.beforeInit)、bean初始化后(AOP代理对象创建)都是通过Spring内置的BeanPostProcessor实现的
    • FactoryBean:FactoryBean是一种特殊的bean,它是一个bean工厂,负责生产其他bean,当生产Bean的过程复杂时,会用到它。

专用扩展点比较简单,这里只说通用扩展点。

BeanFactoryPostProcessor

正常Spring启动的时候会扫描所有的bean,将bean的定义存储在BeanDefinition中。
然后根据BeanDefinition中bean定义的信息实例化单例非延时加载的bean。

BeanFactoryPostProcessor是Spring框架中用于在容器实例化Bean之前修改Bean定义的接口。它在Bean实例化之前运行,因此主要用于修改Bean定义和配置,而不是实际的Bean实例。它是一个非常强大的工具,可用于在容器启动时修改Bean定义、动态注册Bean以及实现条件化的Bean注册,以满足应用程序的特定需求。

源码分析

Spring容器的启动入口都是org.springframework.context.support.AbstractApplicationContext#refresh

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				//看名字就能看出来这是处理BeanFactoryPostProcessors,这里是先扫描bean,把bean的信息注册到BeanDefinition,然后处理BeanFactoryPostProcessors
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.		//实例化单例非延时加载的bean
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

然后执行org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.List<org.springframework.beans.factory.config.BeanFactoryPostProcessor>)

这个方法里关注两个方法:

  • org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(java.util.Collection<? extends org.springframework.beans.factory.config.BeanFactoryPostProcessor>, org.springframework.beans.factory.config.ConfigurableListableBeanFactory):处理BeanFactoryPostProcessors,可以修改BeanDefinition中bean定义信息。
  • org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors:将bean的信息注册到BeanDefinition中。

代码示例

BeanFactoryPostProcessor有三个扩展点:

  • 修改Bean的属性值
  • 动态注册Bean

修改Bean的属性值

测试的bean
BeanInitTest 中有myTestInfo属性,用于测试BeanFactoryPostProcessor给BeanInitTest的bean对象的myTestInfo属性赋值。

package com.ludk.weixin.service;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;

@Service
public class BeanInitTest implements ApplicationContextAware, InitializingBean {
    private String myTestInfo;

    private String myTestInfo2="初始值";
    @Autowired
    private ServiceC servicec;

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("初始化");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("ApplicationContextAware 回调方法");
    }
    @PostConstruct
    private void beforeInit(){
        System.out.println("初始化前");
    }

    public String getMyTestInfo() {
        return myTestInfo;
    }

    public void setMyTestInfo(String myTestInfo) {
        this.myTestInfo = myTestInfo;
    }

    public String getMyTestInfo2() {
        return myTestInfo2;
    }

    public void setMyTestInfo2(String myTestInfo2) {
        this.myTestInfo2 = myTestInfo2;
    }
}

BeanFactoryPostProcessor
这里给beanInitTest bean的myTestInfo属性赋值为addvalue,也加了testAttribute供其他处理器或组件使用。

package com.ludk.weixin.learn;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
@Component
public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition myBeanDefinition=beanFactory.getBeanDefinition("beanInitTest");
        //给指定bean的属性赋值
        myBeanDefinition.getPropertyValues().add("myTestInfo","addvalue");
        //自定义BeanDefinition的属性后面使用
        myBeanDefinition.setAttribute("testAttribute",true);
        System.out.println("TestBeanFactoryPostProcessor--------------------------------------");

    }
}

动态注册Bean

这个BeanFactoryPostProcessor是实现动态注册Bean的功能。
实现的是org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor接口,而这个接口继承了BeanFactoryPostProcessor接口。
这里动态注册了ServiceC的bean。

package com.ludk.weixin.learn;

import com.ludk.weixin.service.ServiceC;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;

@Component
public class TestBeanFactoryPostProcessor2 implements BeanDefinitionRegistryPostProcessor {


    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        //动态注册ServiceC的Bean
        BeanDefinitionBuilder builder=BeanDefinitionBuilder.genericBeanDefinition(ServiceC.class);
        AbstractBeanDefinition beanDefinition=builder.getBeanDefinition();
        registry.registerBeanDefinition("serviceC",beanDefinition);
    }

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

    }
}

BeanInitTest 中依赖注入了ServiceC,用于验证ServiceC的bean是否动态注入成功。

package com.ludk.weixin.service;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;


@Service
public class BeanInitTest implements ApplicationContextAware, InitializingBean {
    private String myTestInfo;

    private String myTestInfo2="初始值";
    //用于验证动态注入
    @Autowired
    private ServiceC servicec;

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("初始化");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("ApplicationContextAware 回调方法");
    }
    @PostConstruct
    private void beforeInit(){
        System.out.println("初始化前");
    }

    public String getMyTestInfo() {
        return myTestInfo;
    }

    public void setMyTestInfo(String myTestInfo) {
        this.myTestInfo = myTestInfo;
    }

    public String getMyTestInfo2() {
        return myTestInfo2;
    }

    public void setMyTestInfo2(String myTestInfo2) {
        this.myTestInfo2 = myTestInfo2;
    }
}

如何验证上面ServiceC的bean是动态注册的呢?
定义下面的ServiceC时不加@Service等注解,让Spring认为ServiceC不是一个归于Spring管理的bean。这样扫描bean到BeanDefinition中时就没有ServiceC的bean定义。

package com.ludk.weixin.service;


public class ServiceC {
    private String a;

    public String getA() {
        return a;
    }

    public void setA(String a) {
        this.a = a;
    }
}

调试启动,会发现启动成功。
如果删除掉TestBeanFactoryPostProcessor2类,则没有动态注册的逻辑。启动项目发现报错,找不到ServiceC

BeanPostProcessor

BeanPostProcessor是应用于bean初始化前后的扩展点。Spring中的Aware接口回调、bean初始化前(InitializingBean.beforeInit)、bean初始化后(AOP代理对象创建)都是通过Spring内置的BeanPostProcessor实现的。

主要有两个方法

  • postProcessBeforeInitialization:bean初始化前
  • postProcessAfterInitialization:bean初始化后

postProcessBeforeInitialization

  • 功能:允许开发人员在Bean初始化之前对Bean对象进行预处理。
  • 应用:常用于执行一些初始化前的逻辑,例如:验证、属性设置、数据加载等。
  • 时机“”在Bean的属性设置之后,但在初始化方法(如init-method)之前被调用。
  • 返回值:该方法的返回值是一个对象,允许开发人员修改Bean对象的实例,甚至可以返回一个完全不同的实例对象。

postProcessAfterInitialization

  • 功能:允许开发人员在Bean初始化之后对Bean对象进行后处理。
  • 用途:通常用于执行一些初始化后的逻辑,例如:初始化之后的验证、注册、清理等。
  • 在Bean的初始化方法(如init-method)之后被调用。
  • 返回值:同样是一个对象,允许开发人员修改Bean对象的实例,但返回的对象必须是Bean对象的后代(subclass)或者相同的实例。

源码分析

参考:Spring中Bean的生命周期及源码详解

代码示例

定义一个bean,有初始化前、初始化、Aware接口实现。

package com.ludk.weixin.service;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;

@Service
public class BeanInitTest implements ApplicationContextAware, InitializingBean {

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("初始化");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("ApplicationContextAware 回调方法");
    }
    @PostConstruct
    private void beforeInit(){
        System.out.println("初始化前");
    }
}

定义一个BeanPostProcessor,专门处理上面的bean。

package com.ludk.weixin.learn;

import com.ludk.weixin.service.BeanInitTest;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class TestBeanPostProcess implements BeanPostProcessor {
	//bean初始化前方法
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof BeanInitTest){
            System.out.println("com.ludk.weixin.learn.TestBeanPostProcess.postProcessBeforeInitialization:");
        }
        return bean;
    }
	//bean初始化后方法
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof BeanInitTest){
            System.out.println("com.ludk.weixin.learn.TestBeanPostProcess.postProcessAfterInitialization:");
        }
        return bean;
    }
}

调试代码

在下面的两个位置打断点,调试启动
在这里插入图片描述
进入断点后如图:
在这里插入图片描述
运行结果:

ApplicationContextAware 回调方法
com.ludk.weixin.learn.TestBeanPostProcess.postProcessBeforeInitialization:
初始化前
初始化
com.ludk.weixin.learn.TestBeanPostProcess.postProcessAfterInitialization:

从下面代码及注释,可以看到BeanPostProcess的执行时机。

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			//处理Aware接口的回调,其中包括ApplicationContextAware接口的setApplicationContext方法的执行
			//初始化前,也包括自定义BeanPostProcess的前置方法
			//都是用BeanProcess的前置处理方法实现的
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			//初始化 ,InitializingBean接口的afterPropertiesSet方法
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
			//初始化后,包括AOP。也包括自定义BeanPostProcess的后置方法
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

如果实现org.springframework.core.Ordered接口,可以指定BeanPostProcess的执行顺序。

个人理解

BeanPostProcess会处理所有的bean,性能肯定差些。如果只有三两个bean需要特殊处理,可以用bean的初始化前、初始化方法等方式解决。

FactoryBean

FactoryBean是一种特殊的bean,它是一个bean工厂,负责生产其他bean,当生产Bean的过程复杂时,会用到它。

BeanFactory与FactoryBean

BeanFactory

org.springframework.beans.factory.BeanFactory
从源码可以看出来,它是用来获取bean的类。都是说Spring的IOC是将对象交由容器管理,BeanFactory就是容器。BeanFactory里有很多bean,用的时候可以通过getBean获取。
负责生产和管理Bean的一个工厂接口,提供一个Spring Ioc容器规范。

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

package org.springframework.beans.factory;

import org.springframework.beans.BeansException;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;

public interface BeanFactory {
    String FACTORY_BEAN_PREFIX = "&";

    Object getBean(String var1) throws BeansException;

    <T> T getBean(String var1, Class<T> var2) throws BeansException;

    Object getBean(String var1, Object... var2) throws BeansException;

    <T> T getBean(Class<T> var1) throws BeansException;

    <T> T getBean(Class<T> var1, Object... var2) throws BeansException;

    <T> ObjectProvider<T> getBeanProvider(Class<T> var1);

    <T> ObjectProvider<T> getBeanProvider(ResolvableType var1);

    boolean containsBean(String var1);

    boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;

    boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;

    @Nullable
    Class<?> getType(String var1) throws NoSuchBeanDefinitionException;

    @Nullable
    Class<?> getType(String var1, boolean var2) throws NoSuchBeanDefinitionException;

    String[] getAliases(String var1);
}

FactoryBean

org.springframework.beans.factory.FactoryBean
FactoryBean是存储在BeanFactory中的一种bean,通过FactoryBean可以获取其他一系列bean。
对于复杂的Bean对象初始化创建使用其可封装对象的创建细节。

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

package org.springframework.beans.factory;

import org.springframework.lang.Nullable;

public interface FactoryBean<T> {
    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

    @Nullable
    T getObject() throws Exception;

    @Nullable
    Class<?> getObjectType();

    default boolean isSingleton() {
        return true;
    }
}

FactoryBean实例

FactoryBean

package com.ludk.weixin.learn;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * 实现FactoryBean接口,支持泛型,重写getObject、getObjectType、isSingleton方法
 */
@Component
public class MyFactoryBean2 implements FactoryBean<ServiceI> {
    @Value("${myinfo.beanname}")
    private String beanName;
    //ServiceI 类型bean对象实例,根据配置文件中的配置不同,获取不同实例
    @Override
    public ServiceI getObject() throws Exception {
        if ("bean1".equals(beanName)){
            return new ServiceImpl1();
        }else {
            return new ServiceImpl2();
        }
    }
	//获取bean对象类型
    @Override
    public Class<?> getObjectType() {
        return ServiceI.class;
    }
	//是否是单例
    @Override
    public boolean isSingleton() {
        return true;
    }
}

根据FactoryBean获取实例

package com.ludk.weixin.controller;

import com.ludk.weixin.common.tool.RedisUtil;
import com.ludk.weixin.entity.Product;
import com.ludk.weixin.learn.MyFactoryBean;
import com.ludk.weixin.learn.ServiceBean;
import com.ludk.weixin.learn.ServiceI;
import com.ludk.weixin.service.IProductService;
import com.ludk.weixin.service.TestLockService;
import com.ludk.weixin.service.TestLockThread;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 实现ApplicationContextAware接口,在ProductController 初始化前通过setApplicationContext方法获取ServiceI 的实例,相当于将ServiceI 注入进来。
 */
@Controller
@Slf4j
@RequestMapping("/product")
public class ProductController implements ApplicationContextAware{

    @Autowired
    IProductService productService;

    @Autowired
    TestLockService testLockService;

    @Resource(type = ServiceBean.class)
    ServiceBean serviceBean;
	//无法通过依赖注入注入进来
    ServiceI serviceI;


    /**
     *测试方法
     * @param userId
     * @return
     */
    @RequestMapping("/myProduct")
    @ResponseBody
    Object myProduct(@RequestParam("userId") Long userId) throws InterruptedException {
		//测试方法
        serviceI.test();
        return "success";


    }
	//通过FactoryBean将ServiceI注入进来
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.serviceI=(ServiceI) applicationContext.getBean("myFactoryBean2");
    }
}

配置文件、ServiceI接口及ServiceI接口的两个实现类这里就不描述了。

这个例子是根据配置文件的配置不同,Controller中注入不同的ServiceI接口的实现类。

【Spring】扩展点EnvironmentPostProcessor实例详解 之前项目中用到了Apollo配置中心,对接Apollo配置中心后,配置中心的属性就可以在程序中使用了,那么这个是怎么实现的呢?配置中心的属性又是何时加载到程序中的呢?那么我们如果找到了这个是怎么实现的是否就可以 从任何地方加载配置属性、配置属性的加解密功能呢? 阅读详情

相关推荐

23. STM32F103C8T6 ADC采集光敏电阻传感器模块光照强度实战

本文详细介绍了如何使用STM32F103C8T6的ADC模块采集光敏电阻传感器的光照强度。通过硬件接线、核心原理讲解、四步代码配置(GPIO、ADC模式、使能校准、数据滤波)以及串口验证,手把手指导完成从模拟信号到数字值的完整实战流程,并重点提示了ADC时钟分频等关键配置要点。

weixin_42300144的博客 219

spring中的扩展点及其应用

spring容器启动时,会先解析BeanDefinition,然后生成BeanDefinition信息;再实例化生成bean对象,在这个过程中spring为我们提供了很多扩展点,来实现定制功能。

VivianStark的博客 1938

ros1 ubuntu22.04 安装教程

ROS1 ubuntu22.04 安装教程

autolabor的博客 9195

spring中的扩展点解析以及实践使用

这是整个spring容器在刷新之前初始化`ConfigurableApplicationContext`的回调接口,简单来说,就是在容器刷新之前调用此类的`initialize`方法。这个点允许被用户自己扩展。用户可以在整个spring容器还没被初始化之前做一些事情。

itboy 1542

通达信主力检测利器

主力轨迹:100*EMA(EMA(MTM,N1),N1)/EMA(EMA(ABS(MTM),N1),N1),COLORWHITE;主力拉高:IF(VAR51<REF(VAR51,1),VAR51,0),COLORYELLOW,NODRAW;洗盘:IF(VAR5<REF(VAR5,1),VAR5,0),COLOR000079,NODRAW;主力进场:IF(VAR5>REF(VAR5,1),VAR5,0),COLORRED,NODRAW;MAZL:MA(主力轨迹,N2),COLORYELLOW;

zhibiaogong的博客 7453

差分运放电路输出电压偏置设计解析

差分运算放大电路是信号处理中的基础模块,通过差分对管结构实现共模抑制与差模放大。其核心原理基于运放的虚短虚断特性,当电阻网络满足对称条件时,输出电压与输入差分成正比。在工业测量系统中,由于ADC通常仅支持正电压输入,需要通过偏置电路将双极性信号平移至正电压范围。典型设计采用精密基准电压源和匹配电阻网络,既保持信号完整性又满足系统接口要求。本文以-100V高压测量为例,详细解析了分压网络设计、参考电压选取以及电阻匹配等关键技术要点,为传感器接口电路设计提供实践参考。

weixin_35750747的博客 470

盘点10个Spring实际开发中最常用扩展点

Spring的核心思想就是容器,具有控制反转(IoC)和面向切面(AOP)两大核心;更是封装了Spring,遵循约定大于配置,加上自动装配的机制。很多时候我们只要引用了一个依赖,几乎是零配置就能完成一个功能的装配。一个高级开发者如果想精通Spring,不能仅仅局限于对框架的使用,而是需要对Spring进行深入理解,了解Spring对Bean是如何进行管理的,熟知Spring的各个扩展点。在网上搜索Spring扩展点,发现很少有博文说的很全的,只有一些常用的扩展点的说明。

2301_76607156的博客 924

【精细解读】xapp585(多通道LVDS接口ADC)

xapp585的参考设计有Verilog和VHDL两种源码。

FPGA艺术家的博客 532

【Spring】Spring中bean生命周期重要的四个扩展点

一.BeanDefinitionRegistryPostProcessor扩展点 1. 重写 postProcessBeanDefinitionRegistry BeanDefinitionRegistryPostProcessor 继承自 BeanFactoryPostProcessor 需要重写 postProcessBeanDefinitionRegistry 方法 2.获取BeanDefinitionRegistry,增删改BeanDefinition 能过实现 BeanDefinitionR

纸上得来终觉浅,绝知此事要躬行 3875

Open3D 计算点云的倒角距离(Chamfer Distance)【2025最新版】

;Chamfer Distance距离可以计算生成点云数据与标签点云数据之间的平均最短点距离。Open3D可以直接用来计算点云的Chamfer Distance距离。博客长期更新,本文最近一次更新时间为:2025年2月18日。

点云侠的博客 3254

12、控件使用之录入英文、阿拉伯数字删除增加功能及二维码显示

控件使用之录入英文、阿拉伯数字删除增加功能及二维码显示1、用到的控件2、添加控件2.1、添加【文本录入】控件2.1、添加【文本显示】控件2.1、添加【QR 二维码】控件3、保存工程及生成文件4、下载文件 1、用到的控件   需要用的显示控件为【文本显示】控件和【QR二维码】控件,以及触控控件【文本录入】控件。 2、添加控件 2.1、添加【文本录入】控件   【文本录入】控件也叫【ASCI 文本录入】,是用来录入ASCI 字符,打开 DGUS 软件,点击【触控控件】—【文本录入】,用鼠标框选一个区域,即可在右

嵌入式羊圈 624

Spring组件实例化扩展点:InstantiationAwareBeanPostProcessor

是 Spring 生命周期中的一个关键扩展接口,继承自。它在 Bean 的实例化阶段拦截 Bean 的实例化过程,甚至完全自定义实例化逻辑在属性填充(依赖注入)前后执行自定义操作动态修改 Bean 的定义或属性值,实现更灵活的控制与普通的不同,该接口的关注点集中在 Bean 的实例化阶段,而非初始化阶段(如或为 Spring Bean 的生命周期提供了深度的扩展能力,尤其在实例化阶段和属性注入阶段。通过合理利用其回调方法,开发者可以实现高度定制化的 Bean 管理逻辑,如动态代理、属性加密、依赖注入扩展等。

从基础到源码解析的学习记录 4134

运行 ui5 serve 命令行报错的处理方法

如果大家运行 ui5 serve 命令行,报如下的错误消息: ui5 不是内部或外部命令,也不是可运行的程序: 只需要执行命令行,全局安装 ui5 cli(command line interface)这个命令行工具即可: npm install --global @ui5/cli 这个 ui5 cli 的入口执行文件,实际安装在了我 Node.js 的安装目录下: 更多Jerry的原创文章,尽在:“汪子熙”: ...

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1340

Spring Boot 中关于 Bean 加载、实例化、初始化全生命周期的扩展点

核心作用:执行 Bean 专属的初始化逻辑执行时机:BeanPostProcessor 前置处理后 → 后置处理前优先级实战示例:3 种初始化方法对比java体验AI代码助手代码解读复制代码@Component// 方式 1:@PostConstruct 注解(最常用)System.out.println("UserService @PostConstruct 初始化");// 方式 2:实现 InitializingBean 接口@Override。

fuladulu的博客 270

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

Spring 5.x 源码之旅三十五之实例化之前和初始化之后扩展点

Spring 5.x 源码之旅三十五getBean处理器扩展点一处理器扩展点流程图resolveBeforeInstantiation实例化之前-扩展点一applyBeanPostProcessorsBeforeInstantiation实例化之前applyBeanPostProcessorsAfterInitialization初始化扩展点实战MyInstantiationAwareBeanPo...

王伟王胖胖的博客 1096

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Spring 5.x 源码之旅-35之实例化之前和初始化之后扩展点

先把这个图送上,在创建bean的过程中基本就是这些了,可能还有其他地方我漏了,看到的大神提醒下啊,下次补。然后我们一个个来将下这些扩展点能做什么。这个主要是前面如果有返回不为空的,就会执行这个来初始化。接口的处理器处理,比如可以把一个对象替换成另外一个。我们来试试刚才的扩展点,我想把。

smart_an的专栏 548

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Spring 中的扩展点

Spring框架中的BeanDefinitionRegistryPostProcessor、BeanFactoryPostProcessor和BeanPostProcessor是三个核心扩展点,分别在容器启动的不同阶段发挥作用。BeanDefinitionRegistryPostProcessor(继承自BeanFactoryPostProcessor)允许动态注册Bean定义,优先于其他处理器执行;BeanFactoryPostProcessor在Bean定义注册完成后、实例化前修改配置;BeanPost

红血哥 1254

Spring容器扩展点(Container Extension Points)

容器扩展点的概念 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Spring的IoC部分被设计成可扩展的。应用程序开发者通常不需要继承各种各样的BeanFactory或者ApplicationContext的实现类(BeanFactory和ApplicationContext都是接口)。通过插入(plug

码农无双的博客 4988

Spring IoC容器初始化源码(6)—finishBeanFactoryInitialization实例化Bean的整体流程以及某些扩展点【两万字】

基于最新Spring 5.x,详细介绍了finishBeanFactoryInitialization方法的整体流程和部分源码解析,比如DependsOn依赖校验、FactoryBean的特殊获取模式,以及SmartInitializingSingleton、FactoryBean 、SmartFactoryBean扩展点。

终生学习践行者 5158

Spring 5.x 源码之旅三十八之实例化后扩展点

Spring 5.x 源码之旅三十八getBean处理器扩展点四图不能少InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation扩展实战MyConfigNoPopulateBean测试代码MyInstantiationAwareBeanPostProcessor 图不能少 InstantiationAwareBeanPos...

王伟王胖胖的博客 343

聊聊Spring扩展点BeanPostProcessor和BeanFactoryPostProcessor

今天聊一聊spring中很重要的两个扩展点BeanPostProcessor和BeanFactoryPostProcessor,spring之所以如次强大,是因为它提供了丰富的功能给我们使用,但是我觉得最强大的是它扩展点,因为有了各种扩展点,我们才能去开发一些自己的需求,一个框架的强大之处也在于它能否灵活的配置,能够支持很好的扩展。

m88997766的博客 172

Spring扩展点之BeanFactoryPostProcessor:彻底搞懂原理以及使用场景【源码分析】

spring框架流行了这么多年,地位至今不被动摇,除了spring全家桶的生态之外,它给开发者的提供的扩展也是值得一提的。那么今天就来聊聊Spring扩展点之BeanFactoryPostProcessor。 这个扩展点是发生在bean实例化之前,BeanDefinition读取完之后。所以我们在这里可以获取到BeanDefinition,以改变他默认的实例化方式。 由于文章内容是基于源码角度来讲的,考虑到有些朋友不需要看的如此的深入,所以在此贴出其简单的使用方式:加上@Component注解,使其加入到s

CoderOu 1万+

Spring中Bean的生命周期

文章目录Spring生命周期与扩展点(图)生命周期扩展点(钩子函数)生命周期扩展点Aware类型扩展点容器级扩展点总结 Spring生命周期与扩展点(图) Bean的生命周期有两个主要方面,一是生命周期的主要阶段(绿色),一是扩展点(粉色、橘黄色)(用于在生命周期的某个阶段进行自定义扩展)   生命周期 Bean的生命周期本质上就是一系列方法的调用执行,把它划分为四个主要阶段是为了方便我们理解。在Bean被创建完成可供使用前,需要经历实例化、属性赋值、初始化三个重要阶段。当Bean不再需要时,会

Pinker_Q 574

Spring 扩展点总结与分析

明确阶段:根据业务需求选择最靠近目标阶段的扩展点(如修改 Bean 定义用 BeanFactoryPostProcessor 而非 BeanPostProcessor)。 避免副作用:确保扩展逻辑不影响 Spring 原生生命周期(如 BeanPostProcessor 中避免过早初始化其他 Bean)。 性能优先:高频扩展点(如 BeanPostProcessor)应减少阻塞操作,必要时采用懒加载或异步处理。 兼容性:自定义扩展需考虑 Spring 版本差异(如 ApplicationContextIni

肢解生活,直达本质;凡所有相,皆是虚妄。 1221

Spring Bean的生命周期和循环依赖

Spring Bean的完整生命周期从创建Spring容器开始,直到最终Spring容器销毁

非学无以广才,非志无以成学 408

Spring 5.x 源码之旅-38之实例化后扩展点

作者简介:大家好,我是哥,前中兴通讯、美团架构师,现某互联网公司联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬学习必须往深处挖,挖的越深,基础越扎实!

smart_an的专栏 434
上一篇: Redission源码详解
ludkjava
博客等级 码龄11年 173粉丝 32原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值