继承bean并重写方法逻辑以替换原有实现

在企业产品化项目中,当需要针对特定客户需求实现个性化业务逻辑时,可以通过继承原有实现类并重写方法来达成。本文介绍了如何定义注解、创建个性化实现,并在不改变原有代码结构的情况下,实现Bean的替换,以满足定制化需求,同时保持代码的整洁和维护性。

前言

在企业产品化项目中,各个业务处理一般都有标准(通用)实现逻辑,以应对该产品(业务)面对的常见通用型需求。而如果产品下发给某个客户,且该客户要求某个业务逻辑需要做部分微小的个性化处理时,通常有以下几种处理方式:

其一,客户化的业务实现交给非产品模块,即交给个性化模块处理特殊业务,接口调用时同步改成调用该个性化接口,对产品层无影响,但另一方面对于较为复杂、关联处理较多的业务逻辑,显然改动点就大了;

其二,在产品代码中通过增加配置的方式,来处理该客户的个性逻辑,配置不启用也不会影响现有产品主逻辑,但是长此以往把各个客户的特殊处理都杂糅进来后,产品的代码将会变得十分臃肿和难以维护;

其三,如果产品代码在设计时预留了扩展的接口,则也只需要在个性化模块中做扩展实现即可,也不影响产品代码,但通常客户的需求是难以猜测的,具体怎么留有扩展也十分考验产品开发团队的业务和技术水平;

本文针对此问题,结合实际场景,分享一种通过继承原有实现类的bean方式,达到重写其原有方法,又不影响原先bean之间的依赖和调用关系。

定义注解OverrideBean

自定义重写bean注解,用于标注该bean是重写原来实现的类的bean(替代产品化实现bean

package mine.code.config.annotation;

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

/**
 * 自定义重写bean注解
 *
 * @author BlueDriver
 * @email cpwu@foxmail.com
 * @date 2022/6/27 20:01
 * -----------------------------------------
 * Gitee: https://gitee.com/BlueDriver
 * Github: https://github.com/BlueDriver
 * -----------------------------------------
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OverrideBean {

}

定义OverrideBeanDefinitionRegistryPostProcessor

用于将重写的bean替换其原先的bean(个性化实现bean替换产品实现bean),具体实现原理可结合注释和下文示例理解,建议配合源码食用(源码链接见文章末尾)

package mine.code.config.processor;

import mine.code.config.annotation.OverrideBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * 重写bean注册处理
 *
 * @author BlueDriver
 * @email cpwu@foxmail.com
 * @date 2022/6/27 20:02
 * -----------------------------------------
 * Gitee: https://gitee.com/BlueDriver
 * Github: https://github.com/BlueDriver
 * -----------------------------------------
 */
@Component
public class OverrideBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware {
    private static final Logger LOGGER = LoggerFactory.getLogger(OverrideBeanDefinitionRegistryPostProcessor.class);
    /**
     * 业务bean实现类前缀(用于过滤不必要的bean处理)
     */
    public static final String KEY_BIZ_BEAN_CLASS_PREFIX = "mine.biz.bean.class.prefix";
    /**
     * 业务bean实现类前缀默认值
     */
    private static final String DEFAULT_BIZ_BEAN_CLASS_PREFIX = "mine.code";
    /**
     * 业务bean实现类前缀(包名)
     */
    private String bizBeanClassPrefix;


    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // do nothing
    }

    /**
     * 核心逻辑为用OverrideBean替换注册被继承的bean
     */
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        // 所有业务bean的map,key为bean实现类的类名,value为bean名称
        HashMap<String, String> bizBeanImplClassName2BeanNameMap = new HashMap<>();

        // 所有重写的业务bean(含OverrideBean注解且继承了另一个bean实现类)的map,
        // key为overrideBean的实现类的父类的类名,value为bean名称
        HashMap<String, String> overrideBizBeanImplParentClassName2BeanNameMap = new HashMap<>();

        // 按bean名称遍历所有的bean定义,以初始化className2BeanNameMap和overrideBeanClassName2BeanNameMap
        for (String beanName : registry.getBeanDefinitionNames()) {
            // 获取bean定义
            BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);

            // bean实现类名
            String beanImplClassName = beanDefinition.getBeanClassName();

            // bean对应的实现类名不存在 或 不是自己指定的某个服务包目录下的bean(所有的业务服务bean都应在此包目录下)
            if (beanImplClassName == null || !beanImplClassName.startsWith(bizBeanClassPrefix)) {
                continue;
            }

            // 将所有的业务bean定义放入map
            bizBeanImplClassName2BeanNameMap.put(beanImplClassName, beanName);

            try {
                // 加载bean实现类对应的类
                Class<?> beanImplClass = Class.forName(beanDefinition.getBeanClassName());

                // 判断bean类上有没有【OverrideBean】重写bean注解
                OverrideBean overrideBean = beanImplClass.getAnnotation(OverrideBean.class);
                if (overrideBean != null && beanImplClass.getGenericSuperclass() != Object.class) {
                    // 有注解,放到map,key为所继承的父类的类名(即被覆盖的bean的实现类)
                    overrideBizBeanImplParentClassName2BeanNameMap.put(beanImplClass.getGenericSuperclass().getTypeName(), beanName);
                }
            } catch (Exception e) {
                LOGGER.error("处理OverrideBean异常", e);
            }
        }

        // 遍历所有重写bean,并替换注册被重写的bean(重写的bean以其父类bean的名称注册代之)
        for (Map.Entry<String, String> overrideBeanEntry : overrideBizBeanImplParentClassName2BeanNameMap.entrySet()) {
            // bean实现类的类名(被重写bean的父类,即被继承的bean的实现类)
            String originalBeanImplClassName = overrideBeanEntry.getKey();

            // bean名称
            String overrideBeanName = overrideBeanEntry.getValue();

            // 从所有beanMap中取出被继承父类对应的(被重写bean类型)的bean名称
            String originalBeanName = bizBeanImplClassName2BeanNameMap.get(originalBeanImplClassName);
            BeanDefinition originalBeanDefinition = registry.getBeanDefinition(originalBeanName);

            // 移除掉原bean定义
            registry.removeBeanDefinition(originalBeanName);

            // 将重写bean以原bean名称注册
            BeanDefinition overrideBeanDefinition = registry.getBeanDefinition(overrideBeanName);
            registry.registerBeanDefinition(originalBeanName, overrideBeanDefinition);

            // 移除重写bean注册
            registry.removeBeanDefinition(overrideBeanName);


            LOGGER.warn("OverrideBean: 将bean的实现类由[{}]替换为[{}]",
                    originalBeanDefinition.getBeanClassName(), overrideBeanDefinition.getBeanClassName());
        }

        // 清空map
        bizBeanImplClassName2BeanNameMap.clear();
        overrideBizBeanImplParentClassName2BeanNameMap.clear();
    }

    /**
     * 初始化bean类前缀配置
     */
    @Override
    public void setEnvironment(Environment environment) {
        bizBeanClassPrefix = environment.getProperty(KEY_BIZ_BEAN_CLASS_PREFIX, DEFAULT_BIZ_BEAN_CLASS_PREFIX);
    }
}

效果演示

接口类定义
package mine.code.standard.service.inter;

/**
 * @author BlueDriver
 * @email cpwu@foxmail.com
 * @date 2022/6/27 20:26
 * -----------------------------------------
 * Gitee: https://gitee.com/BlueDriver
 * Github: https://github.com/BlueDriver
 * -----------------------------------------
 */
public interface UserService {
    String hello();

    String getUserNameById(int id);
}
产品标准实现
package mine.code.standard.service.impl;

import mine.code.standard.service.inter.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class StandardUserServiceImpl implements UserService {
    /**
     * 日志对象
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(StandardUserServiceImpl.class);

    @Override
    public String getUserNameById(int id) {
        LOGGER.info("getUserNameById标准实现");
        return "StandardName_" + id;
    }

    @Override
    public String hello() {
        return "StandardUserServiceImpl";
    }
}

调用

@SpringBootTest(classes = StandardBizApplication.class)
public class ApplicationTests {
    @Autowired
    private UserService userInter;

    @Test
    public void testLogin() {
        String userName = userInter.getUserNameById(1);
        System.out.println(userName);
    }
}

输出:

2022-06-29 21:14:51.610  INFO 9812 --- [           main] m.c.s.s.impl.StandardUserServiceImpl     : getUserNameById标准实现
StandardName_1
个性化实现
package mine.code.personalized.service.impl;

import mine.code.config.annotation.OverrideBean;
import mine.code.standard.service.impl.StandardUserServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * 个性化实现bean,其继承了产品实现类
 */
@Component
@OverrideBean
public class PersonalizedUserServiceImpl extends StandardUserServiceImpl {
    /**
     * 日志对象
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(PersonalizedUserServiceImpl.class);

    @Override
    public String getUserNameById(int id) {
        LOGGER.info("getUserNameById个性化实现");
        return "PersonalizedName_" + id;
    }

    @Override
    public String hello() {
        return "PersonalizedUserServiceImpl";
    }
}

调用:

package mine.code;

import mine.code.standard.service.inter.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest(classes = PersonalizedBizApplication.class)
public class ApplicationTests {
    @Autowired
    private UserService userInter;

    @Test
    public void testLogin() {
        String userName = userInter.getUserNameById(1);
        System.out.println(userName);
    }
}

输出:

2022-06-29 21:35:42.115  WARN 12916 --- [           main] rrideBeanDefinitionRegistryPostProcessor : OverrideBean: 将bean的实现类由[mine.code.standard.service.impl.StandardUserServiceImpl]替换为[mine.code.personalized.service.impl.PersonalizedUserServiceImpl]

2022-06-29 21:35:43.402  INFO 12916 --- [           main] m.c.p.s.i.PersonalizedUserServiceImpl    : getUserNameById个性化实现
PersonalizedName_1

总结

在不改变原先实现类的情况下,通过继承该实现类并在bean注册阶段进行bean替换,我们达到了自定义重写产品实现类的逻辑

源码

https://gitee.com/BlueDriver/code-demo/tree/master/demo/override-bean

其他

本文仅供参考学习,还望指正!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值