首页 文章 精选 留言 我的

精选列表

搜索[手游加固],共7872篇文章
优秀的个人博客,低调大师

自己手搓一套咨询风格的PPT Skills技能包并开源-WorkBuddy技能市场和GitHub可下载

很多人以为,咨询顾问风格 PPT 的关键是配色、版式和图标。它们当然重要,但真正决定一页 PPT 是否有说服力的,是内容有没有被转化为清晰的判断结构。我的目标不是做一个“把文字排得更漂亮”的工具,而是把从材料到结论、从结论到证据、从证据到视觉表达的过程,沉淀为一套可复用的生成技能。

优秀的个人博客,低调大师

《Spring 手撸专栏》第 15 章:万人之敌,通过注解给属性注入配置和Bean对象

持续坚持原创输出,点击蓝字关注我吧 作者:小傅哥博客:https://bugstack.cn ❝ 沉淀、分享、成长,让自己和他人都能有所收获!😜 ❞ 目录 一、前言 二、目标 三、方案 四、实现 1. 工程结构 2. 把读取到属性填充到容器 3. 自定义属性注入注解 4. 扫描自定义注解 5. 在Bean的生命周期中调用属性注入 五、测试 1. 事先准备 2. 属性配置文件 3. 单元测试 六、总结 七、系列推荐 一、前言 写代码,就是从能用到好用的不断折腾! 你听过扰动函数吗?你写过斐波那契(Fibonacci)散列吗?你实现过梅森旋转算法吗?怎么 没听过这些写不了代码吗!不会的,即使没听过你一样可以写的了代码,比如你实现的数据库路由数据总是落在1库1表它不散列分布、你实现的抽奖系统总是把运营配置的最大红包发出去提高了运营成本、你开发的秒杀系统总是在开始后的1秒就挂了货品根本给不出去。 除了一部分仅把编码当成搬砖应付工作外的程序员,还有一部分总是在追求极致的码农。写代码还能赚钱,真开心! 这样的码农总是会考虑🤔还有没有更好的实现逻辑能让代码不仅是能用,还要好用呢?其实这一点的追求到完成,需要大量扩展性学习和深度挖掘,这样你设计出来的系统才更你考虑的更加全面,也能应对各种复杂的场景。 二、目标 在目前 IOC、AOP 两大核心功能模块的支撑下,完全可以管理 Bean 对象的注册和获取,不过这样的使用方式总感觉像是刀耕火种有点难用。因此在上一章节我们解决需要手动配置 Bean 对象到 spring.xml 文件中,改为可以自动扫描带有注解 @Component 的对象完成自动装配和注册到 Spring 容器的操作。 那么在自动扫描包注册 Bean 对象之后,就需要把原来在配置文件中通过 property name="token" 配置属性和Bean的操作,也改为可以自动注入。这就像我们使用 Spring 框架中 @Autowired、@Value 注解一样,完成我们对属性和对象的注入操作。 三、方案 其实从我们在完成 Bean 对象的基础功能后,后续陆续添加的功能都是围绕着 Bean 的生命周期进行的,比如修改 Bean 的定义 BeanFactoryPostProcessor,处理 Bean 的属性要用到 BeanPostProcessor,完成个性的属性操作则专门继承 BeanPostProcessor 提供新的接口,因为这样才能通过 instanceof 判断出具有标记性的接口。所以关于 Bean 等等的操作,以及监听 Aware、获取 BeanFactory,都需要在 Bean 的生命周期中完成。那么我们在设计属性和 Bean 对象的注入时候,也会用到 BeanPostProcessor 来完成在设置 Bean 属性之前,允许 BeanPostProcessor 修改属性值。整体设计结构如下图: 要处理自动扫描注入,包括属性注入、对象注入,则需要在对象属性 applyPropertyValues 填充之前 ,把属性信息写入到 PropertyValues 的集合中去。这一步的操作相当于是解决了以前在 spring.xml 配置属性的过程。 而在属性的读取中,需要依赖于对 Bean 对象的类中属性的配置了注解的扫描, field.getAnnotation(Value.class); 依次拿出符合的属性并填充上相应的配置信息。 这里有一点 ,属性的配置信息需要依赖于 BeanFactoryPostProcessor 的实现类 PropertyPlaceholderConfigurer,把值写入到 AbstractBeanFactory的embeddedValueResolvers集合中,这样才能在属性填充中利用 beanFactory 获取相应的属性值 还有一个是关于 @Autowired 对于对象的注入,其实这一个和属性注入的唯一区别是对于对象的获取 beanFactory.getBean(fieldType),其他就没有什么差一点了。 当所有的属性被设置到 PropertyValues 完成以后,接下来就到了创建对象的下一步,属性填充,而此时就会把我们一一获取到的配置和对象填充到属性上,也就实现了自动注入的功能。 四、实现 1. 工程结构 small-spring-step-14└──src├──main│└──java│└──cn.bugstack.springframework│├──aop││├──aspectj│││└──AspectJExpressionPointcut.java│││└──AspectJExpressionPointcutAdvisor.java││├──framework│││├──adapter││││└──MethodBeforeAdviceInterceptor.java│││├──autoproxy││││└──MethodBeforeAdviceInterceptor.java│││├──AopProxy.java│││├──Cglib2AopProxy.java│││├──JdkDynamicAopProxy.java│││├──ProxyFactory.java│││└──ReflectiveMethodInvocation.java││├──AdvisedSupport.java││├──Advisor.java││├──BeforeAdvice.java││├──ClassFilter.java││├──MethodBeforeAdvice.java││├──MethodMatcher.java││├──Pointcut.java││├──PointcutAdvisor.java││└──TargetSource.java│├──beans││├──factory│││├──annotation││││├──Autowired.java││││├──AutowiredAnnotationBeanPostProcessor.java││││├──Qualifier.java││││└──Value.java│││├──config││││├──AutowireCapableBeanFactory.java││││├──BeanDefinition.java││││├──BeanFactoryPostProcessor.java││││├──BeanPostProcessor.java││││├──BeanReference.java││││├──ConfigurableBeanFactory.java││││├──InstantiationAwareBeanPostProcessor.java││││└──SingletonBeanRegistry.java│││├──support││││├──AbstractAutowireCapableBeanFactory.java││││├──AbstractBeanDefinitionReader.java││││├──AbstractBeanFactory.java││││├──BeanDefinitionReader.java││││├──BeanDefinitionRegistry.java││││├──CglibSubclassingInstantiationStrategy.java││││├──DefaultListableBeanFactory.java││││├──DefaultSingletonBeanRegistry.java││││├──DisposableBeanAdapter.java││││├──FactoryBeanRegistrySupport.java││││├──InstantiationStrategy.java││││└──SimpleInstantiationStrategy.java│││├──support││││└──XmlBeanDefinitionReader.java│││├──Aware.java│││├──BeanClassLoaderAware.java│││├──BeanFactory.java│││├──BeanFactoryAware.java│││├──BeanNameAware.java│││├──ConfigurableListableBeanFactory.java│││├──DisposableBean.java│││├──FactoryBean.java│││├──HierarchicalBeanFactory.java│││├──InitializingBean.java│││├──ListableBeanFactory.java│││└──PropertyPlaceholderConfigurer.java││├──BeansException.java││├──PropertyValue.java││└──PropertyValues.java│├──context││├──annotation│││├──ClassPathBeanDefinitionScanner.java│││├──ClassPathScanningCandidateComponentProvider.java│││└──Scope.java││├──event│││├──AbstractApplicationEventMulticaster.java│││├──ApplicationContextEvent.java│││├──ApplicationEventMulticaster.java│││├──ContextClosedEvent.java│││├──ContextRefreshedEvent.java│││└──SimpleApplicationEventMulticaster.java││├──support│││├──AbstractApplicationContext.java│││├──AbstractRefreshableApplicationContext.java│││├──AbstractXmlApplicationContext.java│││├──ApplicationContextAwareProcessor.java│││└──ClassPathXmlApplicationContext.java││├──ApplicationContext.java││├──ApplicationContextAware.java││├──ApplicationEvent.java││├──ApplicationEventPublisher.java││├──ApplicationListener.java││└──ConfigurableApplicationContext.java│├──core.io││├──ClassPathResource.java││├──DefaultResourceLoader.java││├──FileSystemResource.java││├──Resource.java││├──ResourceLoader.java││└──UrlResource.java│├──stereotype││└──Component.java│└──utils│├──ClassUtils.java│└──StringValueResolver.java└──test└──java└──cn.bugstack.springframework.test├──bean│├──IUserService.java│└──UserService.java└──ApiTest.java 工程源码:公众号「bugstack虫洞栈」,回复:Spring 专栏,获取完整源码 自动扫描注入占位符配置和对象的类关系,如图 15-2 图 15-2 在整个类图中以围绕实现接口 InstantiationAwareBeanPostProcessor 的类 AutowiredAnnotationBeanPostProcessor 作为入口点,被 AbstractAutowireCapableBeanFactory创建 Bean 对象过程中调用扫描整个类的属性配置中含有自定义注解 Value、 Autowired、 Qualifier,的属性值。 这里稍有变动的是关于属性值信息的获取,在注解配置的属性字段扫描到信息注入时,包括了占位符从配置文件获取信息也包括 Bean 对象,Bean 对象可以直接获取,但配置信息需要在 AbstractBeanFactory 中添加新的属性集合 embeddedValueResolvers,由 PropertyPlaceholderConfigurer#postProcessBeanFactory 进行操作填充到属性集合中。 2. 把读取到属性填充到容器 定义解析字符串接口 cn.bugstack.springframework.util.StringValueResolver publicinterfaceStringValueResolver{StringresolveStringValue(StringstrVal);} 接口 StringValueResolver 是一个解析字符串操作的接口 填充字符串 publicclassPropertyPlaceholderConfigurerimplementsBeanFactoryPostProcessor{@OverridepublicvoidpostProcessBeanFactory(ConfigurableListableBeanFactorybeanFactory)throwsBeansException{try{//加载属性文件DefaultResourceLoaderresourceLoader=newDefaultResourceLoader();Resourceresource=resourceLoader.getResource(location);//...占位符替换属性值、设置属性值//向容器中添加字符串解析器,供解析@Value注解使用StringValueResolvervalueResolver=newPlaceholderResolvingStringValueResolver(properties);beanFactory.addEmbeddedValueResolver(valueResolver);}catch(IOExceptione){thrownewBeansException("Couldnotloadproperties",e);}}privateclassPlaceholderResolvingStringValueResolverimplementsStringValueResolver{privatefinalPropertiesproperties;publicPlaceholderResolvingStringValueResolver(Propertiesproperties){this.properties=properties;}@OverridepublicStringresolveStringValue(StringstrVal){returnPropertyPlaceholderConfigurer.this.resolvePlaceholder(strVal,properties);}}} 在解析属性配置的类 PropertyPlaceholderConfigurer 中,最主要的其实就是这行代码的操作 beanFactory.addEmbeddedValueResolver(valueResolver) 这是把属性值写入到了 AbstractBeanFactory 的 embeddedValueResolvers 中。 这里说明下,embeddedValueResolvers 是 AbstractBeanFactory 类新增加的集合 List<StringValueResolver> embeddedValueResolvers String resolvers to apply e.g. to annotation attribute values 3. 自定义属性注入注解 自定义注解,Autowired、Qualifier、Value @Retention(RetentionPolicy.RUNTIME)@Target({ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD})public@interfaceAutowired{}@Target({ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER,ElementType.TYPE,ElementType.ANNOTATION_TYPE})@Retention(RetentionPolicy.RUNTIME)@Inherited@Documentedpublic@interfaceQualifier{Stringvalue()default"";}@Target({ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic@interfaceValue{/***Theactualvalueexpression:e.g."#{systemProperties.myProp}".*/Stringvalue();} 3个注解在我们日常使用 Spring 也是非常常见的,注入对象、注入属性,而 Qualifier 一般与 Autowired 配合使用。 4. 扫描自定义注解 cn.bugstack.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor publicclassAutowiredAnnotationBeanPostProcessorimplementsInstantiationAwareBeanPostProcessor,BeanFactoryAware{privateConfigurableListableBeanFactorybeanFactory;@OverridepublicvoidsetBeanFactory(BeanFactorybeanFactory)throwsBeansException{this.beanFactory=(ConfigurableListableBeanFactory)beanFactory;}@OverridepublicPropertyValuespostProcessPropertyValues(PropertyValuespvs,Objectbean,StringbeanName)throwsBeansException{//1.处理注解@ValueClass<?>clazz=bean.getClass();clazz=ClassUtils.isCglibProxyClass(clazz)?clazz.getSuperclass():clazz;Field[]declaredFields=clazz.getDeclaredFields();for(Fieldfield:declaredFields){ValuevalueAnnotation=field.getAnnotation(Value.class);if(null!=valueAnnotation){Stringvalue=valueAnnotation.value();value=beanFactory.resolveEmbeddedValue(value);BeanUtil.setFieldValue(bean,field.getName(),value);}}//2.处理注解@Autowiredfor(Fieldfield:declaredFields){AutowiredautowiredAnnotation=field.getAnnotation(Autowired.class);if(null!=autowiredAnnotation){Class<?>fieldType=field.getType();StringdependentBeanName=null;QualifierqualifierAnnotation=field.getAnnotation(Qualifier.class);ObjectdependentBean=null;if(null!=qualifierAnnotation){dependentBeanName=qualifierAnnotation.value();dependentBean=beanFactory.getBean(dependentBeanName,fieldType);}else{dependentBean=beanFactory.getBean(fieldType);}BeanUtil.setFieldValue(bean,field.getName(),dependentBean);}}returnpvs;}} AutowiredAnnotationBeanPostProcessor 是实现接口 InstantiationAwareBeanPostProcessor 的一个用于在 Bean 对象实例化完成后,设置属性操作前的处理属性信息的类和操作方法。 只有实现了 BeanPostProcessor 接口才有机会在 Bean 的生命周期中处理初始化信息 核心方法 postProcessPropertyValues,主要用于处理类含有 @Value、@Autowired 注解的属性,进行属性信息的提取和设置。 这里需要注意一点因为我们在 AbstractAutowireCapableBeanFactory 类中使用的是 CglibSubclassingInstantiationStrategy 进行类的创建,所以在 AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues 中需要判断是否为 CGlib 创建对象,否则是不能正确拿到类信息的。 ClassUtils.isCglibProxyClass(clazz) ? clazz.getSuperclass() : clazz; 5. 在Bean的生命周期中调用属性注入 cn.bugstack.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory publicabstractclassAbstractAutowireCapableBeanFactoryextendsAbstractBeanFactoryimplementsAutowireCapableBeanFactory{privateInstantiationStrategyinstantiationStrategy=newCglibSubclassingInstantiationStrategy();@OverrideprotectedObjectcreateBean(StringbeanName,BeanDefinitionbeanDefinition,Object[]args)throwsBeansException{Objectbean=null;try{//判断是否返回代理Bean对象bean=resolveBeforeInstantiation(beanName,beanDefinition);if(null!=bean){returnbean;}//实例化Beanbean=createBeanInstance(beanDefinition,beanName,args);//在设置Bean属性之前,允许BeanPostProcessor修改属性值applyBeanPostProcessorsBeforeApplyingPropertyValues(beanName,bean,beanDefinition);//给Bean填充属性applyPropertyValues(beanName,bean,beanDefinition);//执行Bean的初始化方法和BeanPostProcessor的前置和后置处理方法bean=initializeBean(beanName,bean,beanDefinition);}catch(Exceptione){thrownewBeansException("Instantiationofbeanfailed",e);}//注册实现了DisposableBean接口的Bean对象registerDisposableBeanIfNecessary(beanName,bean,beanDefinition);//判断SCOPE_SINGLETON、SCOPE_PROTOTYPEif(beanDefinition.isSingleton()){registerSingleton(beanName,bean);}returnbean;}/***在设置Bean属性之前,允许BeanPostProcessor修改属性值**@parambeanName*@parambean*@parambeanDefinition*/protectedvoidapplyBeanPostProcessorsBeforeApplyingPropertyValues(StringbeanName,Objectbean,BeanDefinitionbeanDefinition){for(BeanPostProcessorbeanPostProcessor:getBeanPostProcessors()){if(beanPostProcessorinstanceofInstantiationAwareBeanPostProcessor){PropertyValuespvs=((InstantiationAwareBeanPostProcessor)beanPostProcessor).postProcessPropertyValues(beanDefinition.getPropertyValues(),bean,beanName);if(null!=pvs){for(PropertyValuepropertyValue:pvs.getPropertyValues()){beanDefinition.getPropertyValues().addPropertyValue(propertyValue);}}}}}//...} AbstractAutowireCapableBeanFactory#createBean 方法中有这一条新增加的方法调用,就是在 设置 Bean 属性之前,允许 BeanPostProcessor 修改属性值 的操作 applyBeanPostProcessorsBeforeApplyingPropertyValues 那么这个 applyBeanPostProcessorsBeforeApplyingPropertyValues 方法中,首先就是获取已经注入的 BeanPostProcessor 集合并从中筛选出继承接口 InstantiationAwareBeanPostProcessor 的实现类。 最后就是调用相应的 postProcessPropertyValues 方法以及循环设置属性值信息, beanDefinition.getPropertyValues().addPropertyValue(propertyValue); 五、测试 1. 事先准备 配置 Dao @ComponentpublicclassUserDao{privatestaticMap<String,String>hashMap=newHashMap<>();static{hashMap.put("10001","小傅哥,北京,亦庄");hashMap.put("10002","八杯水,上海,尖沙咀");hashMap.put("10003","阿毛,香港,铜锣湾");}publicStringqueryUserName(StringuId){returnhashMap.get(uId);}} 给类配置上一个自动扫描注册 Bean 对象的注解 @Component,接下来会把这个类注入到 UserService 中。 注解注入到 UserService @Component("userService")publicclassUserServiceimplementsIUserService{@Value("${token}")privateStringtoken;@AutowiredprivateUserDaouserDao;publicStringqueryUserInfo(){try{Thread.sleep(newRandom(1).nextInt(100));}catch(InterruptedExceptione){e.printStackTrace();}returnuserDao.queryUserName("10001")+","+token;}//...} 这里包括了两种类型的注入,一个是占位符注入属性信息 @Value("${token}"),另外一个是注入对象信息 @Autowired 2. 属性配置文件 token.properties token=RejDlI78hu223Opo983Ds spring.xml <?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context"><beanclass="cn.bugstack.springframework.beans.factory.PropertyPlaceholderConfigurer"><propertyname="location"value="classpath:token.properties"/></bean><context:component-scanbase-package="cn.bugstack.springframework.test.bean"/></beans> 在 spring.xml 中配置了扫描属性信息和自动扫描包路径范围。 3. 单元测试 @Testpublicvoidtest_scan(){ClassPathXmlApplicationContextapplicationContext=newClassPathXmlApplicationContext("classpath:spring.xml");IUserServiceuserService=applicationContext.getBean("userService",IUserService.class);System.out.println("测试结果:"+userService.queryUserInfo());} 单元测试时候就可以完整的测试一个类注入到 Spring 容器,同时这个属性信息也可以被自动扫描填充上。 测试结果 测试结果:小傅哥,北京,亦庄,RejDlI78hu223Opo983DsProcessfinishedwithexitcode0 从测试结果可以看到现在我们的使用方式已经通过了,有自动扫描类,有注解注入属性。这与使用 Spring 框架越来越像了。 六、总结 从整个注解信息扫描注入的实现内容来看,我们一直是围绕着在 Bean 的生命周期中进行处理,就像 BeanPostProcessor 用于修改新实例化 Bean 对象的扩展点,提供的接口方法可以用于处理 Bean 对象实例化前后进行处理操作。而有时候需要做一些差异化的控制,所以还需要继承 BeanPostProcessor 接口,定义新的接口 InstantiationAwareBeanPostProcessor 这样就可以区分出不同扩展点的操作了。 像是接口用 instanceof 判断,注解用 Field.getAnnotation(Value.class); 获取,都是相当于在类上做的一些标识性信息,便于可以用一些方法找到这些功能点,以便进行处理。所以在我们日常开发设计的组件中,也可以运用上这些特点。 当你思考把你的实现融入到一个已经细分好的 Bean 生命周期中,你会发现它的设计是如此的好,可以让你在任何初始化的时间点上,任何面上,都能做你需要的扩展或者改变,这也是我们做程序设计时追求的灵活性。 七、系列推荐 调研字节码插桩技术,用于系统监控设计和实现 工作两三年了,整不明白架构图都画啥? Thread.start() ,它是怎么让线程启动的呢? 基于jdbc实现一个Demo版的Mybatis 一个Bug,让我发现了 Java 界的.AJ(锥)! - END - 下方扫码关注 bugstack虫洞栈,与小傅哥一起学习成长、共同进步,做一个码场最贵Coder! 回复【设计模式】,获取《重学Java设计模式》,这是一本互联网真实案例的实践书籍,从实际业务中抽离出,交易、营销、秒杀、中间件、源码等众多场景进行学习代码设计。 回复【面经手册】,获取《面经手册•拿大厂Offer》,这是一本有深度的Java核心内容,从数据结构、算法、并发编程以及JVM系8不断深入讲解,让懂了就是真的懂。 你好,我是小傅哥。一线互联网 java 工程师、架构师,开发过交易&营销、写过运营&活动、设计过中间件也倒腾过中继器、IO板卡。不只是写Java语言,也搞过C#、PHP,是一个技术活跃的折腾者。 2020年写了一本PDF 《重学Java设计模式》 ,全网下载量50万+,帮助很多同学成长,现已出书。同年 github 的两个项目, CodeGuide 、 itstack-demo-design ,持续霸榜 Trending,成为全球热门项目。 2021年上架一本小册 《SpringBoot 中间件设计和开发》 ,16个互联网中间件场景、30个工程,是全网唯一一次手把手教你造轮子、写中间件,因为这样的技术离P7最近、离架构师最近、离高薪资最近! 本文分享自微信公众号 - bugstack虫洞栈(bugstack)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

软硬件两手抓!解读H3C关键业务的高可用高可靠性

在云计算、大数据、物联网和移动互联网时代,企业对IT系统的依赖性越来越高。如何建设一套高可用性和高可靠性的IT系统,确保企业各项业务稳健高效运行,成为摆在企业面前的最大难题,特别是对于互联网支付、证券交易等核心关键业务来讲,系统一旦出现问题,就会造成无法弥补的损失。 对于关键业务来讲,企业的IT系统正在面临着以下挑战: 1)我们正在部署新应用,需要更高的可靠性; 2)我们的业务交易量和数量快速膨胀,对关键业务应对系统可用性的要求越来越高; 3)我们的系统有可能遭遇到不同类型的故障,对IT服务级别(SLA)要求越来越高; 4)我们对需要停机进行的系统维护很不满意。 解决IT系统的高可用性和高可靠性,靠无休止的增加硬件软件的传统容灾方案不但会大幅提高企业的成本支出,而且还会使系统变得越来越臃肿,即加大了系统的运维管理难度,又进一步提高了系统的风险,显然不是最佳的解决方案。那么,如何实现IT系统高可用高可靠性的难题呢?实际上,H3C Superdome X关键业务服务器就提供了完美的解决方案。 H3C Superdome X关键业务服务器从解决方案可靠性、系统可靠性、服务器可靠性和部件可靠性四个维度,为企业提供了完整的可靠性保障。不但解决了服务器、存储等硬件基础设备的可靠性问题,而且还通过操作系统的错误分析识别、在线优化和修复等软件层面进行了优化。打包的可靠性解决方案为用户提供了高达100%的应用可用性,确保了企业关键业务的连续性。 硬件方面,为了保证设备的高可用性,H3C Superdome X关键业务服务器提供了业界独有的冗余系统时钟技术。上图可以看到,这项技术是首次引入关键业务X86系统中,支持动态自动故障转移和热插拔等。这项技术的应用,不但能够在系统出现故障后实现瞬时转移,而且能够保证技术人员在不停机的情况下实现对出现故障的硬件进行及时处理修复,确保了系统不停机,业务不断线。 系统方面,H3C Superdome X关键业务服务器提供了深入分析与自我修复功能,当系统出现故障后,会自动检测错误,收集证据并实现自我的修复。这样技术不但能够节省技术人员的运维难度,而且还能够实现快速修复。一些小的问题,在业务部门没有察觉的情况下即可以实现自我修复,完全不会影响到业务的正常进行。当然,在普通的X86系统中,由于没有这项功能,那么就需要技术人员手动进行修复,不但需要花费较长的时间,而且还会影响到前端业务的正常进行。 编辑点评:笔者认为,高可用性和高可靠性是衡量企业关键业务的最重要标准,也是最为关键的因素,与性能等诸如其它因素相比,高可用性高可靠性绝对排在首位。试想,正要进行交易的数据突然中断,将会给企业和用户带来重大的损失和影响。在H3C关键业务中,高可用性和高可靠性也放在首位,由此可见厂商对这一标准的重视程序。H3C Superdome X关键业务服务器提供的99.999%的高可用高可靠性解决方案,不但为企业节省了成本,而且降低了运维管理难度,为企业在激烈的市场竞争中奠定了扎实的基础。 本文作者:ZC 来源:51CTO

优秀的个人博客,低调大师

高颜值妹子写的一手好代码,还赢得了阿里硅谷游学大奖!

由阿里中间件与天池联合举办的『阿里中间件性能挑战赛』决赛答辩会于8月12日在著名学府清华大学举行。 本次大赛吸引到了来自413所知名高校的学生,以及众多来自业界的工程师,共计1946支队伍,近2500人。大赛为选手们开放了阿里电商业务中最具挑战的双十一实时交易真实场景,以及阿里中间件多项开源产品(JStorm/Tair/RocketMQ)。 大赛历时1个多月,选手们可以通过挑战充分展现自己的技术实力。第二赛季入围TOP10的队伍齐聚现场进行最后的巅峰对决。 ▼ TOP10选手风采墙 ▼ ▼答辩会现场 ▼ 精彩记录 ▼ 《阿里大中台战略揭秘》▼ 阿里中间件掌门人蒋江伟(小邪)分享 ▼ 《在阿里技术平台上创业钉钉》▼ 钉钉CTO朱鴻(一粟)分享 ▼ 大赛评委 - 阿里中间件资深技术专家沈询 ▼ ▼ 大赛评委 - 阿里中间件资深技术专家纪君祥 ▼ ▼ 大赛

优秀的个人博客,低调大师

让 AI 拥有「手」和「眼」:我把 Claude 关进一个 PHP 容器后,Vibe Coding 才算真正闭环

接上集:阿杰用 php-vibe-coding-frame 解决了「AI 写代码的幻觉」,三行闭包一次跑通。可他很快发现,框架只是第一道坎。周五晚上十一点,阿杰盯着屏幕上的 500 错误发呆。这是他这周第三次了。上集他听老陈的建议,把项目从「全家桶」框架换成了 php-vibe-coding-frame——AI 写代码的幻觉问题确实压下去了。可新问题比想象中来得更狠:

优秀的个人博客,低调大师

《Spring 手撸专栏》第 7 章:所向披靡,实现应用上下文,自动识别、资源加载、扩展机制

持续坚持原创输出,点击蓝字关注我吧 作者:小傅哥博客:https://bugstack.cn ❝ 沉淀、分享、成长,让自己和他人都能有所收获!😜 ❞ 目录 一、前言 二、目标 三、设计 四、实现 1. 工程结构 2. 定义 BeanFactoryPostProcessor 3. 定义 BeanPostProcessor 4. 定义上下文接口 5. 应用上下文抽象类实现 6. 获取Bean工厂和加载资源 7. 上下文中对配置信息的加载 8. 应用上下文实现类(ClassPathXmlApplicationContext) 9. 在Bean创建时完成前置和后置处理 五、测试 1. 事先准备 2. 实现 BeanPostProcessor 和 BeanFactoryPostProcessor 3. 配置文件 4. 不用应用上下文 5. 使用应用上下文 六、总结 七、系列推荐 一、前言 你这代码,可不能写死了呀! 依照项目落地经验来看,我们在承接紧急的产品需求时候,通常会选择在原有同类项目中进行扩展,如果没有相关类型项目的储备,也可能会选择临时搭建出一个工程来实现产品的需求。但这个时候就会遇到非常现实的问题,选择完整的设计和开发就可能满足不了上线时间,临时拼凑式的完成需求又可能不具备上线后响应产品的临时调整。 上线后的调整有哪些呢?项目刚一上线,运营了还不到半天,老板发现自己的配置的活动好像金额配置的太小了,用户都不来,割不到韭菜呀。赶紧半夜联系产品,来来来,你给我这改改,那修修,把人均优惠1万元放大大的,把可能两字缩小放在后面。再把优惠的奖金池配置从10元调整11元,快快快,赶紧修改,你修改了咱们能赚1个亿!!! 好家伙,项目是临时开发堆出来的,没有后台系统、没有配置中心、没有模块拆分,老板一句句改改改,产品来传达催促,最后背锅的可就是研发了。你这不能写死,这优惠配置得抽出来,这文案也后台下发吧,这接口入参也写死了,再写一个新接口吧! 一顿操作猛如虎,研发搬砖修接口,运营折腾好几宿,最后PV150! 无论业务、产品、运营如何,但就研发自身来讲,尽可能的要不避免临时堆出一个服务来,尤其是在团队建设初期或者运营思路经常调整的情况下,更要注重设计细节和实现方案。哪怕去报风险延期,也不要让自己背上一个明知是烂坑还要接的活。 而本章节说到不把代码写死,就是因为我们需要继续在手写 Spring 框架中继续扩展新的功能,如一个Bean的定义和实例化的过程前后,是否可以满足我们进行自定义扩展,对Bean对象执行一些修改、增强、记录等操作呢?这个过程基本就是你在使用 Spring 容器框架时候做的一些中间件扩展开发。 二、目标 如果你在自己的实际工作中开发过基于 Spring 的技术组件,或者学习过关于 SpringBoot 中间件设计和开发 等内容。那么你一定会继承或者实现了 Spring 对外暴露的类或接口,在接口的实现中获取了 BeanFactory 以及 Bean 对象的获取等内容,并对这些内容做一些操作,例如:修改 Bean 的信息,添加日志打印、处理数据库路由对数据源的切换、给 RPC 服务连接注册中心等。 在对容器中 Bean 的实例化过程添加扩展机制的同时,还需要把目前关于 Spring.xml 初始化和加载策略进行优化,因为我们不太可能让面向 Spring 本身开发的 DefaultListableBeanFactory 服务,直接给予用户使用。修改点如下: DefaultListableBeanFactory、XmlBeanDefinitionReader,是我们在目前 Spring 框架中对于服务功能测试的使用方式,它能很好的体现出 Spring 是如何对 xml 加载以及注册Bean对象的操作过程,但这种方式是面向 Spring 本身的,还不具备一定的扩展性。 就像我们现在需要提供出一个可以在 Bean 初始化过程中,完成对 Bean 对象的扩展时,就很难做到自动化处理。所以我们要把 Bean 对象扩展机制功能和对 Spring 框架上下文的包装融合起来,对外提供完整的服务。 三、设计 为了能满足于在 Bean 对象从注册到实例化的过程中执行用户的自定义操作,就需要在 Bean 的定义和初始化过程中插入接口类,这个接口再有外部去实现自己需要的服务。那么在结合对 Spring 框架上下文的处理能力,就可以满足我们的目标需求了。整体设计结构如下图: 满足于对 Bean 对象扩展的两个接口,其实也是 Spring 框架中非常具有重量级的两个接口: BeanFactoryPostProcess 和 BeanPostProcessor,也几乎是大家在使用 Spring 框架额外新增开发自己组建需求的两个必备接口。 BeanFactoryPostProcessor,是由 Spring 框架组建提供的容器扩展机制,允许在 Bean 对象注册后但未实例化之前,对 Bean 的定义信息 BeanDefinition 执行修改操作。 BeanPostProcessor,也是 Spring 提供的扩展机制,不过 BeanPostProcessor 是在 Bean 对象实例化之后修改 Bean 对象,也可以替换 Bean 对象。这部分与后面要实现的 AOP 有着密切的关系。 同时如果只是添加这两个接口,不做任何包装,那么对于使用者来说还是非常麻烦的。我们希望于开发 Spring 的上下文操作类,把相应的 XML 加载 、注册、实例化以及新增的修改和扩展都融合进去,让 Spring 可以自动扫描到我们的新增服务,便于用户使用。 四、实现 1. 工程结构 small-spring-step-06└──src├──main│└──java│└──cn.bugstack.springframework│├──beans││├──factory│││├──factory││││├──AutowireCapableBeanFactory.java││││├──BeanDefinition.java││││├──BeanFactoryPostProcessor.java││││├──BeanPostProcessor.java││││├──BeanReference.java││││├──ConfigurableBeanFactory.java││││└──SingletonBeanRegistry.java│││├──support││││├──AbstractAutowireCapableBeanFactory.java││││├──AbstractBeanDefinitionReader.java││││├──AbstractBeanFactory.java││││├──BeanDefinitionReader.java││││├──BeanDefinitionRegistry.java││││├──CglibSubclassingInstantiationStrategy.java││││├──DefaultListableBeanFactory.java││││├──DefaultSingletonBeanRegistry.java││││├──InstantiationStrategy.java││││└──SimpleInstantiationStrategy.java│││├──support││││└──XmlBeanDefinitionReader.java│││├──BeanFactory.java│││├──ConfigurableListableBeanFactory.java│││├──HierarchicalBeanFactory.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│└──utils│└──ClassUtils.java└──test└──java└──cn.bugstack.springframework.test├──bean│├──UserDao.java│└──UserService.java├──common│├──MyBeanFactoryPostProcessor.java│└──MyBeanPostProcessor.java└──ApiTest.java 工程源码:公众号「bugstack虫洞栈」,回复:Spring 专栏,获取完整源码 Spring 应用上下文和对Bean对象扩展机制的类关系,如图 7-3 图 7-3 在整个类图中主要体现出来的是关于 Spring 应用上下文以及对 Bean 对象扩展机制的实现。 以继承了 ListableBeanFactory 接口的 ApplicationContext 接口开始,扩展出一系列应用上下文的抽象实现类,并最终完成 ClassPathXmlApplicationContext 类的实现。而这个类就是最后交给用户使用的类。 同时在实现应用上下文的过程中,通过定义接口: BeanFactoryPostProcessor、 BeanPostProcessor 两个接口,把关于对 Bean 的扩展机制串联进去了。 2. 定义 BeanFactoryPostProcessor cn.bugstack.springframework.beans.factory.config.BeanFactoryPostProcessor publicinterfaceBeanFactoryPostProcessor{/***在所有的BeanDefinition加载完成后,实例化Bean对象之前,提供修改BeanDefinition属性的机制**@parambeanFactory*@throwsBeansException*/voidpostProcessBeanFactory(ConfigurableListableBeanFactorybeanFactory)throwsBeansException;} 在 Spring 源码中有这样一段描述 Allows for custom modification of an application context's bean definitions,adapting the bean property values of the context's underlying bean factory. 其实也就是说这个接口是满足于在所有的 BeanDefinition 加载完成后,实例化 Bean 对象之前,提供修改 BeanDefinition 属性的机制。 3. 定义 BeanPostProcessor cn.bugstack.springframework.beans.factory.config.BeanPostProcessor publicinterfaceBeanPostProcessor{/***在Bean对象执行初始化方法之前,执行此方法**@parambean*@parambeanName*@return*@throwsBeansException*/ObjectpostProcessBeforeInitialization(Objectbean,StringbeanName)throwsBeansException;/***在Bean对象执行初始化方法之后,执行此方法**@parambean*@parambeanName*@return*@throwsBeansException*/ObjectpostProcessAfterInitialization(Objectbean,StringbeanName)throwsBeansException;} 在 Spring 源码中有这样一段描述 Factory hook that allows for custom modification of new bean instances,e.g. checking for marker interfaces or wrapping them with proxies.也就是提供了修改新实例化 Bean 对象的扩展点。 另外此接口提供了两个方法: postProcessBeforeInitialization 用于在 Bean 对象执行初始化方法之前,执行此方法、 postProcessAfterInitialization用于在 Bean 对象执行初始化方法之后,执行此方法。 4. 定义上下文接口 cn.bugstack.springframework.context.ApplicationContext publicinterfaceApplicationContextextendsListableBeanFactory{} context 是本次实现应用上下文功能新增的服务包 ApplicationContext,继承于 ListableBeanFactory,也就继承了关于 BeanFactory 方法,比如一些 getBean 的方法。另外 ApplicationContext 本身是 Central 接口,但目前还不需要添加一些获取ID和父类上下文,所以暂时没有接口方法的定义。 cn.bugstack.springframework.context.ConfigurableApplicationContext publicinterfaceConfigurableApplicationContextextendsApplicationContext{/***刷新容器**@throwsBeansException*/voidrefresh()throwsBeansException;} ConfigurableApplicationContext 继承自 ApplicationContext,并提供了 refresh 这个核心方法。 如果你有看过一些 Spring 源码,那么一定会看到这个方法。 接下来也是需要在上下文的实现中完成刷新容器的操作过程。 5. 应用上下文抽象类实现 cn.bugstack.springframework.context.support.AbstractApplicationContext publicabstractclassAbstractApplicationContextextendsDefaultResourceLoaderimplementsConfigurableApplicationContext{@Overridepublicvoidrefresh()throwsBeansException{//1.创建BeanFactory,并加载BeanDefinitionrefreshBeanFactory();//2.获取BeanFactoryConfigurableListableBeanFactorybeanFactory=getBeanFactory();//3.在Bean实例化之前,执行BeanFactoryPostProcessor(Invokefactoryprocessorsregisteredasbeansinthecontext.)invokeBeanFactoryPostProcessors(beanFactory);//4.BeanPostProcessor需要提前于其他Bean对象实例化之前执行注册操作registerBeanPostProcessors(beanFactory);//5.提前实例化单例Bean对象beanFactory.preInstantiateSingletons();}protectedabstractvoidrefreshBeanFactory()throwsBeansException;protectedabstractConfigurableListableBeanFactorygetBeanFactory();privatevoidinvokeBeanFactoryPostProcessors(ConfigurableListableBeanFactorybeanFactory){Map<String,BeanFactoryPostProcessor>beanFactoryPostProcessorMap=beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);for(BeanFactoryPostProcessorbeanFactoryPostProcessor:beanFactoryPostProcessorMap.values()){beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);}}privatevoidregisterBeanPostProcessors(ConfigurableListableBeanFactorybeanFactory){Map<String,BeanPostProcessor>beanPostProcessorMap=beanFactory.getBeansOfType(BeanPostProcessor.class);for(BeanPostProcessorbeanPostProcessor:beanPostProcessorMap.values()){beanFactory.addBeanPostProcessor(beanPostProcessor);}}//...getBean、getBeansOfType、getBeanDefinitionNames方法} AbstractApplicationContext 继承 DefaultResourceLoader 是为了处理 spring.xml 配置资源的加载。 之后是在 refresh() 定义实现过程,包括: 提前实例化单例Bean对象 BeanPostProcessor 需要提前于其他 Bean 对象实例化之前执行注册操作 在 Bean 实例化之前,执行 BeanFactoryPostProcessor (Invoke factory processors registered as beans in the context.) 获取 BeanFactory 创建 BeanFactory,并加载 BeanDefinition 另外把定义出来的抽象方法,refreshBeanFactory()、getBeanFactory() 由后面的继承此抽象类的其他抽象类实现。 6. 获取Bean工厂和加载资源 cn.bugstack.springframework.context.support.AbstractRefreshableApplicationContext publicabstractclassAbstractRefreshableApplicationContextextendsAbstractApplicationContext{privateDefaultListableBeanFactorybeanFactory;@OverrideprotectedvoidrefreshBeanFactory()throwsBeansException{DefaultListableBeanFactorybeanFactory=createBeanFactory();loadBeanDefinitions(beanFactory);this.beanFactory=beanFactory;}privateDefaultListableBeanFactorycreateBeanFactory(){returnnewDefaultListableBeanFactory();}protectedabstractvoidloadBeanDefinitions(DefaultListableBeanFactorybeanFactory);@OverrideprotectedConfigurableListableBeanFactorygetBeanFactory(){returnbeanFactory;}} 在 refreshBeanFactory() 中主要是获取了 DefaultListableBeanFactory 的实例化以及对资源配置的加载操作 loadBeanDefinitions(beanFactory),在加载完成后即可完成对 spring.xml 配置文件中 Bean 对象的定义和注册,同时也包括实现了接口 BeanFactoryPostProcessor、BeanPostProcessor 的配置 Bean 信息。 但此时资源加载还只是定义了一个抽象类方法 loadBeanDefinitions(DefaultListableBeanFactory beanFactory),继续由其他抽象类继承实现。 7. 上下文中对配置信息的加载 cn.bugstack.springframework.context.support.AbstractXmlApplicationContext publicabstractclassAbstractXmlApplicationContextextendsAbstractRefreshableApplicationContext{@OverrideprotectedvoidloadBeanDefinitions(DefaultListableBeanFactorybeanFactory){XmlBeanDefinitionReaderbeanDefinitionReader=newXmlBeanDefinitionReader(beanFactory,this);String[]configLocations=getConfigLocations();if(null!=configLocations){beanDefinitionReader.loadBeanDefinitions(configLocations);}}protectedabstractString[]getConfigLocations();} 在 AbstractXmlApplicationContext 抽象类的 loadBeanDefinitions 方法实现中,使用 XmlBeanDefinitionReader 类,处理了关于 XML 文件配置信息的操作。 同时这里又留下了一个抽象类方法,getConfigLocations(),此方法是为了从入口上下文类,拿到配置信息的地址描述。 8. 应用上下文实现类(ClassPathXmlApplicationContext) cn.bugstack.springframework.context.support.ClassPathXmlApplicationContext publicclassClassPathXmlApplicationContextextendsAbstractXmlApplicationContext{privateString[]configLocations;publicClassPathXmlApplicationContext(){}/***从XML中加载BeanDefinition,并刷新上下文**@paramconfigLocations*@throwsBeansException*/publicClassPathXmlApplicationContext(StringconfigLocations)throwsBeansException{this(newString[]{configLocations});}/***从XML中加载BeanDefinition,并刷新上下文*@paramconfigLocations*@throwsBeansException*/publicClassPathXmlApplicationContext(String[]configLocations)throwsBeansException{this.configLocations=configLocations;refresh();}@OverrideprotectedString[]getConfigLocations(){returnconfigLocations;}} ClassPathXmlApplicationContext,是具体对外给用户提供的应用上下文方法。 在继承了 AbstractXmlApplicationContext 以及层层抽象类的功能分离实现后,在此类 ClassPathXmlApplicationContext 的实现中就简单多了,主要是对继承抽象类中方法的调用和提供了配置文件地址信息。 9. 在Bean创建时完成前置和后置处理 cn.bugstack.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory publicabstractclassAbstractAutowireCapableBeanFactoryextendsAbstractBeanFactoryimplementsAutowireCapableBeanFactory{privateInstantiationStrategyinstantiationStrategy=newCglibSubclassingInstantiationStrategy();@OverrideprotectedObjectcreateBean(StringbeanName,BeanDefinitionbeanDefinition,Object[]args)throwsBeansException{Objectbean=null;try{bean=createBeanInstance(beanDefinition,beanName,args);//给Bean填充属性applyPropertyValues(beanName,bean,beanDefinition);//执行Bean的初始化方法和BeanPostProcessor的前置和后置处理方法bean=initializeBean(beanName,bean,beanDefinition);}catch(Exceptione){thrownewBeansException("Instantiationofbeanfailed",e);}addSingleton(beanName,bean);returnbean;}publicInstantiationStrategygetInstantiationStrategy(){returninstantiationStrategy;}publicvoidsetInstantiationStrategy(InstantiationStrategyinstantiationStrategy){this.instantiationStrategy=instantiationStrategy;}privateObjectinitializeBean(StringbeanName,Objectbean,BeanDefinitionbeanDefinition){//1.执行BeanPostProcessorBefore处理ObjectwrappedBean=applyBeanPostProcessorsBeforeInitialization(bean,beanName);//待完成内容:invokeInitMethods(beanName, wrappedBean, beanDefinition);invokeInitMethods(beanName,wrappedBean,beanDefinition);//2.执行BeanPostProcessorAfter处理wrappedBean=applyBeanPostProcessorsAfterInitialization(bean,beanName);returnwrappedBean;}privatevoidinvokeInitMethods(StringbeanName,ObjectwrappedBean,BeanDefinitionbeanDefinition){}@OverridepublicObjectapplyBeanPostProcessorsBeforeInitialization(ObjectexistingBean,StringbeanName)throwsBeansException{Objectresult=existingBean;for(BeanPostProcessorprocessor:getBeanPostProcessors()){Objectcurrent=processor.postProcessBeforeInitialization(result,beanName);if(null==current)returnresult;result=current;}returnresult;}@OverridepublicObjectapplyBeanPostProcessorsAfterInitialization(ObjectexistingBean,StringbeanName)throwsBeansException{Objectresult=existingBean;for(BeanPostProcessorprocessor:getBeanPostProcessors()){Objectcurrent=processor.postProcessAfterInitialization(result,beanName);if(null==current)returnresult;result=current;}returnresult;}} 实现 BeanPostProcessor 接口后,会涉及到两个接口方法, postProcessBeforeInitialization、 postProcessAfterInitialization,分别作用于Bean 对象执行初始化前后的额外处理。 也就是需要在创建 Bean 对象时,在 createBean 方法中添加 initializeBean(beanName, bean, beanDefinition); 操作。而这个操作主要主要是对于方法 applyBeanPostProcessorsBeforeInitialization、 applyBeanPostProcessorsAfterInitialization 的使用。 另外需要提一下,applyBeanPostProcessorsBeforeInitialization、applyBeanPostProcessorsAfterInitialization 两个方法是在接口类 AutowireCapableBeanFactory 中新增加的。 五、测试 1. 事先准备 cn.bugstack.springframework.test.bean.UserDao publicclassUserDao{privatestaticMap<String,String>hashMap=newHashMap<>();static{hashMap.put("10001","小傅哥");hashMap.put("10002","八杯水");hashMap.put("10003","阿毛");}publicStringqueryUserName(StringuId){returnhashMap.get(uId);}} cn.bugstack.springframework.test.bean.UserService publicclassUserService{privateStringuId;privateStringcompany;privateStringlocation;privateUserDaouserDao;publicvoidqueryUserInfo(){returnuserDao.queryUserName(uId);}//...get/set} Dao、Service,是我们平常开发经常使用的场景。在 UserService 中注入 UserDao,这样就能体现出Bean属性的依赖了。 另外这里新增加了 company、location,两个属性信息,便于测试 BeanPostProcessor、BeanFactoryPostProcessor 两个接口对 Bean 属性信息扩展的作用。 2. 实现 BeanPostProcessor 和 BeanFactoryPostProcessor cn.bugstack.springframework.test.common.MyBeanFactoryPostProcessor publicclassMyBeanFactoryPostProcessorimplementsBeanFactoryPostProcessor{@OverridepublicvoidpostProcessBeanFactory(ConfigurableListableBeanFactorybeanFactory)throwsBeansException{BeanDefinitionbeanDefinition=beanFactory.getBeanDefinition("userService");PropertyValuespropertyValues=beanDefinition.getPropertyValues();propertyValues.addPropertyValue(newPropertyValue("company","改为:字节跳动"));}} cn.bugstack.springframework.test.common.MyBeanPostProcessor publicclassMyBeanPostProcessorimplementsBeanPostProcessor{@OverridepublicObjectpostProcessBeforeInitialization(Objectbean,StringbeanName)throwsBeansException{if("userService".equals(beanName)){UserServiceuserService=(UserService)bean;userService.setLocation("改为:北京");}returnbean;}@OverridepublicObjectpostProcessAfterInitialization(Objectbean,StringbeanName)throwsBeansException{returnbean;}} 如果你在 Spring 中做过一些组件的开发那么一定非常熟悉这两个类,本文的测试也是实现了这两个类,对实例化过程中的 Bean 对象做一些操作。 3. 配置文件 基础配置,无BeanFactoryPostProcessor、BeanPostProcessor,实现类 <?xmlversion="1.0"encoding="UTF-8"?><beans><beanid="userDao"class="cn.bugstack.springframework.test.bean.UserDao"/><beanid="userService"class="cn.bugstack.springframework.test.bean.UserService"><propertyname="uId"value="10001"/><propertyname="company"value="腾讯"/><propertyname="location"value="深圳"/><propertyname="userDao"ref="userDao"/></bean></beans> 增强配置,有BeanFactoryPostProcessor、BeanPostProcessor,实现类 <?xmlversion="1.0"encoding="UTF-8"?><beans><beanid="userDao"class="cn.bugstack.springframework.test.bean.UserDao"/><beanid="userService"class="cn.bugstack.springframework.test.bean.UserService"><propertyname="uId"value="10001"/><propertyname="company"value="腾讯"/><propertyname="location"value="深圳"/><propertyname="userDao"ref="userDao"/></bean><beanclass="cn.bugstack.springframework.test.common.MyBeanPostProcessor"/><beanclass="cn.bugstack.springframework.test.common.MyBeanFactoryPostProcessor"/></beans> 这里提供了两个配置文件,一个是不包含BeanFactoryPostProcessor、BeanPostProcessor,另外一个是包含的。之所以这样配置主要对照验证,在运用 Spring 新增加的应用上下文和不使用的时候,都是怎么操作的。 4. 不用应用上下文 @Testpublicvoidtest_BeanFactoryPostProcessorAndBeanPostProcessor(){//1.初始化BeanFactoryDefaultListableBeanFactorybeanFactory=newDefaultListableBeanFactory();//2.读取配置文件&注册BeanXmlBeanDefinitionReaderreader=newXmlBeanDefinitionReader(beanFactory);reader.loadBeanDefinitions("classpath:spring.xml");//3.BeanDefinition加载完成&Bean实例化之前,修改BeanDefinition的属性值MyBeanFactoryPostProcessorbeanFactoryPostProcessor=newMyBeanFactoryPostProcessor();beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);//4.Bean实例化之后,修改Bean属性信息MyBeanPostProcessorbeanPostProcessor=newMyBeanPostProcessor();beanFactory.addBeanPostProcessor(beanPostProcessor);//5.获取Bean对象调用方法UserServiceuserService=beanFactory.getBean("userService",UserService.class);Stringresult=userService.queryUserInfo();System.out.println("测试结果:"+result);} DefaultListableBeanFactory 创建 beanFactory 并使用 XmlBeanDefinitionReader 加载配置文件的方式,还是比较熟悉的。 接下来就是对 MyBeanFactoryPostProcessor 和 MyBeanPostProcessor 的处理,一个是在BeanDefinition 加载完成 & Bean实例化之前,修改 BeanDefinition 的属性值,另外一个是在Bean实例化之后,修改 Bean 属性信息。 测试结果 测试结果:小傅哥,改为:字节跳动,改为:北京Processfinishedwithexitcode0 通过测试结果可以看到,我们配置的属性信息已经与spring.xml 配置文件中不一样了。 5. 使用应用上下文 @Testpublicvoidtest_xml(){//1.初始化BeanFactoryClassPathXmlApplicationContextapplicationContext=newClassPathXmlApplicationContext("classpath:springPostProcessor.xml");//2.获取Bean对象调用方法UserServiceuserService=applicationContext.getBean("userService",UserService.class);Stringresult=userService.queryUserInfo();System.out.println("测试结果:"+result);} 另外使用新增加的 ClassPathXmlApplicationContext 应用上下文类,再操作起来就方便多了, 这才是面向用户使用的类,在这里可以一步把配置文件交给 ClassPathXmlApplicationContext,也不需要管理一些自定义实现的 Spring 接口的类。 测试结果 测试结果:小傅哥,改为:字节跳动,改为:北京Processfinishedwithexitcode0 这与不用应用上下文的测试结果是一样,不过现在的方式更加方便了。 六、总结 本文主要新增了 Spring 框架中两个非常重要的接口 BeanFactoryPostProcess、BeanPostProcessor 同时还添加了关于应用上下文的实现,ApplicationContext 接口的定义是继承 BeanFactory 外新增加功能的接口,它可以满足于自动识别、资源加载、容器事件、监听器等功能,同时例如一些国际化支持、单例Bean自动初始化等,也是可以在这个类里实现和扩充的。 通过本文的实现一定会非常了解 BeanFactoryPostProcess、BeanPostProcessor,以后再做一些关于 Spring 中间件的开发时,如果需要用到 Bean 对象的获取以及修改一些属性信息,那么就可以使用这两个接口了。同时 BeanPostProcessor 也是实现 AOP 切面技术的关键所在。 有人问: 面试问那么多,可是工作又用不到,是嘎哈么呢?,嘎哈么,那你说你开车上桥的时候,会每次都撞两边的护栏吗,不撞是吧,那不要修了哇,直接就铺一个平板,还省材料了。其实核心技术的原理学习,是更有助于你完成更复杂的架构设计,当你的知识能更全面覆盖所承接的需求时,也就能更好的做出合理的架构和落地。 七、系列推荐 小傅哥,一个有“副业”的码农! 久等了,小傅哥的《重学Java设计模式》终于出版了,彩印&纸质! 半年招聘筛选了400+份简历,告诉你怎么写容易被撩! 一次代码评审,差点过不了试用期! 大学四年到毕业工作5年的学习路线资源汇总 - END - 下方扫码关注 bugstack虫洞栈,与小傅哥一起学习成长、共同进步,做一个码场最贵Coder! 回复【设计模式】,获取《重学Java设计模式》,这是一本互联网真实案例的实践书籍,从实际业务中抽离出,交易、营销、秒杀、中间件、源码等众多场景进行学习代码设计。 回复【面经手册】,获取《面经手册•拿大厂Offer》,这是一本有深度的Java核心内容,从数据结构、算法、并发编程以及JVM系8不断深入讲解,让懂了就是真的懂。 你好,我是小傅哥。一线互联网 java 工程师、架构师,开发过交易&营销、写过运营&活动、设计过中间件也倒腾过中继器、IO板卡。不只是写Java语言,也搞过C#、PHP,是一个技术活跃的折腾者。 2020年写了一本PDF 《重学Java设计模式》 ,全网下载量50万+,帮助很多同学成长,现已出书。同年 github 的两个项目, CodeGuide 、 itstack-demo-design ,持续霸榜 Trending,成为全球热门项目。 2021年上架一本小册 《SpringBoot 中间件设计和开发》 ,16个互联网中间件场景、30个工程,是全网唯一一次手把手教你造轮子、写中间件,因为这样的技术离P7最近、离架构师最近、离高薪资最近! 本文分享自微信公众号 - bugstack虫洞栈(bugstack)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

资源下载

更多资源
Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册