Spring中的ImportBeanDefinitionRegistrar接口详解

 更新时间:2023年09月20日 08:45:00   作者:信仰_273993243  
这篇文章主要介绍了Spring中的ImportBeanDefinitionRegistrar接口详解,ImportBeanDefinitionRegistrar接口是也是spring的扩展点之一,它可以支持我们自己写的代码封装成BeanDefinition对象,注册到Spring容器中,功能类似于注解@Service @Component,需要的朋友可以参考下

接口功能介绍

描述:ImportBeanDefinitionRegistrar接口是也是spring的扩展点之一,它可以支持我们自己写的代码封装成BeanDefinition对象,注册到Spring容器中,功能类似于注解@Service @Component。

很多三方框架集成Spring的时候,都会通过该接口,实现扫描指定的类,然后注册到spring容器中,比如Mybatis中的Mapper接口,springCloud中的FeignClient接口,都是通过该接口实现的自定义注册逻辑。

1、ImportBeanDefinitionRegistrar接口实现类,只能通过@Import注解的方式来注入,通常把@Import修饰在启动类或配置类。

2、使用@Import,如果括号中的类是ImportBeanDefinitionRegistrar的实现类,启动时会触发ImportBeanDefinitionRegistrar接口的方法,将其中要注册的类注册成bean。

3、实现该接口的类拥有注册bean的能力。

//接口所有抽象方法,合并看就一个注册BeanDefinition的方法
public interface ImportBeanDefinitionRegistrar {
	//把自定义的类封装成BeanDefinition对象,注册到Spring里面去
	default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
		registerBeanDefinitions(importingClassMetadata, registry);
	}
	//我们平时重写这个就可以了
	default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
	}
}

使用案例

1、案例1

自定义业务类UserServiceTest,通过ImportBeanDefinitionRegistrar将注册Spring容器中。在通过spring容器获取Bean=UserServiceTest

//业务类
public class UserServiceTest {
	/**
	 * 获取用户名称
	 * @return 用户名称
	 */
	public String getUserName(){
		return "测试";
	}
}

ImportBeanDefinitionRegistrar实现类

//注意这里不能加注解,要通过Import导入进去。
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
	//业务类转成bd,注册到spring容器中注入
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		//1、通过Bd工具类生成bd对象,只是这个Db对象比较纯洁没有绑定任何类
		BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition();
		GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanDefinitionBuilder.getBeanDefinition();
		//2、设置bd绑定的类型
		beanDefinition.setBeanClass(UserServiceTest.class);
		//3、注册到spring容器中
		registry.registerBeanDefinition("userServiceTest",beanDefinition);
	}
}
@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class AppConfigClassTest {
	//在配置类导入ImportBeanDefinitionRegistrar实现类
}
//测试
public static void main(String[] args) {
	AnnotationConfigApplicationContext AnnotationConfigApplicationContext =
			new AnnotationConfigApplicationContext(AppConfigClassTest.class);
	UserServiceTest userServiceTest = AnnotationConfigApplicationContext.getBean("userServiceTest", UserServiceTest.class);
	String userName = userServiceTest.getUserName();
	System.out.println(userName);
}

如果只是把业务类注册到Spring容器中我们通过其他注解就可以了,那么ImportBeanDefinitionRegistrar有没有更高级的玩法。

2、案例2

public interface UserServiceTestInterface {
	public void list();
}
//因为是接口,但是spring的容器里面是不允许注入接口的,只能是接口的实现类。如果我们写个去实现接口,那就没有什么意义了,没必要搞得那么复杂,这次我们通过代理类来完成对接口的实现。
public class MyInvocationHandler implements InvocationHandler {
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("代理类逻辑代码");
		return null;
	}
}
//注意这里不能加注解,要通过Import导入进去。
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
	 @Override
	 public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //通过工具类生成一个bd,只是这个Db对象比较纯洁没有绑定任何类
		BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition();
		GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanDefinitionBuilder.getBeanDefinition();
		//设置Bean的类型MyInvocationHandler,类型是实现类的类型,不是接口类型。因为在实例化的时候,调用的是设置类型所以对应的构造方法。
		beanDefinition.setBeanClass(MyInvocationHandler.class);
		//注册到Spring容器中进去
		registry.registerBeanDefinition("userServiceTest",beanDefinition);
    }
}
//通过配置类,导入ImportBeanDefinitionRegistrar的实现类
@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class AppConfigClassTest {
}

测试

public static void main(String[] args) {
	AnnotationConfigApplicationContext AnnotationConfigApplicationContext = new AnnotationConfigApplicationContext(AppConfigClassTest.class);
	//通过name获取Bean,注意此时的bean类型不是UserServiceTestInterface类型,而是MyInvocationHandler
	Object userServiceTestInterface = AnnotationConfigApplicationContext.getBean("userServiceTest");
	if(userServiceTestInterface instanceof MyInvocationHandler){
		//代码实际会走到这里,把object转成带代理类。
		MyInvocationHandler u = (MyInvocationHandler) userServiceTestInterface;
		//生成接口UserServiceTestInterface的代理对象
		UserServiceTestInterface o = (UserServiceTestInterface) Proxy.newProxyInstance(MainTest.class.getClassLoader(), new Class[]{UserServiceTestInterface.class}, u);
	}
}

3、案例3

定义一个业务接口,通过FactoryBean+InvocationHandler来生成该接口的代理类,无需手动写业务接口的实现类,很多底层框架就是这样实现的。

  • InvocationHandler:主要是通过Invoke方法来拦截业务接口的方法
  • FactoryBean:主要是用来将生成的代理类。
  • ImportBeanDefinitionRegistrar:在这里的作用就是帮忙我们把自定义的FactoryBean注册到Spring中
//业务接口
public interface UserServiceTestInterface {
	public void list();
}

自定义FactoryBean这样我们控制Bean的创建的过程,实现InvocationHandler用来拦截业务接口的方法。

//创建代理类,代理UserServiceTestInterface接口,UserServiceTestInterface接口方法在执行前后都会被invoke方法拦截
//FactoryBean可以生成某一个类型Bean实例,它最大的一个作用是:可以让我们自定义Bean的创建过程
public class MyFactoryBean implements FactoryBean, InvocationHandler {
	//为了使这个类更好地扩展。创建更多的接口,我们定义一个参数,让他们通过参数传递进来。
	private Class classs;
	//添加一个有参的构造方法。
	public MyFactoryBean(Class classs){
		this.classs = classs;
	}
	//拦截Class的所有方法
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("diaoyonlejiekou123");
		return null;
	}
	//返回bean的对象。spring会自动把它add到容器里面去。
	@Override
	public Object getObject() throws Exception {
		Class[] clazzs = new Class[]{classs};//目标类集合。
		//通过proxy来得到代理对象。本来最有一个参数需要穿代理类对象,但因为本类实现了InvocationHandler,所以只需传this
		Object proxy = Proxy.newProxyInstance(this.getClass().getClassLoader(), clazzs, this);
		return proxy;//返回的这个对象,会把加到spring的容器中。
	}
	//返回要添加到容器里bean的类型
	@Override
	public Class<?> getObjectType() {
		return this.classs;
	}
}

自定义ImportBeanDefinitionRegistrar实现类,把我们自定义的FactoryBean注册到Spring中。

//注意这里不能加注解,要通过Import导入进去。
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		//通过工具类生成一个bd,只是这个Db对象比较纯洁没有绑定任何类
		BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition();
		//为什么要转成GenericBeanDefinition这种类型。因为GenericBeanDefinition有更多修改bd属性的方法。后面我会介绍为什么要修改属性。
		GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanDefinitionBuilder.getBeanDefinition();
		//这里很重要。getConstructorArgumentValues是为了获取该bd的所有构造方法,因为我们重写了有参构造方法,所有我们需要带参数过去 
		//不然spring没法帮我们实例化,addGenericArgumentValue是添加参数,该代码会执行两步
		//第一步是匹配对应的构造方法,第二步是实例化。
		beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(UserServiceTestInterface.class.getName());
		//因为代理对象类型的,实例化的时候走的是代理类的构造方法
		beanDefinition.setBeanClass(MyFactoryBean.class);
		//注册bd
		registry.registerBeanDefinition("userServiceTest",beanDefinition);
	}
}

测试

public static void main(String[] args) {
	AnnotationConfigApplicationContext AnnotationConfigApplicationContext = new AnnotationConfigApplicationContext(AppConfigClassTest.class);
	//通过name获取Bean
	Object userServiceTestInterface = AnnotationConfigApplicationContext.getBean("userServiceTest");
	//针对这种场景Bean的类型是,通过FactoryBean的getObjectType方法返回的。
	UserServiceTestInterface u = (UserServiceTestInterface) userServiceTestInterface;
	u.list();
}

​到此这篇关于Spring中的ImportBeanDefinitionRegistrar接口详解的文章就介绍到这了,更多相关ImportBeanDefinitionRegistrar接口内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 浅谈HashMap中7种遍历方式的性能分析

    浅谈HashMap中7种遍历方式的性能分析

    本文先从HashMap的遍历方法讲起,然后再从性能、原理以及安全性等方面,来分析HashMap各种遍历方式的优势与不足
    2021-06-06
  • Linux服务器如何部署java项目

    Linux服务器如何部署java项目

    这篇文章主要介绍了Linux服务器如何部署java项目问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • JAVA遍历一个文件夹中的所有文件的小例子

    JAVA遍历一个文件夹中的所有文件的小例子

    在实际项目中给定一文件夹,得到这个文件夹下所有的文件这样的需求并不是很多,更多的是查找或是删除某一具体的文件
    2013-10-10
  • springboot使用mybatis开启事务回滚

    springboot使用mybatis开启事务回滚

    本文主要介绍了springboot使用mybatis开启事务回滚,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-02-02
  • SpringBoot MongoCustomConversions自定义转换方式

    SpringBoot MongoCustomConversions自定义转换方式

    这篇文章主要介绍了SpringBoot MongoCustomConversions自定义转换方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • java编程题之顺时针打印矩阵

    java编程题之顺时针打印矩阵

    这篇文章主要为大家详细介绍了java编程题之顺时针打印矩阵,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-03-03
  • pagehelper踩坑记之分页乱套问题解决

    pagehelper踩坑记之分页乱套问题解决

    这篇文章主要为大家介绍了pagehelper踩坑记之分页乱套问题解决,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • Java结构型模式之代理模式详解

    Java结构型模式之代理模式详解

    这篇文章主要介绍了Java结构型模式之代理模式,代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等
    2023-02-02
  • 一文详解springboot中的热启动配置方案

    一文详解springboot中的热启动配置方案

    SpringBoot的热启动主要通过 **`spring-boot-devtools`** 模块实现,能在代码修改后自动重启应用,大幅提升开发效率,下面小编就来和大家讲讲详细配置和使用指南
    2025-07-07
  • Java之Springcloud Gateway内置路由案例讲解

    Java之Springcloud Gateway内置路由案例讲解

    这篇文章主要介绍了Java之Springcloud Gateway内置路由案例讲解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08

最新评论