导入组件的方式:
@Component+@ComponentScan搭配使用@Bean@Import- ImportSelector
- ImportBeanDefinitionRegistry
FactoryBean 接口
对于该类型的 Bean 对象,Spring 框架的
getBean()方法有特殊处理。默认情况下获取该 FactoryBean 的getObject()方法注入的 Bean 对象,使用&前缀才能获取该 FactoryBean 对象本身。
@Import导入组件
@Import注解和@Bean注解导入组件的功能没有本质区别
- @Bean注解可以自定义一些属性, bean对象的默认id为方法名
- @Import注解导入一个无参构造器生成的对象, bean对象的默认id为全类名
配置类
package com.xiong.config;
import com.xiong.bean.User;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
//通过@Import注解导入User类对象
@Import({User.class})
@Configuration
public class UserConfig {
}
测试类
package com.xiong;
import com.xiong.bean.Person;
import com.xiong.bean.User;
import com.xiong.config.PersonConfig;
import com.xiong.config.UserConfig;
import com.xiong.service.PersonService;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainTest {
@Test
public void importTest() {
ApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.class);
String[] userNames = context.getBeanNamesForType(User.class);
for (String userName : userNames) {
User user = context.getBean(userName, User.class);
System.out.println(userName + ": " + user);
}
}
}
实体类: 模拟第三方包
不添加空参构造器使其报错
package com.xiong.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
//不存在空参构造器
@Data
@AllArgsConstructor
public class User {
private String name;
private Integer age;
}

添加空参构造器
package com.xiong.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String name;
private Integer age;
}

ImportSelector自定义导入器
可以根据规则批量导入, 避免@Import单个导入.
导入的组件的id默认为全类名, 不可以自定义修改
自定义导入器类
package com.xiong.selector;
import com.xiong.bean.Person;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import java.util.ArrayList;
import java.util.List;
public class XImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
List<String> importingClass = new ArrayList<>();
// 自定义导入器中添加Person类
importingClass.add(Person.class.getName());
// List<String> => String[] 的写法
return importingClass.toArray(new String[0]);
}
}
配置类
package com.xiong.config;
import com.xiong.bean.User;
import com.xiong.selector.XImportSelector;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
//使用自定义导入器
@Import({User.class, XImportSelector.class})
@Configuration
public class UserConfig {
}
测试类
package com.xiong;
import com.xiong.bean.Person;
import com.xiong.bean.User;
import com.xiong.config.PersonConfig;
import com.xiong.config.UserConfig;
import com.xiong.service.PersonService;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainTest {
@Test
public void importSelectorTest() {
ApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.class);
//这里通过importSelector导入person对象
String[] personNames = context.getBeanNamesForType(Person.class);
for (String personName : personNames) {
Person person = context.getBean(personName, Person.class);
System.out.println(personName + ": " + person);
}
}
}
ImportBeanDefinitionRegistrar自定义导入
ImportSelector不能够定义导入的bean对象的id, 而使用ImportBeanDefinitionRegistrar可以自定义
自定义组件注册类
package com.xiong.registrar;
import com.xiong.bean.Customer;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
public class XImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClass(Customer.class);
//设置该bean对象的id为customer
registry.registerBeanDefinition("customer", beanDefinition);
}
}
配置类
package com.xiong.config;
import com.xiong.bean.User;
import com.xiong.registrar.XImportBeanDefinitionRegistrar;
import com.xiong.selector.XImportSelector;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Import({User.class, XImportSelector.class, XImportBeanDefinitionRegistrar.class})
@Configuration
public class UserConfig {
}
测试类
package com.xiong;
import com.xiong.bean.Person;
import com.xiong.bean.User;
import com.xiong.config.PersonConfig;
import com.xiong.config.UserConfig;
import com.xiong.service.PersonService;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainTest {
@Test
public void importBeanDefinitionRegistrarTest() {
ApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.class);
Customer customer = context.getBean("customer", Customer.class);
System.out.println(customer);
}
}
实验结果

通过 FactoryBean导入组件
容器中注入的 Bean 的类型如果是 FactoryBean,那么在获取 FactoryBean 对象时,默认会调用 FactoryBean 对象的 getObject() 方法。
FactoryBean接口实现类
package com.xiong.bean;
import org.springframework.beans.factory.FactoryBean;
public class XFctoryBean implements FactoryBean<Consumer> {
@Override
public Consumer getObject() throws Exception {
return new Consumer("consumer", 18);
}
@Override
public Class<?> getObjectType() {
return Consumer.class;
}
/**
* 返回该对象是否是单实例
*
* @return true表示是单实例, 容器中只保存一份;
* false表示是多实例, 每次调用都会创建一个bean对象
*/
@Override
public boolean isSingleton() {
return true;
}
}
配置类
package com.xiong.config;
import com.xiong.bean.XFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FactoryBeanConfig {
//将FactoryBean实现类作为bean对象注入, 默认会通过委托模式获取该FactoryBean内部的getObject()
@Bean
XFactoryBean xFactoryBean() {
return new XFactoryBean();
}
}
测试类
package com.xiong;
import com.xiong.bean.Person;
import com.xiong.bean.User;
import com.xiong.config.PersonConfig;
import com.xiong.config.UserConfig;
import com.xiong.service.PersonService;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainTest {
@Test
public void factoryBeanTest() {
ApplicationContext context = new AnnotationConfigApplicationContext(FactoryBeanConfig.class);
//FactoryBean默认会获取getObject()返回的对象
Object bean = context.getBean("xFactoryBean");
System.out.println(bean.getClass().getName());
//如果想要获得FactoryBean对象本身, 使用&前缀
Object xFactoryBean = context.getBean("&xFactoryBean");
System.out.println(xFactoryBean.getClass().getName());
Consumer consumer = context.getBean("xFactoryBean", Consumer.class);
System.out.println(consumer);
//由于在XFactoryBean中设置isSingleton为true, 所以返回单实例bean对象, 因此bean和consumer是同一个对象
System.out.println(bean == consumer);
}
}
实验结果

拓展学习
AnnotationMetadata类
获取当前类的注解信息
todo
BeanDefinitionRegistry类
通过registerBeanDefinition()可以手动的向容器中注册bean对象, 这种方式可以自定义bean对象的名字
todo