简介 :
- ImportBeanDefinitionRegistrar类只能通过其他类@Import的方式来加载,通常是启动类或配置类。
- 使用@Import,如果括号中的类是ImportBeanDefinitionRegistrar的实现类,则会调用接口方法,将其中要注册的类注册成bean。
- 实现该接口的类拥有注册bean的能力。
扩展 : 将类交给spring管理方式 :
- @Componet
- @Service等
扩展 : 将对象交给spring管理方式:
- @Bean
@Bean
public UserService userService() {
return new UserService();
}
- 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();
- 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;
}
}
- FactoryMethod : 不做说明
说明 :
- 个人感觉类似仿@Component的实现,只不过可以自定义一些功能
用途 :
- 无法修改三方类的前提下,将三方的类也让spring来管理
- 通过可配置的方式加载一些类,如mybatis的@MapperScan
- 实现对象的创建过程,然后将对象交给spring管理,如注册前先进行代理,mybatis即如此
代码如下 :
- MyImportBeanDefinitionRegistrar.java : 实现 ImportBeanDefinitionRegistrar 来注册Bean
- MyClassPathBeanDefinitionScanner.java : 定义 ClassPathBeanDefinitionScanner ,实现 registerFilters
- MyMapperAutoConfig.java : 自定义配置类,启动类增加注解
- MyComponent.java : 此注解,仅作为自定义注册bean的过滤条件
- MyMapperBean.java : 测试类
- AppConfig.java : 配置类
- TestClient : 测试类
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();
}
}