热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Java流程定义组件,如何写好一个Spring组件

背景Spring框架提供了许多接口,可以使用这些接口来定制化bean,而非简单的gettersetter或者构造器注入。细翻SpringCloudNet

a27ce94ed6bf766dc2da297f2e88a56c.png

背景

Spring 框架提供了许多接口,可以使用这些接口来定制化 bean ,而非简单的 getter/setter 或者构造器注入。细翻 Spring Cloud Netflix、Spring Cloud Alibaba 等这些构建在 Spring Framework 的成熟框架源码,你会发现大量的扩展 bean 例如

Eureka 健康检查

package org.springframework.cloud.netflix.eureka;

public class EurekaHealthCheckHandler implements InitializingBean {}

Seata Feign 配置

package com.alibaba.cloud.seata.feign;

public class SeataContextBeanPostProcessor implements BeanPostProcessor {}

代码示例

0ae1e393ed2124a585f59d0374176ca5.png

DemoBean

@Slf4j

public class DemoBean implements InitializingBean {

public DemoBean() {

log.info("--> instantiate ");

}

@PostConstruct

public void postConstruct() {

log.info("--> @PostConstruct ");

}

@Override

public void afterPropertiesSet() throws Exception {

log.info("--> InitializingBean.afterPropertiesSet ");

}

public void initMethod() {

log.info("--> custom initMehotd");

}

}

DemoBeanPostProcessor

@Configuration

public class DemoBeanPostProcessor implements BeanPostProcessor {

@Override

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

if ("demoBean".equals(beanName)){

log.info("--> BeanPostProcessor.postProcessBeforeInitialization ");

}

return bean;

}

@Override

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

if ("demoBean".equals(beanName)){

log.info("--> BeanPostProcessor.postProcessAfterInitialization ");

}

return bean;

}

}

DemoConfig

@Configuration

public class DemoConfig {

@Bean(initMethod = "initMethod")

public DemoBean demoBean() {

return new DemoBean();

}

}

运行输出日志

整个 bean 的创建过程日志输出如下和文首图片横线以上 bean 创建周期一致

DemoBean : --> instantiate

DemoBeanPostProcessor: --> BeanPostProcessor.postProcessBeforeInitialization

DemoBean : --> @PostConstruct

DemoBean : --> InitializingBean.afterPropertiesSet

DemoBean : --> custom initMehotd

DemoBeanPostProcessor: --> BeanPostProcessor.postProcessAfterInitialization

执行过程核心源码

AbstractAutowireCapableBeanFactory.initializeBean

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {

// 执行BeanPostProcessor.postProcessBeforeInitialization

Object wrappedBean = wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);

...

// 执行用户自定义初始化and JSR 250 定义的方法

invokeInitMethods(beanName, wrappedBean, mbd);

...

// 执行执行BeanPostProcessor.postProcessAfterInitialization

wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

return wrappedBean;

}

下文就详细说明一下每个 bean 的扩展周期的最佳使用场景

BeanPostProcessor

10b3f170354c966e9c5a84dcbd11efc6.png

BeanPostProcessor 是一个可以自定义实现回调方法接口,来实现自己的实例化逻辑、依赖解决逻辑等,如果想要在 Spring 完成对象实例化、配置、初始化之后实现自己的业务逻辑,可以通过扩展实现一个或多个 BeanPostProcessor 处理。

多用于适配器模式,可以在实现同一接口 bean 创建前后进行包装转换

// seata 上下文转换,将其他类型 wrap 成 SeataFeignContext

public class SeataContextBeanPostProcessor implements BeanPostProcessor {

@Override

public Object postProcessBeforeInitialization(Object bean, String beanName){

if (bean instanceof FeignContext && !(bean instanceof SeataFeignContext)) {

return new SeataFeignContext(getSeataFeignObjectWrapper(),

(FeignContext) bean);

}

return bean;

}

}

自定义 注解查找扩展

net.dreamlu.mica.redisson.stream.RStreamListenerDetector 查找自定义 @RStreamListener 实现 基于 Redisson 的 pub/sub

public class RStreamListenerDetector implements BeanPostProcessor {

@Override

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

Class> userClass = ClassUtils.getUserClass(bean);

ReflectionUtils.doWithMethods(userClass, method -> {

RStreamListener listener = AnnotationUtils.findAnnotation(method, RStreamListener.class);

.... do something

}, ReflectionUtils.USER_DECLARED_METHODS);

return bean;

}

}

PostConstruct

JavaEE5 引入了@PostConstruct 作用于 Servlet 生命周期的注解,实现 Bean 初始化之前的自定义操作。

只能有一个非静态方法使用此注解

被注解的方法不能有返回值和方法参数

被注解的方法不得抛出异常

这里需要注意的 这个注解不是 Spring 定义的,而是属于 JavaEE JSR-250 规范定义的注解,当你在使用 Java11 的时候要手动引入相关 jar(因为 Java11 移除了)

javax.annotation

javax.annotation-api

使用场景: 在之前的版本,我们可以在启动后通过 @PostConstruct 注解的方法执行初始化数据。但由于 Java 高版本已经移除相关 API ,我们不推荐使用此 注解,可以通过 Spring 相关 Event 回调事件处理

@PostConstruct 注解的方法在项目启动的时候执行这个方法,也可以理解为在 spring 容器启动的时候执行,可作为一些数据的常规化加载,比如数据字典之类的。

InitializingBean

79e2fe62ba43cf350758057025c7adf9.png

InitializingBean 接口方法会在 容器初始化(getter/setter/构造器)完成 bean 的属性注入后执行。

应用场景: 动态修改容器注入的 Bean 参数

正常用户配置参数注入到 bean

security:

oauth2:

ignore-urls:

- '/ws/**'

@ConfigurationProperties(prefix = "security.oauth2")

public class PermitAllUrlProperties {

@Getter

@Setter

private List ignoreUrls &#61; new ArrayList<>();

}

我们发现此时用户配置并不完整&#xff0c;还有一些通用不需要用户维护&#xff0c;可通过实现 InitializingBean 接口回调扩展

&#64;ConfigurationProperties(prefix &#61; "security.oauth2.ignore")

public class PermitAllUrlProperties implements InitializingBean {

&#64;Getter

&#64;Setter

private List urls &#61; new ArrayList<>();

&#64;Override

public void afterPropertiesSet() {

urls.add("/common/*");

}

}

initMethod

上文 &#64;PostConstruct 已经不推荐大家使用&#xff0c;可以使用 Bean(initMethod &#61; &#39;initMehotd&#39;) 替代&#xff0c;相关的限制如上。

&#64;Bean(initMethod &#61; "initMethod")

public DemoBean demoBean() {

return new DemoBean();

}

public void initMethod() {

log.info("--> custom initMehotd");

}

总结



推荐阅读
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 闭包一直是Java社区中争论不断的话题,很多语言都支持闭包这个语言特性,闭包定义了一个依赖于外部环境的自由变量的函数,这个函数能够访问外部环境的变量。本文以JavaScript的一个闭包为例,介绍了闭包的定义和特性。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 浏览器中的异常检测算法及其在深度学习中的应用
    本文介绍了在浏览器中进行异常检测的算法,包括统计学方法和机器学习方法,并探讨了异常检测在深度学习中的应用。异常检测在金融领域的信用卡欺诈、企业安全领域的非法入侵、IT运维中的设备维护时间点预测等方面具有广泛的应用。通过使用TensorFlow.js进行异常检测,可以实现对单变量和多变量异常的检测。统计学方法通过估计数据的分布概率来计算数据点的异常概率,而机器学习方法则通过训练数据来建立异常检测模型。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
author-avatar
手机用户2602896875
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有