手写Spring:第7章-实现应用上下文
文章目录
- 一、目标:实现应用上下文
 - 二、设计:实现应用上下文
 - 三、实现:实现应用上下文
 - 3.1 工程结构
 - 3.2 Spring应用上下文和Bean对象扩展类图
 - 3.3 对象工厂和对象扩展接口
 - 3.3.1 对象工厂扩展接口
 - 3.3.2 对象扩展接口
 
- 3.4 定义应用上下文
 - 3.4.1 定义上下文接口
 - 3.4.2 配置应用上下文接口
 - 3.4.3 应用上下文抽象类实现
 - 3.4.4 获取Bean工厂和加载资源
 - 3.4.5 上下文中对配置信息的加载
 - 3.4.6 应用上下文实现类
 
- 3.5 对象定义读取方法添加
 - 3.5.1 对象定义读取接口
 - 3.5.2 XML处理对象注册修改
 
- 3.6 对象工厂整合应用上下文
 - 3.6.1 配置Bean工厂接口
 - 3.6.2 抽象的Bean工厂基类
 - 3.6.3 配置列表Bean工厂接口
 - 3.6.4 默认的Bean工厂实现类
 - 3.6.5 Bean工厂超类接口
 - 3.6.6 在Bean创建时完成前置和后置处理
 
- 四、测试:实现应用上下文
 - 4.1 配置测试环境
 - 4.1.1 修改UserService用户对象
 - 4.1.2 实现BeanFactoryPostProcessor
 - 4.1.3 实现BeanPostProcessor
 - 4.1.4 基础配置,无BeanFactoryPostProcessor、BeanPostProcessor实现类
 - 4.1.5 增强配置,有BeanFactoryPostProcessor、BeanPostProcessor实现类
 
- 4.2 单元测试
 - 4.2.1 不使用应用上下文测试
 - 4.2.2 使用应用上下文
 
- 五、总结:实现应用上下文
 
一、目标:实现应用上下文
💡 如何在 Spring 接口的实现中获取 BeanFactory 以及 Bean 对象内容,并对这些内容做一些操作呢?
- 在开发基于 Spring 的技术组件时,你一定会继承或者实现了 Spring 对外暴露的类或接口,在接口的实现中获取 BeanFactory 以及 Bean 对象等内容,并对这些内容做一些操作。 
- 例如:修改 Bean 的信息,添加日志打印、处理数据库路由对数据源的切换、给 RPC 服务连接注册中心等。
 
 - 在对容器中 Bean 的实例化过程添加扩展机制的同时,还需要把目前关于 
spring.xml初始化和加载策略进行优化。- 因为我们不太可能让面向 Spring 本身开发的 
DefaultListableBeanFactory服务,直接给予用户使用。 
 - 因为我们不太可能让面向 Spring 本身开发的 
 

DefaultListableBeanFactory、XmlBeanDefinitionReader,是我们在目前 Spring 框架中对于服务功能测试的使用方式,它能很好的体现出 Spring 是如何对xml加载以及注册 Bean 对象的操作过程,但这种方式是面向 Spring 本身的,还不具备一定的扩展性。- 我们现在需要提供出一个可以在 Bean 初始化过程中,完成对 Bean 对象的扩展时,就很难做到自动化处理。 
- 所以我们要把 Bean 对象扩展机制功能和对 Spring 框架上下文的包装融合起来,对外提供完整的服务。
 
 
二、设计:实现应用上下文
💡 技术设计:实现应用上下文
- 为了满足:在 Bean 对象从注册到实例化的过程中执行用户的自定义操作。 
- 需要在 Bean 的定义和初始化过程中插入接口类,这个接口再由外部去实现自己需要的服务。再结合对 Spring 框架上下文的处理能力。
 
 

- 满足于对 Bean 对象扩展的两个接口,其实也是 Spring 框架中具有重量级的两个接口:
BeanFactoryPostProcessor和BeanPostProcessor,也几乎是在使用 Spring 框架额外新增开发自己组件需求的两个必备接口。 BeanFactoryPostProcessor:是由 Spring 框架组件提供的容器扩展机制,允许在 Bean 对象注册后但未实例化之前,对 Bean 的定义信息BeanDefinition执行修改操作。BeanPostProcessor:也是 Spring 提供的扩展机制,不过BeanPostProcessor是在 Bean 对象实例化之后修改 Bean 对象,也可以替换 Bean 对象。这部分与后面的 AOP 密切相关。- 设计:开发 Spring 的上下文操作类,把相应的 XML 加载、注册、实例化以及新增的修改和扩展都融合进去,让 Spring 可以自动扫描到我们的新增服务,便于用户使用。
 
三、实现:实现应用上下文
3.1 工程结构
spring-step-06
|-src|-main|	|-java|		|-com.lino.springframework|			|-beans|			|	|-factory|			|	|	|-config|			|	|	|	|-AutowireCapableBeanFactory.java|			|	|	|	|-BeanDefinition.java|			|	|	|	|-BeanFactoryPostProcessor.java|			|	|	|	|-BeanPostProcessor.java|			|	|	|	|-BeanReference.java|			|	|	|	|-ConfigurableBeanFactory.java|			|	|	|	|-SingletonBeanRegistry.java|			|	|	|-support|			|	|	|	|-AbstractAutowireCapableBeanFactory.java|			|	|	|	|-AbstractBeabDefinitionReader.java|			|	|	|	|-AbstractBeabFactory.java|			|	|	|	|-BeabDefinitionReader.java|			|	|	|	|-BeanDefinitionRegistry.java|			|	|	|	|-CglibSubclassingInstantiationStrategy.java|			|	|	|	|-DefaultListableBeanFactory.java|			|	|	|	|-DefaultSingletonBeanRegistry.java|			|	|	|	|-InstantiationStrategy.java|			|	|	|	|-SimpleInstantiationStrategy.java|			|	|	|-support|			|	|	|	|-XMLBeanDefinitionReader.java|			|	|	|-BeanFactory.java|			|	|	|-ConfigurableListableBeanFactory.java|			|	|	|-HierarcgicalBeanFactory.java|			|	|	|-ListableBeanFactory.java|			|	|-BeansException.java|			|	|-PropertyValue.java|			|	|-PropertyValues.java|			|-context|			|	|-support|			|	|	|-AbstractApplicationContext.java|			|	|	|-AbstractRefreshableApplicationContext.java|			|	|	|-AbstractXmlApplicationContext.java|			|	|	|-ClassPathXmlApplicationContext.java|			|	|-ApplicationContext.java|			|	|-ConfigurableApplicationContext.java|			|-core.io|			|	|-ClassPathResource.java|			|	|-DefaultResourceLoader.java|			|	|-FileSystemResource.java|			|	|-Resource.java|			|	|-ResourceLoader.java|			|	|-UrlResource.java|			|-util|			|	|-ClassUtils.java|-test|-java|-com.lino.springframework.test|-bean|	|-UserDao.java|	|-UserService.java|-common|	|-MyBeanFactoryPostProcessor.java|	|-MyBeanPostProcessor.java|-ApiTest.java|-resources|-important.properties|-spring.xml|-springPostProcessor.xml
 
3.2 Spring应用上下文和Bean对象扩展类图

- 在整个类图中主要体现出来的是关于 Spring 应用上下文以及对 Bean 对象扩展机制的实现。
 - 以继承了 
ListableBeanFactory接口的ApplicationContext接口开始,扩展出一系列应用上下文的抽象实现类,并最终完成ClassPathXmlApplicationContext类的实现。而这个类就是最后交给用户使用的类。 - 同时在实现应用上下文的过程中,通过定义接口:
BeanFactoryPostProcessor、BeanPostProcessor两个接口,把关于 Bean 的扩展机制串联进去。 
3.3 对象工厂和对象扩展接口
3.3.1 对象工厂扩展接口
BeanFactoryPostProcessor.java
package com.lino.springframework.beans.factory.config;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.ConfigurableListableBeanFactory;/*** @description: 允许自定义修改 BeanDefinition 属性信息*/
public interface BeanFactoryPostProcessor {/*** 在所有的 BeanDefinition 加载完成后,实例化 Bean 对象之前,提供修改 BeanDefinition 属性的机制** @param beanFactory 对象工厂* @throws BeansException 对象异常*/void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
 
- 这个接口是满足于在所有的 
BeanDefinition加载完成后,实例化 Bean 对象之前,提供修改BeanDefinition属性的机制。 
3.3.2 对象扩展接口
BeanPostProcessor.java
package com.lino.springframework.beans.factory.config;import com.lino.springframework.beans.BeansException;/*** @description: 用于修改新实例化 Bean 对象的扩展点*/
public interface BeanPostProcessor {/*** 在 Bean 对象执行初始化方法之前,执行此方法** @param bean     对象* @param beanName 对象名称* @return 新对象* @throws BeansException 对象异常*/Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;/*** 在 Bean 对象执行初始化方法之后,执行此方法** @param bean     对象* @param beanName 对象名称* @return 新对象* @throws BeansException 对象异常*/Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
 
- 提供了修改新实例化 Bean 对象的扩展点。
 - 此接口提供了两个方法。 
postProcessBeforeInitialization:用于在 Bean 对象执行初始化方法之前,执行此方法。postProcessAfterInitialization:用于在 Bean 对象执行初始化方法之后,执行此方法。
 
3.4 定义应用上下文
3.4.1 定义上下文接口
ApplicationContext.java
package com.lino.springframework.context;import com.lino.springframework.beans.factory.ListableBeanFactory;/*** @description: 应用上下文接口*/
public interface ApplicationContext extends ListableBeanFactory {
}
 
context是本次实现应用上下文功能新增的服务包。ApplicationContext,继承于ListableBeanFactory,也就是继承了关于BeanFactory方法。比如一些getBean的方法。- 另外 
ApplicationContext本身是Central接口,后续会扩展。 
- 另外 
 
3.4.2 配置应用上下文接口
ConfigurableApplicationContext.java
package com.lino.springframework.context;import com.lino.springframework.beans.BeansException;/*** @description: SPI 接口配置应用上下文*/
public interface ConfigurableApplicationContext extends ApplicationContext {/*** 刷新容器** @throws BeansException 对象异常*/void refresh() throws BeansException;
}
 
ConfigurableApplicationContext继承自ApplicationContext,并提供了refresh这个核心方法。- 接下来也是需要在上下文的实现中完成刷新容器的操作过程。
 
3.4.3 应用上下文抽象类实现
AbstractApplicationContext.java
package com.lino.springframework.context.support;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.ConfigurableListableBeanFactory;
import com.lino.springframework.beans.factory.config.BeanFactoryPostProcessor;
import com.lino.springframework.beans.factory.config.BeanPostProcessor;
import com.lino.springframework.context.ConfigurableApplicationContext;
import com.lino.springframework.core.io.DefaultResourceLoader;
import java.util.Map;/*** @description: 抽象应用上下文*/
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {@Overridepublic void refresh() throws BeansException {// 1.创建 BeanFactory,并加载 BeanDefinitionrefreshBeanFactory();// 2.获取 BeanFactoryConfigurableListableBeanFactory beanFactory = getBeanFactory();// 3.在 Bean 实例化之前,执行 BeanFactoryPostProcessinvokeBeanFactoryPostProcessor(beanFactory);// 4.BeanPostProcessor 需要提前与其他 Bean 对象实例化之前执行注册操作registerBeanPostProcessor(beanFactory);// 5.提前实例化单例 Bean 对象beanFactory.preInstantiateSingletons();}/*** 创建 BeanFactory,并加载 BeanDefinition** @throws BeansException 异常*/protected abstract void refreshBeanFactory() throws BeansException;/*** 获取对象工厂** @return 配置列表 Bean工厂接口*/protected abstract ConfigurableListableBeanFactory getBeanFactory();private void invokeBeanFactoryPostProcessor(ConfigurableListableBeanFactory beanFactory) {Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()) {beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);}}private void registerBeanPostProcessor(ConfigurableListableBeanFactory beanFactory) {Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {beanFactory.addBeanPostProcessor(beanPostProcessor);}}@Overridepublic <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {return getBeanFactory().getBeansOfType(type);}@Overridepublic String[] getBeanDefinitionNames() {return getBeanFactory().getBeanDefinitionNames();}@Overridepublic Object getBean(String name) throws BeansException {return getBeanFactory().getBean(name);}@Overridepublic Object getBean(String name, Object... args) throws BeansException {return getBeanFactory().getBean(name, args);}@Overridepublic <T> T getBean(String name, Class<T> requiredType) throws BeansException {return getBeanFactory().getBean(name, requiredType);}
}
 
AbstractApplicationContext继承DefaultResourceLoader是为了处理spring.xml配置资源的加载。- 之后是在 
refresh()定义实现过程。- 创建 BeanFactory,并加载 BeanDefinition。
 - 获取 BeanFactory。
 - 在 Bean 实例化之前,执行 BeanFactoryPostProcessor。
 - BeanPostProcessor 需要提前于其他 Bean 对象实例化之前执行注册操作。
 - 提前实例化单例 Bean 对象。
 
 - 另外把定义出来的抽象方法:
refreshBeanFactory()、getBeanFactory()由后面的继承此抽象类的其它抽象类实现。 
3.4.4 获取Bean工厂和加载资源
AbstractRefreshableApplicationContext.java
package com.lino.springframework.context.support;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.ConfigurableListableBeanFactory;
import com.lino.springframework.beans.factory.support.DefaultListableBeanFactory;/*** @description: 抽象基类刷新应用上下文*/
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {private DefaultListableBeanFactory beanFactory;@Overrideprotected void refreshBeanFactory() throws BeansException {DefaultListableBeanFactory beanFactory = createBeanFactory();loadBeanDefinitions(beanFactory);this.beanFactory = beanFactory;}private DefaultListableBeanFactory createBeanFactory() {return new DefaultListableBeanFactory();}/*** 加载Bean对象** @param beanFactory 对象工厂*/protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory);@Overrideprotected ConfigurableListableBeanFactory getBeanFactory() {return beanFactory;}
}
 
- 在 
refreshBeanFactory()中主要是获取 DefaultListableBeanFactory 的实例化以及对资源配置的加载操作loadBeanDefinitions(beanFactory).- 在加载完成后即可对 
spring.xml配置文件中 Bean 对象的定义和注册。 - 同时也包括实现了接口 
BeanFactoryPostProcessor、BeanPostProcessor的配置 Bean 信息。 
 - 在加载完成后即可对 
 - 但此时资源加载还是指只是定义了一个抽象方法:
loadBeanDefinitions(DefaultListableBeanFactory beanFactory),继续由其他抽象类继承实现。 
3.4.5 上下文中对配置信息的加载
AbstractXmlApplicationContext.java
package com.lino.springframework.context.support;import com.lino.springframework.beans.factory.support.DefaultListableBeanFactory;
import com.lino.springframework.beans.factory.xml.XMLBeanDefinitionReader;/*** @description: 抽象基类 XML 上下文*/
public abstract class AbstractXmlApplicationContext extends AbstractRefreshableApplicationContext {@Overrideprotected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {XMLBeanDefinitionReader beanDefinitionReader = new XMLBeanDefinitionReader(beanFactory, this);String[] configLocations = getConfigLocations();if (null != configLocations) {beanDefinitionReader.loadBeanDefinitions(configLocations);}}/*** 获取配置** @return 字符串列表*/protected abstract String[] getConfigLocations();
}
 
- 在 
AbstractXmlApplicationContext抽象类的loadBeanDefinitions方法实现中,使用 XMLBeanDefinitionReader 类,处理了关于 XML 文件配置信息的操作。 - 同时这里又留下一个抽象类方法,
getConfigLocations(),此方法是为了从入口上下文类,拿到配置信息的地址描述。 
3.4.6 应用上下文实现类
ClassPathXmlApplicationContext.java
package com.lino.springframework.context.support;import com.lino.springframework.beans.BeansException;/*** @description: XML 文件应用上下文*/
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {private String[] configLocations;public ClassPathXmlApplicationContext() {}/*** 从 XML 中加载 BeanDefinition,并刷新上下文** @param configLocations 本地配置* @throws BeansException 异常*/public ClassPathXmlApplicationContext(String configLocations) throws BeansException {this(new String[]{configLocations});}/*** 从 XML 中加载 BeanDefinition,并刷新上下文** @param configLocations 本地配置* @throws BeansException 异常*/public ClassPathXmlApplicationContext(String[] configLocations) throws BeansException {this.configLocations = configLocations;refresh();}@Overrideprotected String[] getConfigLocations() {return configLocations;}
}
 
ClassPathXmlApplicationContext,是具体对外给用户提供的应用上下文方法。- 在继承了 
AbstractXmlApplicationContext以及层层抽象类的功能分离实现后,在此类ClassPathXmlApplicationContext的实现中就简单多,主要是对继承抽象类中方法的调用和提供配置文件地址信息。 
3.5 对象定义读取方法添加
3.5.1 对象定义读取接口
BeanDefinitionReader.java
package com.lino.springframework.beans.factory.support;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.core.io.Resource;
import com.lino.springframework.core.io.ResourceLoader;/*** @description: Bean定义读取接口*/
public interface BeanDefinitionReader {/*** 获取bean对象注册对象** @return bean对象注册对象*/BeanDefinitionRegistry getRegistry();/*** 获取资源加载器** @return 资源加载器*/ResourceLoader getResourceLoader();/*** 加载bean定义方法** @param resource 资源* @throws BeansException bean异常*/void loadBeanDefinitions(Resource resource) throws BeansException;/*** 加载bean定义方法** @param resources 资源列表* @throws BeansException bean异常*/void loadBeanDefinitions(Resource... resources) throws BeansException;/*** 加载bean定义方法** @param location 路径名称* @throws BeansException bean异常*/void loadBeanDefinitions(String location) throws BeansException;/*** 加载bean定义方法** @param locations 路径名称* @throws BeansException bean异常*/void loadBeanDefinitions(String... locations) throws BeansException;
}
 
- 定价加载 Bean 定义方法:
loadBeanDefinitions(String... locations),支持多地址的参数构造。 
3.5.2 XML处理对象注册修改
XMLBeanDefinitionReader.java
package com.lino.springframework.beans.factory.xml;import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.XmlUtil;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValue;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.config.BeanReference;
import com.lino.springframework.beans.factory.support.AbstractBeanDefinitionReader;
import com.lino.springframework.beans.factory.support.BeanDefinitionRegistry;
import com.lino.springframework.core.io.Resource;
import com.lino.springframework.core.io.ResourceLoader;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import java.io.IOException;
import java.io.InputStream;/*** @description: XML处理Bean注册*/
public class XMLBeanDefinitionReader extends AbstractBeanDefinitionReader {public XMLBeanDefinitionReader(BeanDefinitionRegistry registry) {super(registry);}public XMLBeanDefinitionReader(BeanDefinitionRegistry registry, ResourceLoader resourceLoader) {super(registry, resourceLoader);}@Overridepublic void loadBeanDefinitions(Resource resource) throws BeansException {try {try (InputStream inputStream = resource.getInputStream()) {doLoadBeanDefinitions(inputStream);}} catch (IOException | ClassNotFoundException e) {throw new BeansException("IOException parsing XML document from " + resource, e);}}@Overridepublic void loadBeanDefinitions(Resource... resources) throws BeansException {for (Resource resource : resources) {loadBeanDefinitions(resource);}}@Overridepublic void loadBeanDefinitions(String location) throws BeansException {ResourceLoader resourceLoader = getResourceLoader();Resource resource = resourceLoader.getResource(location);loadBeanDefinitions(resource);}@Overridepublic void loadBeanDefinitions(String... locations) throws BeansException {for (String location : locations) {loadBeanDefinitions(location);}}protected void doLoadBeanDefinitions(InputStream inputStream) throws ClassNotFoundException {Document doc = XmlUtil.readXML(inputStream);Element root = doc.getDocumentElement();NodeList childNodes = root.getChildNodes();for (int i = 0; i < childNodes.getLength(); i++) {// 判断元素if (!(childNodes.item(i) instanceof Element)) {continue;}// 判断对象if (!"bean".equals(childNodes.item(i).getNodeName())) {continue;}// 解析标签Element bean = (Element) childNodes.item(i);String id = bean.getAttribute("id");String name = bean.getAttribute("name");String className = bean.getAttribute("class");// 获取 Class, 方便获取类中的名称Class<?> clazz = Class.forName(className);// 优先级 id > nameString beanName = StrUtil.isNotEmpty(id) ? id : name;if (StrUtil.isEmpty(beanName)) {beanName = StrUtil.lowerFirst(clazz.getSimpleName());}// 定义beanBeanDefinition beanDefinition = new BeanDefinition(clazz);// 读取属性并填充for (int j = 0; j < bean.getChildNodes().getLength(); j++) {// 判断元素if (!(bean.getChildNodes().item(j) instanceof Element)) {continue;}// 判断对象if (!"property".equals(bean.getChildNodes().item(j).getNodeName())) {continue;}// 解析标签:propertyElement property = (Element) bean.getChildNodes().item(j);String attrName = property.getAttribute("name");String attrValue = property.getAttribute("value");String attrRef = property.getAttribute("ref");// 获取属性值:引入对象、值对象Object value = StrUtil.isNotEmpty(attrRef) ? new BeanReference(attrRef) : attrValue;// 创建属性信息PropertyValue propertyValue = new PropertyValue(attrName, value);beanDefinition.getPropertyValues().addPropertyValue(propertyValue);}if (getRegistry().containsBeanDefinition(beanName)) {throw new BeansException("Duplicate beanName[" + beanName + "] is not allowed");}// 注册 BeanDefinitiongetRegistry().registerBeanDefinition(beanName, beanDefinition);}}
}
 
3.6 对象工厂整合应用上下文
3.6.1 配置Bean工厂接口
ConfigurableBeanFactory.java
package com.lino.springframework.beans.factory.config;import com.lino.springframework.beans.factory.HierarchicalBeanFactory;/*** @description: 配置Bean工厂接口*/
public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {String SCOPE_SINGLETON = "singleton";String SCOPE_PROTOTYPE = "prototype";/*** 添加修改新实例化 Bean 对象的扩展点** @param beanPostProcessor 新实例化 Bean 对象*/void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);
}
 
3.6.2 抽象的Bean工厂基类
AbstractBeanFactory.java
package com.lino.springframework.beans.factory.support;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.BeanFactory;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.config.BeanPostProcessor;
import com.lino.springframework.beans.factory.config.ConfigurableBeanFactory;
import java.util.ArrayList;
import java.util.List;/*** @description: 抽象的 Bean 工厂基类,定义模板方法*/
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements ConfigurableBeanFactory {private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();@Overridepublic Object getBean(String name) throws BeansException {return doGetBean(name, null);}@Overridepublic Object getBean(String name, Object... args) throws BeansException {return doGetBean(name, args);}@Overridepublic <T> T getBean(String name, Class<T> requiredType) throws BeansException {return (T) getBean(name);}protected <T> T doGetBean(final String name, final Object[] args) {Object bean = getSingleton(name);if (bean != null) {return (T) bean;}BeanDefinition beanDefinition = getBeanDefinition(name);return (T) createBean(name, beanDefinition, args);}/*** 获取 Bean 对象** @param beanName 要检索的bean的名称* @return Bean 对象*/protected abstract BeanDefinition getBeanDefinition(String beanName);/*** 创建Bean对象** @param beanName       要检索的bean的名称* @param beanDefinition Bean对象* @param args           构造函数入参* @return 实例化的Bean对象*/protected abstract Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args);@Overridepublic void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {this.beanPostProcessors.remove(beanPostProcessor);this.beanPostProcessors.add(beanPostProcessor);}public List<BeanPostProcessor> getBeanPostProcessors() {return beanPostProcessors;}
}
 
3.6.3 配置列表Bean工厂接口
ConfigurableListableBeanFactory.java
package com.lino.springframework.beans.factory;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.config.AutowireCapableBeanFactory;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.config.ConfigurableBeanFactory;/*** @description: 配置列表 Bean工厂接口*/
public interface ConfigurableListableBeanFactory extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory {/*** 根据对象名称获取bean对象** @param beanName 对象名称* @return bean对象* @throws BeansException bean异常*/BeanDefinition getBeanDefinition(String beanName) throws BeansException;/*** 实例化单例 Bean 对象** @throws BeansException bean异常*/void preInstantiateSingletons() throws BeansException;
}
 
- 添加实例化单例 Bean 对象方法。
 
3.6.4 默认的Bean工厂实现类
DefaultListableBeanFactory.java
package com.lino.springframework.beans.factory.support;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.ConfigurableListableBeanFactory;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.config.BeanPostProcessor;import java.util.HashMap;
import java.util.Map;/*** @description: 默认的Bean工厂实现类*/
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry, ConfigurableListableBeanFactory {private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();@Overridepublic BeanDefinition getBeanDefinition(String beanName) {BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);if (beanDefinition == null) {throw new BeansException("No bean named '" + beanName + "' is defined");}return beanDefinition;}@Overridepublic void preInstantiateSingletons() throws BeansException {beanDefinitionMap.keySet().forEach(this::getBean);}@Overridepublic void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {beanDefinitionMap.put(beanName, beanDefinition);}@Overridepublic boolean containsBeanDefinition(String beanName) {return beanDefinitionMap.containsKey(beanName);}@Overridepublic <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {Map<String, T> result = new HashMap<>(16);beanDefinitionMap.forEach((beanName, beanDefinition) -> {Class beanClass = beanDefinition.getBeanClass();if (type.isAssignableFrom(beanClass)) {result.put(beanName, (T) getBean(beanName));}});return result;}@Overridepublic String[] getBeanDefinitionNames() {return beanDefinitionMap.keySet().toArray(new String[0]);}
}
 
3.6.5 Bean工厂超类接口
AutowireCapableBeanFactory.java
package com.lino.springframework.beans.factory.config;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.BeanFactory;/*** @description: Bean工厂超类接口*/
public interface AutowireCapableBeanFactory extends BeanFactory {/*** 执行 BeanPostProcessors 接口实现类的 postProcessorsBeforeInitialization 方法** @param existingBean 现有的对象* @param beanName     对象名称* @return 新对象* @throws BeansException 异常*/Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException;/*** 执行 BeanPostProcessors 接口实现类的 postProcessorsAfterInitialization 方法** @param existingBean 现有的对象* @param beanName     对象名称* @return 新对象* @throws BeansException 异常*/Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException;
}
 
- 添加了执行 
BeanPostProcessors接口实现类的前置和后置操作。 
3.6.6 在Bean创建时完成前置和后置处理
AbstractAutowireCapableBeanFactory.java
package com.lino.springframework.beans.factory.support;import cn.hutool.core.bean.BeanUtil;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValue;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.config.AutowireCapableBeanFactory;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.config.BeanPostProcessor;
import com.lino.springframework.beans.factory.config.BeanReference;
import java.lang.reflect.Constructor;/*** @description: 实现默认bean创建的抽象bean工厂超类*/
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();@Overrideprotected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) {Object bean = null;try {bean = createBeanInstance(beanDefinition, beanName, args);// 给bean填充属性applyPropertyValues(beanName, bean, beanDefinition);// 执行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置处理方法bean = initializeBean(beanName, bean, beanDefinition);} catch (Exception e) {throw new BeansException("Instantiation of bean failed", e);}registerSingletonBean(beanName, bean);return bean;}private Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {// 1.执行 BeanPostProcessor Before 处理Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);// 待完成内容:invokeInitMethods(beanName, wrappedBean, beanDefinition)invokeInitMethods(beanName, wrappedBean, beanDefinition);// 2.执行 BeanPostProcessor After 处理wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);return wrappedBean;}private void invokeInitMethods(String beanName, Object wrappedBean, BeanDefinition beanDefinition) {}private void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {try {PropertyValues propertyValues = beanDefinition.getPropertyValues();for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {String name = propertyValue.getName();Object value = propertyValue.getValue();if (value instanceof BeanReference) {// A 依赖 B,获取 B 的实例化BeanReference beanReference = (BeanReference) value;value = getBean(beanReference.getBeanName());}// 属性填充BeanUtil.setFieldValue(bean, name, value);}} catch (Exception e) {throw new BeansException("Error setting property values: " + beanName);}}protected Object createBeanInstance(BeanDefinition beanDefinition, String beanName, Object[] args) {Constructor constructorToUse = null;Class<?> beanClass = beanDefinition.getBeanClass();Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();for (Constructor ctor : declaredConstructors) {if (null != args && ctor.getParameterTypes().length == args.length) {constructorToUse = ctor;break;}}return getInstantiationStrategy().instantiate(beanDefinition, beanName, constructorToUse, args);}public InstantiationStrategy getInstantiationStrategy() {return instantiationStrategy;}public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {this.instantiationStrategy = instantiationStrategy;}@Overridepublic Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {Object current = processor.postProcessBeforeInitialization(result, beanName);if (null == current) {return result;}result = current;}return result;}@Overridepublic Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {Object current = processor.postProcessAfterInitialization(result, beanName);if (null == current) {return result;}result = current;}return result;}
}
 
- 实现 
BeanPostProcessor接口后,会涉及到两个接口方法:postProcessBeforeInitialization、postProcessAfterInitialization。- 分别作用于 Bean 对象执行初始化前后的额外处理。
 
 - 也就是需要在创建 Bean 对象时,在 
createBean方法中添加initializeBean(beanName, bean, beanDefinition)操作。- 这个操作方法主要是对于前置和后置方法的使用。 
applyBeanPostProcessorsBeforeInitialization()applyBeanPostProcessorsAfterInitialization()
 
 - 这个操作方法主要是对于前置和后置方法的使用。 
 
四、测试:实现应用上下文
4.1 配置测试环境
4.1.1 修改UserService用户对象
UserService.java
package com.lino.springframework.test.bean;/*** @description: 模拟用户 Bean 对象*/
public class UserService {private String uId;private String company;private String location;private UserDao userDao;/*** 查询用户信息*/public String queryUserInfo() {return userDao.queryUserName(uId) + "," + company + "," + location;}public String getuId() {return uId;}public void setuId(String uId) {this.uId = uId;}public String getCompany() {return company;}public void setCompany(String company) {this.company = company;}public String getLocation() {return location;}public void setLocation(String location) {this.location = location;}public UserDao getUserDao() {return userDao;}public void setUserDao(UserDao userDao) {this.userDao = userDao;}
}
 
- 添加 
company和location字段。 
4.1.2 实现BeanFactoryPostProcessor
MyBeanFactoryPostProcessor.java
package com.lino.springframework.test.common;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValue;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.ConfigurableListableBeanFactory;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.config.BeanFactoryPostProcessor;/*** @description: BeanFactoryPostProcessor 实例化 Bean 对象之前,修改 BeanDefinition 属性*/
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {BeanDefinition beanDefinition = beanFactory.getBeanDefinition("userService");PropertyValues propertyValues = beanDefinition.getPropertyValues();propertyValues.addPropertyValue(new PropertyValue("company", "改为:字节跳动"));}
}
 
4.1.3 实现BeanPostProcessor
MyBeanPostProcessor.java
package com.lino.springframework.test.common;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.config.BeanPostProcessor;
import com.lino.springframework.test.bean.UserService;/*** @description: BeanPostProcessor 在 Bean 对象执行初始化方法前后进行扩展*/
public class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if ("userService".equals(beanName)) {UserService userService = (UserService) bean;userService.setLocation("改为:温州");}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}
}
 
4.1.4 基础配置,无BeanFactoryPostProcessor、BeanPostProcessor实现类
spring.xml
<?xml version="1.0" encoding="utf-8" ?>
<beans><bean id="userDao" class="com.lino.springframework.test.bean.UserDao"/><bean id="userService" class="com.lino.springframework.test.bean.UserService"><property name="uId" value="10001"/><property name="company" value="阿里"/><property name="location" value="杭州"/><property name="userDao" ref="userDao"/></bean>
</beans>
 
4.1.5 增强配置,有BeanFactoryPostProcessor、BeanPostProcessor实现类
springPostProcessor.xml
<?xml version="1.0" encoding="utf-8" ?>
<beans><bean id="userDao" class="com.lino.springframework.test.bean.UserDao"/><bean id="userService" class="com.lino.springframework.test.bean.UserService"><property name="uId" value="10001"/><property name="company" value="阿里"/><property name="location" value="杭州"/><property name="userDao" ref="userDao"/></bean><bean class="com.lino.springframework.test.common.MyBeanPostProcessor"/><bean class="com.lino.springframework.test.common.MyBeanFactoryPostProcessor"/>
</beans>
 
- 这里提供两个配置文件,一个不包含 
BeanFactoryPostProcessor、BeanPostProcessor,另外一个是包含的。 
4.2 单元测试
4.2.1 不使用应用上下文测试
ApiTest.java
@Test
public void test_BeanFactoryPostProcessorAndBeanPostProcessor() {// 1.初始化 BeanFactoryDefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();// 2.读取配置文件&注册BeanXMLBeanDefinitionReader reader = new XMLBeanDefinitionReader(beanFactory);reader.loadBeanDefinitions("classpath:spring.xml");// 3.BeanDefinition 加载完成 & Bean实例化之前,修改 BeanDefinition 的属性值MyBeanFactoryPostProcessor beanFactoryPostProcessor = new MyBeanFactoryPostProcessor();beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);// 4.Bean实例化之后,修改 Bean 属性信息MyBeanPostProcessor beanPostProcessor = new MyBeanPostProcessor();beanFactory.addBeanPostProcessor(beanPostProcessor);// 5.获取Bean对象调用方法UserService userService = beanFactory.getBean("userService", UserService.class);String result = userService.queryUserInfo();System.out.println("测试结果:" + result);
}
 
- DefaultListableBeanFactory 创建 BeanFactory 并使用 XMLBeanDefinitionReader 加载配置文件的方式。
 - 接下来就是对 MyBeanFactoryPostProcessor 和 MyBeanPostProcessor 的处理。 
- 一个是在 BeanDefinition 加载完成 & Bean 实例化之前,修改 BeanDefinition 的属性值。
 - 另外一个是在 Bean 实例化之后,修改 Bean 属性信息。
 
 
测试结果
测试结果:张三,改为:字节跳动,改为:温州
 
- 从测试结果来看,我们配置的属性信息和 
spring.xml配置文件中不一样了。 
4.2.2 使用应用上下文
ApiTest.java
@Test
public void test_xml() {// 1.初始化 BeanFactoryClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:springPostProcessor.xml");// 3.获取Bean对象调用方法UserService userService = applicationContext.getBean("userService", UserService.class);String result = userService.queryUserInfo();System.out.println("测试结果:" + result);
}
 
- 新增 ClassPathXmlApplicationContext 应用上下文,再操作起来就方便很多。
 - 在这里可以一步把配置文件交给 ClassPathXmlApplicationContext,也不需要管理一些自定义实现的 Spring 接口的类。
 
测试结果
测试结果:张三,改为:字节跳动,改为:温州
 
五、总结:实现应用上下文
- 新增加了 Spring 框架中两个非常重要的接口 
BeanFactoryPostProcessor、BeanPostProcessor同时还添加了关于应用上下文的实现。ApplicationContext接口的定义是继承BeanFactory外新增加功能的接口,它可以满足于自动识别、资源加载、容器事件、监听器等功能。- 同时例如一些国际化支持、单例 Bean 自动初始化等,也是可以再这个类里实现和扩充的。
 
 - 通过本节的实现了解 
BeanFactoryPostProcessor、BeanPostProcessor,以后再做一些关于 Spring 中间件的开发时,如果需要用到 Bean 对象的获取以及修改一些属性信息,那么就可以使用这两个接口了。同时BeanPostProcessor也是实现 AOP 切面技术的关键所在。 
相关文章:
手写Spring:第7章-实现应用上下文
文章目录 一、目标:实现应用上下文二、设计:实现应用上下文三、实现:实现应用上下文3.1 工程结构3.2 Spring应用上下文和Bean对象扩展类图3.3 对象工厂和对象扩展接口3.3.1 对象工厂扩展接口3.3.2 对象扩展接口 3.4 定义应用上下文3.4.1 定义…...
Java(三)逻辑控制(if....else,循环语句)与方法
逻辑控制(if....else,循环语句)与方法 四、逻辑控制1.if...else(常用)1.1表达格式(三种) 2.switch...case(用的少)2.1表达式 3.while(常用)3.1语法格式3.2关键字beak:3.3关键字 continue: 4.for…...
通过API接口实现数据实时更新的方案(InsCode AI 创作助手)
要实现实时数据更新,需要采用轮询或者长连接两种方式。 1. 轮询方式 轮询方式指的是客户端定时向服务器请求数据的方式,通过一定的时间间隔去请求最新数据。具体的实现方法包括: 客户端定时向服务器发送请求,获取最新数据&…...
分类预测 | MATLAB实现PCA-GRU(主成分门控循环单元)分类预测
分类预测 | MATLAB实现PCA-GRU(主成分门控循环单元)分类预测 目录 分类预测 | MATLAB实现PCA-GRU(主成分门控循环单元)分类预测预测效果基本介绍程序设计参考资料致谢 预测效果 基本介绍 Matlab实现基于PCA-GRU主成分分析-门控循环单元多输入分类预测(完整程序和数据…...
el-dialog无法关闭
代码如下,:visible.sync"result2DeptVisible"来控制dialog的隐显问题,但当点击关闭的时候 ,无法关闭!! <el-dialog :visible.sync"result2DeptVisible" class"el-dialog-view">&…...
MATLAB算法实战应用案例精讲-【大模型】LLM算法(最终篇)
目录 前言 知识储备 1).通讯原语操作: 2).并行计算技术: 算法原理...
Mac brew -v 报错 fatal: detected dubious ownership in repository
Mac 电脑查询 brew版本时报错,如下错误: Last login: Fri Sep 8 14:56:21 on ttys021 sunshiyusunshiyudeMacBook-Pro-2 ~ % brew -v Homebrew 4.0.3-30-g7ac31f7 fatal: detected dubious ownership in repository at /usr/local/Homebrew/Library/Ta…...
Docker镜像、容器、仓库及数据管理
使用Docker镜像 获取镜像 使用docker pull命令,使用docker search命令可以搜索远端仓库中共享的镜像。 运行容器 使用docker run [OPTIONS] IMAGE [COMMAND] [ARG...]命令,如:docker run --name ubuntu_test --rm -it ubuntu:test /bin/b…...
Java的选择排序、冒泡排序、插入排序
不爱生姜不吃醋 如果本文有什么错误的话欢迎在评论区中指正 与其明天开始,不如现在行动! 文章目录 🌴前言🌴一、选择排序1.原理2.时间复杂度3.代码实现 🌴二、冒泡排序1. 原理2. 时间复杂度3.代码实现 🌴三…...
Vagrant + VirtualBox + CentOS7 + WindTerm 5分钟搭建本地linux开发环境
1、准备阶段 将环境搭建所需要的工具和文件下载好(页面找不到可参考Tips部分) Vagrant 版本:vagrant_2.2.18_x86_64.msi 链接:https://developer.hashicorp.com/vagrant/downloads VirtualBox 版本:VirtualBox-6.1.46…...
关于Ajax
1.Ajax 异步 JavaScript 和 XML, 或 Ajax 本身不是一种技术,而是一种将一些现有技术结合起来使用的方法,包括:HTML 或 XHTML、CSS、JavaScript、DOM、XML、XSLT、以及最重要的 XMLHttpRequest 对象。当使用结合了这些技术的 Aja…...
打开转盘锁 -- BFS
打开转盘锁 这里提供两种实现,单向BFS和双向BFS。 class OpenLock:"""752. 打开转盘锁https://leetcode.cn/problems/open-the-lock/"""def solution(self, deadends: List[str], target: str) -> int:"""单向BFS:…...
国标EHOME视频平台EasyCVR视频融合平台助力地下停车场安全
EasyCVR能在复杂的网络环境中,将分散的各类视频资源进行统一汇聚、整合、集中管理,实现视频资源的鉴权管理、按需调阅、全网分发、云存储、智能分析等,视频智能分析平台EasyCVR融合性强、开放度高、部署轻快,在智慧工地、智慧园区…...
【业务功能篇96】微服务-springcloud-springboot-认证服务-登录注册功能-Auth2.0-分布式session
5.登录功能 通过最基础的登录操作来完成登录处理 登录页面处理 认证服务的处理 /*** 注册的方法* return*/PostMapping("/login")public String login(LoginVo loginVo , RedirectAttributes redirectAttributes){R r memberFeginService.login(loginVo);if(r.getC…...
自造简易版音频进度条
最近在做音乐播放器页面, 积累了很多有趣的经验, 今天先分享播放进度条的开发过程. 效果 话不多说,先看效果 支持点击修改进度,拖拽修改进度,当然大家肯定都知道ui库里面有现成的,为何要自己造一个 首先著名的ui库中确实都要这…...
433MHz芯片在遥控应用市场中的优点
当涉及到简单的无线射频通信,433MHz芯片成为一种经济实惠且广泛应用的选择。以下是关于433MHz芯片的重点信息: 工作原理:433MHz芯片的工作原理是将数字信号转化为射频信号,并通过无线信道进行传输。在接收端,射频信号再…...
基于Bert+Attention+LSTM智能校园知识图谱问答推荐系统——NLP自然语言处理算法应用(含Python全部工程源码及训练模型)+数据集
目录 前言总体设计系统整体结构图系统流程图 运行环境Python 环境服务器环境 模块实现1. 构造数据集2. 识别网络3. 命名实体纠错4. 检索问题类别5. 查询结果 系统测试1. 命名实体识别网络测试2. 知识图谱问答系统整体测试 工程源代码下载其它资料下载 前言 这个项目充分利用了…...
慕尼黑主题活动!亚马逊云科技生成式AI全新解决方案,引领未来移动出行领域
IAA作为世界五大车展之一,一直对全球汽车产业的发展起着关键作用!2023年9月5日在慕尼黑开幕的IAA MOBILITY 2023以“体验联动智慧出行”为主题,紧跟移动出行领域的前沿变化,将汇集整车企业、开发者、供应商、科技公司、服务提供商…...
android 离线语言合成(文字转语音)
1、基于开源MaryTTS https://github.com/AndroidMaryTTS/AndroidMaryTTS 目前查到的资料,不支持中文,只针对西方语种。 2、基于TensorFlowTTS 官方个地址:为 Android 构建 TensorFlow Lite 库 (google.cn) 所依赖包下载地址:Maven Centr…...
使用Fastchat部署vicuna大模型
FastChat是一个用于训练、提供服务和评估基于大型语言模型的聊天机器人的开放平台。其核心特点包括: 最先进模型(例如 Vicuna)的权重、训练代码和评估代码。一个分布式的多模型提供服务系统,配备 Web 用户界面和与 OpenAI 兼容的…...
利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
