SpringBoot(一)
最开始使用spring时,配置bean使用的都是xml格式, 在xml中写
后来接触到使用注解进行配置, 只要使用@Bean注解修饰这个方法,在扫包的时候扫到,该方法的返回值就会放到ioc容器中交给spring管理.
BeanDefinition
BeanDefinition, 即Bean定义.
可以通过@ComponentScan扫描的@Repository,@Service,@Component,@Controller和@Bean形式注入.会被spring识别出来后形成一个个的BeanDefinition, 这些BeanDefinition就是用来描述这个bean的一些属性.BeanDefinition就类似于图纸, ioc会凭借图纸将对象new出来.
BeanFactoryPostProcessor
BeanFactoryPostProcessor,是用来扩展
的.在bean还没有实例化之前,可以用来修改beanDefinition的属性.
比如可以修改BeanDefinition的lazyInit属性
public class DemoApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext("com.example");
System.out.println("---------");
User user = annotationConfigApplicationContext.getBean("user", User.class);
System.out.println(user.getName());
}
}
@Component
public class User {
private String name;
public User (){
System.out.println("user init");
}
public User (String name){
this.name = name;
System.out.println("user init");
}
}
运行结果是
user init
---------
null
添加BeanFactoryPostProcessor实现类将该bean改成懒加载
@Component
public class UserBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
BeanDefinition userDefinition = configurableListableBeanFactory.getBeanDefinition("user");
userDefinition.setLazyInit(true);
}
}
运行输出:
---------
16:11:13.688 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'user'
user init
null
可以看到,分割线打在创建ioc容器之后,获取bean之前.在没有使用BeanFactoryPostProcessor扩展之前,user类的实例在创建ioc容器的时候就已经创建出来了,在使用BeanFactoryPostProcessor扩展之后,当使用到了user这个bean才会去创建.
同样, BeanFactoryPostProcessor也可以用来修改bean的实现类.
// 添加两个user的实现类,并将ZhangSan设置为自动扫描
public class LiSi extends User {
public LiSi(){
setName("lisi");
System.out.println("lisi init");
}
}
// 在BeanFactoryPostProcessor中将user的改为实现类李四
@Component
public class UserBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
BeanDefinition userDefinition = configurableListableBeanFactory.getBeanDefinition("user");
userDefinition.setBeanClassName(LiSi.class.getName());
}
}
// 在main方法中获取zhangSan对应的bean并输出类名
public class DemoApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext("com.example");
System.out.println("---------");
User user = annotationConfigApplicationContext.getBean("user", User.class);
System.out.println(user.getClass().getName());
}
}
输出结果:
user init
lisi init
---------
com.example.repository.LiSi
我们知道,在@ComponentScan扫描的bean,会默认调用该类的无参构造器.那么也可以通过BeanFactoryPostProcessor来改变调用的构造器.
@Component
public class UserBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
GenericBeanDefinition userDefinition = (GenericBeanDefinition)configurableListableBeanFactory.getBeanDefinition("user");
// 修改User类实例化时调用的构造器, 将"zhangsan"作为构造器参数传入
ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();
constructorArgumentValues.addIndexedArgumentValue(0, "zhangsan");
userDefinition.setConstructorArgumentValues(constructorArgumentValues);
}
}
// 添加User类含参构造器
@Data
@Component
public class User {
private String name;
public User (){
System.out.println("user init");
}
public User(String name){
this.name = name;
System.out.println("user init with args");
}
}
输出结果:
user init with args
---------
com.example.repository.User
zhangsan
@Import
- 直接导入一个类
public class DemoApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
}
}
@ComponentScan(basePackages = {"com.example"})
@Import(value = {User.class})
public class MainConfig {
}
输出结果 :
user init
@Import将User的BeanDefinition导入到BeanDefinitionMap中.
- 导入BeanDefinitionRegister
@ComponentScan(basePackages = {"com.example"})
//@Import(value = {User.class})
@Import(value = {MainImportBeanDefinitionRegister.class})
public class MainConfig {
}
public class MainImportBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(User.class);
registry.registerBeanDefinition("user", rootBeanDefinition);
}
}
输出结果 :
user init
- 通过ImportSelector导入
*
这种方法可以批量加载.(自动装配原理的核心)
public class MainImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// 会返回一个数组, 数组的内容是类的全类名
return new String[]{"com.example.repository.User"};
}
}
输出结果 :
user init
搜索ImportSelector,在org.springframework.boot.autoconfigure.cache包下有一个CacheAutoConfiguration类中, 静态内部类实现了这个接口CacheConfigurationImportSelector.
static class CacheConfigurationImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
CacheType[] types = CacheType.values();
String[] imports = new String[types.length];
for (int i = 0; i < types.length; i++) {
imports[i] = CacheConfigurations.getConfigurationClass(types[i]);
}
return imports;
}
}
缓存了CacheType这个枚举,会根据CacheConfigurations.getConfigurationClass(types[i]);
依次去取缓存类的全类名.