接口不需要实现类即可完成bean的注册

345 阅读2分钟
  • 以下无全部实现,只实现了核心部分

  • 需要实现的效果

  • 跟springcloud的 @FeignClient注解一样不需要传统的实现类就能跟正常的bean一样使用
  • @Autowired能注入使用
  • 分解各个步骤

  • 自定义注解,定义所需的参数
  • 使用spring的扫包获取interface上的特定注解类
  • 为每个interface使用BeanDefinition注册到IOC容器
  • 验证和代码实现BeanDefinition注册到IOC容器

这里我只是将各个点给串在一起,实现特定的业务需要,只是提供一种思想和部分逻辑的验证,其余逻辑相信大家都能实现.

  • 相关代码
public class User {

    private Long id;

    private String name;
}
@Import(AnnotationBeanDefinitionDemo.Config.class)
public class AnnotationBeanDefinitionDemo {

    @Autowired
    public static void main(String[] args) {
        //创建BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext =new AnnotationConfigApplicationContext();
        //注册 Configuration(配置类)
        applicationContext.register(AnnotationBeanDefinitionDemo.class);
        //启动 spring 应用上下文
        applicationContext.refresh();
        //按类型查找查找依赖
        //命名bean的注册方式
        registerBeanDefinitionRegistry(applicationContext,"test",User.class);
        //非命名bean的注册方式
        registerBeanDefinitionRegistry(applicationContext,User.class);

        System.out.println("config 类型的所有beans" + applicationContext.getBeansOfType(Config.class));
        System.out.println("user 类型的所有beans" + applicationContext.getBeansOfType(User.class));
        //显示的关闭 Spring 上下文
        applicationContext.close();
    }

    /**
     *  命名bean的注册方式
     * @param registry
     * @param beanName
     * @param beanClass
     */
    public static void registerBeanDefinitionRegistry(BeanDefinitionRegistry registry,String beanName,Class<?> beanClass){
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(beanClass);
        beanDefinitionBuilder.addPropertyValue("id",10L)
                .addPropertyValue("name","tt.victor");
        if (StringUtils.hasText(beanName)){
            //命名bean的注册方式
            registry.registerBeanDefinition(beanName,beanDefinitionBuilder.getBeanDefinition());
        }else {
            //非命名bean的注册方式
            BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinitionBuilder.getBeanDefinition(),registry);
        }
    }
    public static void registerBeanDefinitionRegistry(BeanDefinitionRegistry registry,Class<?> beanClass){
        registerBeanDefinitionRegistry(registry,null,beanClass);
    }

    //2,通过 @Component 方式定义
    @Component
    public static class Config{
        //1,通过 @Bean 方式定义
        @Bean(name = {"user","st-user"})
        public User user(){
            User user= new User();
            user.setName("st");
            user.setId(11L);
            return user;
        }
    }
}

核心代码

image.png 运行代码,得到结果

config 类型的所有beans{org.victor.spring.bean.definition.AnnotationBeanDefinitionDemo$Config=org.victor.spring.bean.definition.AnnotationBeanDefinitionDemo$Config@13c27452}
user 类型的所有beans{user=User{id=11, name='st', city=null, workCity=null, lifeCities=null}, test=User{id=10, name='tt.victor', city=null, workCity=null, lifeCities=null}, org.victor.spring.ioc.dependency.domain.User#0=User{id=10, name='tt.victor', city=null, workCity=null, lifeCities=null}}

一共有3个bean

user=User{id=11, name='st', city=null, workCity=null, lifeCities=null}
test=User{id=10, name='tt.victor', city=null, workCity=null, lifeCities=null}
org.victor.spring.ioc.dependency.domain.User#0=User{id=10, name='tt.victor', city=null, workCity=null, lifeCities=null}
  • 其中user是靠注解生成的,其他两个是BeanDefinition注册生成的,现在要完成猜想的所有逻辑都已经有了,剩下的就是组装和验证了.
  • 可能有同学要问,接口中定义的方法怎样在BeanDefinition生成的bean中体现呢?这个我认为可以参考@FeignClient中每个方法其实就是一个远程调用,我们可以根据自己的业务,再定义一个注解将每个方法上参数和注解内的参数通过代理来实现.

这里目前我也是看了@FeignClient的源码之后有的猜想,实际项目中还没使用过,如果有同学在项目中使用过,欢迎在评论区里评论,大家互相学习哈.