spring[1]-使用ImportBeanDefinitionRegistrar自定义注册bean(基于源码)

简介 :

  • ImportBeanDefinitionRegistrar类只能通过其他类@Import的方式来加载,通常是启动类或配置类。
  • 使用@Import,如果括号中的类是ImportBeanDefinitionRegistrar的实现类,则会调用接口方法,将其中要注册的类注册成bean。
  • 实现该接口的类拥有注册bean的能力。

扩展 : 将类交给spring管理方式 :

  1. @Componet
  2. @Service等

扩展 : 将对象交给spring管理方式:

  1. @Bean
@Bean
public UserService userService() {
	return new UserService();
}
  1. BeanFactory
// 方式1
// 实例化一个ApplicationContext的对象;
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
// 现在注册已经晚了,因为已经执行了refresh方法,spring已经初始化完成
ac.getBeanFactory().registerSingleton("userService",new UserService());

// 方式2
// 这种方式注册可以,但是需要拿到Context,并修改其执行步骤,所以此方式一般不会用到
ac = new AnnotationConfigApplicationContext();
ac.register(AppConfig.class);
// 现在注册是可以的,因为还没有执行refresh方法,也就是spring并未进行bean的初始化
ac.getBeanFactory().registerSingleton("userService",new UserService());
ac.refresh();
  1. FactoryBean

Mybatis就是通过这个方式+动态代理来实现接口被转化为对象,让这个对象让spring管理的。
一般做法就是实现FactoryBean这个接口,然后在getObject这个方法返回我们自己实现的对象。

public class MyFactoryBean implements FactoryBean {
	@Override
	public Object getObject() throws Exception {
		return new UserService();
	}
	@Override
	public Class<?> getObjectType() {
		return UserService.class;
	}
}
  1. FactoryMethod : 不做说明

说明 :

  • 个人感觉类似仿@Component的实现,只不过可以自定义一些功能

用途 :

  • 无法修改三方类的前提下,将三方的类也让spring来管理
  • 通过可配置的方式加载一些类,如mybatis的@MapperScan
  • 实现对象的创建过程,然后将对象交给spring管理,如注册前先进行代理,mybatis即如此

代码如下 :

  1. MyImportBeanDefinitionRegistrar.java : 实现 ImportBeanDefinitionRegistrar 来注册Bean
  2. MyClassPathBeanDefinitionScanner.java : 定义 ClassPathBeanDefinitionScanner ,实现 registerFilters
  3. MyMapperAutoConfig.java : 自定义配置类,启动类增加注解
  4. MyComponent.java : 此注解,仅作为自定义注册bean的过滤条件
  5. MyMapperBean.java : 测试类
  6. AppConfig.java : 配置类
  7. TestClient : 测试类

在这里插入图片描述
源码下载,代码很少,浪费积分,建议跟着写一下。

spring源码环境搭建

MyImportBeanDefinitionRegistrar.java

package com.beandefinition;

import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;

import java.util.Map;

/**
 * 实现 ImportBeanDefinitionRegistrar 来注册Bean
 */
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
	private ResourceLoader resourceLoader;

	@Override
	public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
		/**
		 * 获取元注解信息的属性、包名 : 也就是加了@Import(MyImportBeanDefinitionRegistrar.class)的类的信息
		 */
		Map<String, Object> annotationAttributes = annotationMetadata.getAnnotationAttributes(MyMapperAutoConfig.class.getName());
		String[] basePackages = (String[]) annotationAttributes.get("basePackages");
		/**
		 * 注册包下的bean,并使用自定义过滤器
		 */
		MyClassPathBeanDefinitionScanner scanner = new MyClassPathBeanDefinitionScanner(registry, false);
		scanner.setResourceLoader(resourceLoader);
		/**
		 * 此处过滤的为 : 仅注册增加了 @MyComponent 注解的类,如想实现扫描包下的所有类,则无需注册过滤器
		 */
		scanner.registerFilters();
		scanner.doScan(basePackages);
	}

	@Override
	public void setResourceLoader(ResourceLoader resourceLoader) {
		this.resourceLoader = resourceLoader;
	}

}

MyClassPathBeanDefinitionScanner.java

package com.beandefinition;

import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.filter.AnnotationTypeFilter;

import java.util.Set;

/**
 * 定义 ClassPathBeanDefinitionScanner ,实现 registerFilters
 */
public class MyClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner {

	public MyClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
		super(registry, useDefaultFilters);
	}

	/**
	 * 实现 registerFilters ,仅注册 注解了 @MyComponent 的类
	 */
	protected void registerFilters() {
		addIncludeFilter(new AnnotationTypeFilter(MyComponent.class));
	}

	@Override
	protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		return super.doScan(basePackages);
	}

}

MyMapperAutoConfig.java

package com.beandefinition;

import org.springframework.context.annotation.Import;

import java.lang.annotation.*;

/**
 * 自定义配置类,启动类增加注解
 * MyMapperAutoConfig(basePackages = "com.beandefinition") 即可扫描包下的类
 */
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Import(MyImportBeanDefinitionRegistrar.class)
public @interface MyMapperAutoConfig {

	/**
	 * 需要扫描的包
	 */
	String[] basePackages() default {};

}

MyComponent.java

package com.beandefinition;

import java.lang.annotation.*;

/**
 * 此注解,仅作为自定义注册bean的过滤条件
 * 如无需过滤,则可省去
 */
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
public @interface MyComponent {

}

MyMapperBean.java

package com.beandefinition;

/**
 * 测试类
 * 这里不使用@Component,则spring不会管理此bean
 * 使用自定义的@MyComponent
 */
@MyComponent
public class MyMapperBean {

	/**
	 * 测试方法
	 */
	public void print() {
		System.err.println("mymapperbean");
	}

}

AppConfig.java

package com;

import com.beandefinition.MyMapperAutoConfig;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan("com")
/**
 * 配置类,增加 @MyMapperAutoConfig(basePackages = "com.beandefinition")
 * 说明 : 启用 自定义ImportBeanDefinitionRegistrar,并传入需要扫描的包
 */
@MyMapperAutoConfig(basePackages = "com.beandefinition")
public class AppConfig {

}

TestClient.java

package com;

import com.beandefinition.MyMapperBean;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestClient {

	public static void main(String[] args) {
		// 1:实例化一个ApplicationContext的对象;
		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

		ac.getBean(MyMapperBean.class).print();

	}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
注册 elasticsearchRestTemplate Bean 的方法可以通过使用 spring-boot-starter-data-elasticsearch 提供的 ElasticsearchRestTemplateAutoConfiguration 类来完成。以下是一个示例: ```java import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientProperties; import org.springframework.boot.autoconfigure.elasticsearch.RestClientBuilderCustomizer; import org.springframework.boot.autoconfigure.elasticsearch.RestClientProperties; import org.springframework.boot.autoconfigure.elasticsearch.RestClientPropertiesBuilderCustomizer; import org.springframework.boot.autoconfigure.elasticsearch.RestHighLevelClientBuilderFactory; import org.springframework.boot.autoconfigure.elasticsearch.RestHighLevelClientFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; @Configuration public class ElasticsearchConfig { @Bean public ElasticsearchRestTemplate elasticsearchRestTemplate( RestHighLevelClientFactory clientFactory, RestHighLevelClientBuilderFactory clientBuilderFactory) { return new ElasticsearchRestTemplate(clientFactory, clientBuilderFactory); } @Bean public RestClientBuilderCustomizer restClientBuilderCustomizer(RestClientProperties properties) { return (builder) -> { // 自定义 RestClientBuilder 的配置 // 可以根据需要进行配置,例如设置连接超时时间、认证等 builder.setRequestConfigCallback((requestConfigBuilder) -> { requestConfigBuilder.setConnectTimeout(properties.getConnectionTimeout()); // 其他自定义配置... return requestConfigBuilder; }); }; } @Bean public RestClientPropertiesBuilderCustomizer restClientPropertiesBuilderCustomizer( ElasticsearchRestClientProperties properties) { return (builder) -> { // 自定义 RestClientProperties 的配置 // 可以根据需要进行配置,例如设置连接池大小、连接保持活动时间等 builder.setMaxRetryTimeout(properties.getMaxRetryTimeout()); // 其他自定义配置... }; } } ``` 在上述示例中,我们通过定义一个 `ElasticsearchRestTemplate` 的 bean 来注册 `elasticsearchRestTemplate`。同时,我们也可以通过自定义 `RestClientBuilderCustomizer` 和 `RestClientPropertiesBuilderCustomizer` 来对 RestClient 进行一些自定义配置。 你可以根据实际需求在 `restClientBuilderCustomizer` 和 `restClientPropertiesBuilderCustomizer` 方法中添加适当的配置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小安灬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值