@Configuration 来声明1个配置类,
@Bean 注解声明1个bean,将其加入到Spring容器中。
@Configuration
public class MyConfiguration {
@Bean
public Person person() {
Person person = new Person();
return person;
}
}
@Componet放在类名上面;
@ComponentScan放在配置类上,可以指定一个路径,进行扫描带有@Componet注解的bean,然后加至容器中。
@Component
public class Person {
}
@ComponentScan(basePackages = "com.haoqian.beans.*")
public class Demo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Demo1.class);
Person bean = applicationContext.getBean(Person.class);
}
}
@Import 注解在进行Spring扩展时经常会用到,它经常搭配自定义注解进行使用,然后往容器中导入一个配置文件。
关于@Import注解,它有四种使用方式。@Import注解的源码如下,可以发现它只能放置在类上。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
/**
* 用于导入一个class文件
* {@link Configuration @Configuration}, {@link ImportSelector},
* {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
*/
Class<?>[] value();
}
public class Person {
}
/**
* 直接使用@Import导入person类
**/
@Import(Person.class)
public class Demo1 {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Demo1.class);
Person bean = applicationContext.getBean(Person.class);
}
}
自定义了一个ImportSelector 接口的实现类,重写selectImports方法,然后将要导入bean的全限定类名写在返回值里面即可。
class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.haoqian.beans.Person"};
}
}
@Import(MyImportSelector.class)
public class Demo1 {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Demo1.class);
Person bean = applicationContext.getBean(Person.class);
}
}
DeferredImportSelector 它是 ImportSelector 的子接口,所以实现的方法和3.2无异。只是Spring的处理方式不同,它和Spring Boot中的自动导入配置文件 延迟导入有关,非常重要。
class MyDeferredImportSelector implements DeferredImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// 也是直接将Person的全限定名放进去
return new String[]{Person.class.getName()};
}
}
@Import(MyDeferredImportSelector.class)
public class Demo1 {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Demo1.class);
Person bean = applicationContext.getBean(Person.class);
}
}
自定义了一个ImportBeanDefinitionRegistrar接口的实现类,重写registerBeanDefinitions方法,然后将要导入bean的beanDefinition 注入到容器中,容器会创建对应的bean。
class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 构建一个beanDefinition.
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Person.class).getBeanDefinition();
// 将beanDefinition注册到Ioc容器中.
registry.registerBeanDefinition("person", beanDefinition);
}
}
@Import(MyImportBeanDefinitionRegistrar.class)
public class Demo1 {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Demo1.class);
Person bean = applicationContext.getBean(Person.class);
}
}
@Import 还可以搭配@Configuration注解使用,用于导入一个配置类。
FactoryBean接口和BeanFactory千万不要弄混了:
使用@Configuration + @Bean的方式将 PersonFactoryBean 加入到容器中,注意,没有向容器中注入 Person, 而是直接注入的 PersonFactoryBean 然后可以从容器中拿到Person这个类型的bean。
class PersonFactoryBean implements FactoryBean<Person> {
/**
* 直接new出来Person进行返回.
*/
@Override
public Person getObject() throws Exception {
return new Person();
}
/**
* 指定返回bean的类型.
*/
@Override
public Class<?> getObjectType() {
return Person.class;
}
}
@Configuration
public class Demo1 {
@Bean
public PersonFactoryBean personFactoryBean() {
return new PersonFactoryBean();
}
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Demo1.class);
Person bean = applicationContext.getBean(Person.class);
}
}
其实这种方式也是利用到了 BeanDefinitionRegistry,在Spring容器启动的时候会执行 BeanDefinitionRegistryPostProcessor 的 postProcessBeanDefinitionRegistry 方法,大概意思就是等beanDefinition加载完毕之后,对beanDefinition进行后置处理,可以在此进行调整IOC容器中的beanDefinition,从而干扰到后面进行初始化bean。
class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Person.class).getBeanDefinition();
registry.registerBeanDefinition("person", beanDefinition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
public class Demo1 {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
MyBeanDefinitionRegistryPostProcessor beanDefinitionRegistryPostProcessor = new MyBeanDefinitionRegistryPostProcessor();
applicationContext.addBeanFactoryPostProcessor(beanDefinitionRegistryPostProcessor);
applicationContext.refresh();
Person bean = applicationContext.getBean(Person.class);
}
}