BeanDefinitionRegistryPostProcessor与动态代理配合使用例子

本文介绍如何结合BeanDefinitionRegistryPostProcessor和动态代理,实现在Spring启动时将带有自定义注解@MyReference的类替换为代理类。通过创建ProxyFactoryBean并利用Spring Boot的Spring Factories机制,在bean初始化前替换beanDefinition,使得调用被注解的类实际上调用了代理类,从而在运行时实现特定功能,如向远程发送请求。
摘要由CSDN通过智能技术生成

实现这样一种功能:
自定义了一个注解@MyReference,

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyReference{
   
}

被它注解的字段是就是我们要代理的类,希望在Spring启动时将代理类注入到这些被该注解标识的字段。

如何实现:

1,如何实现在Spring启动后将被@MyReference标注的类的替换 ?

将代理类的beanDefination注册到容器中,并将其与委托类在容器中的name关联,这样容器注入的就是我们的代理类了。
利用 BeanDefinitionRegistryPostProcessor 来实现。

这里我们代理类的功能是一样的,都是获取委托类的信息来向远端发送请求再获得结果,所以利用FactoryBeanInitializingBean,创建一个叫 ProxyFactoryBean 的类实现它们,内部声明一个成员变量用来标识委托类的类型,afterPropertiesSet方法中根据类型创建对应代理类,该方法在初始化bean时被调用;对于每个标注类都会创建一个 ProxyFactoryBean 类型的beanDefination。

这样我们项目下所有被标注的类,其在Spring容器中的BeanDefination实质上是个FactoryBean,而Spring在获取一个Bean实例时若发现其是FactoryBean,则调用它的getObject,由于我们实现了InitializingBean,在bean初始化时afterPropertiesSet被调用,我们在该方法里根据类型创建该标注类的代理类对象,getObject返回的也是它。具体代码实现在下面。

2,我们使用的是SpringBoot,上述功能作为一个独立的模块,在项目中进行依赖,需要在容器启动时进行触发,如何触发?利用Spring Boot的Spring Factories机制来实现。

关于Spring Factories推荐两篇文章:
Spring Boot的扩展机制之Spring Factories
EnableAutoConfiguration注解的工作原理

功能模块的resources目录下 META-INF/spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.miao.client.MyAutoConfiguration

MyAutoConfiguration

@Configuration
@ConditionalOnMissingBean(ProxyFactoryBeanRegistry.class)
@EnableConfigurationProperties(ClientProperties.class)
public class MyAutoConfiguration{
   

    @Autowired
    private ClientProperties properties;
    
    // 为什么为static? 因为下面的proxyFactoryBeanRegistry方法中要用到client
    // 而该方法必须是static的,因为在@Configuration的类里,若@Bean标注的方法的
    // 返回类型是BeanDefinitionRegistryPostProcessor,则该方法必须是static的
    // https://github.com/ulisesbocchio/jasypt-spring-boot/issues/45
    //https://stackoverflow.com/questions/41939494/springboot-cannot-enhance-configuration-bean-definition-beannameplaceholderreg
    private static Client client = new Client();

    @Bean
    public Client client() {
   
        log.info("初始化Client设置discovery");
        ServiceDiscovery discovery = ......
        client.setDiscovery(discovery);
        client.init();
        return client;
    }
    
    /**
     * Cannot enhance @Configuration bean definition 'com.miao.rpc.client.RpcClientAutoConfiguration'
     * since its 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值