Bean的加载方式
两种基本加载方式
加载Bean可以直接在xml中配置,也可以使用@Component、@Controller、@Service、@Service和@Configuration注解标记后在xml配置扫描的包自动将带有这些注解的类加载为Bean。
@Configuration一般用来标记配置类,比@Component多一个proxyBeanMethods属性。proxyBeanMethods属性决定改配置类是否为代理对象,默认为true。使用代理对象的方法获取对象时,若容器中有者会返回容器中的对象。
除去以上两种方式加载Bean,还有其它方式。主要列出以下6种方式。
@Componentscan
新建一个配置类使用@Componentscan()注解,注解的参数为一个字符串数组,填写要扫描的包。@Componentscan()注解可以声明出扫描哪些包,这样下来就可以将xml完全代替。但是使用new ClassPathXmlApplicationContext("applicationContext.xml")来获取ioc容器只能传入xml文件,此时可以使用new AnnotationConfigApplicationContext(SpringConfig.class)来传入配置类。
若使用new AnnotationConfigApplicationContext(SpringConfig.class)来传入配置类,则原本使用xml注册的Bean将失效。可以使用@ImportResource("applicationcontext.xml")注解声明要读取的xml配置文件。如果有相同id的Bean,后加载的覆盖先加载的。
@Import
在配置类上还可以使用@Import()注解来配置Bean,参数需要填入某个类的class,可以是单个,也可以是一个数组。一个类上该注解只可以用一次,不可以多次使用。以该方式配置的Bean的名称为全路径名。以此形式加载的Bean若是配置类,即使配置类中没有@Configuration注解类中的@Bean也会生效
编码加载
上下文容器初始化完之后,还可以手工加载Bean。AnnotationConfigApplicationContext类有一个registerBean()方法,传入要注册的Bean的名称、类型以及构造器的参数。以该方法加载的Bean后加载的会覆盖之前加载的。AnnotationConfigApplicationContext类还有一个register()方法,只需要传入一个类就可以加载该类的Bean。
实现Importselector接口
创建一个类实现Importselector接口,重写其中的selectImports(AnnotationMetadata importingClassMetadata)方法,返回一个字符串,其中包含要加载的一些类的全类名。importingClassMetadata中存着元数据,可以用来加一些条件判断来判断已加载的Bean的状态,例如是否有某一个注解、注解中有什么参数等。可以通过已加载的Bean来判断是否加载一些类
public class MyImportselector implements Importselector{
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata){
return new String[]{"com.itheima.bean.Dog","com.itheima.bean.cat"};
}
}
ImportBeanDefinitionRegistrar
创建一个类实现ImportBeanDefinitionRegistrar接口,可在重写的方法中创建Bean。主要是用到BeanDefinitionRegistry registry创建Bean对象。同一个Bean注册多次,后边的会覆盖前边的。
public class MyRegistrar implements ImportBeanDefinitionRegistrar{
@override
public void registerBeanDefinitions(AnnotationMetadata importingclassMetadata, BeanDefinitionRegistry registry){
BeanDefinition beanDefinition = BeanDefinitionBuilder,rootBeanDefinition(Dog.class).getBeanDefinition();
registry.registerBeanDefinition( beanName:"yellow",beanDefinition);
}
}
BeanDefinitionRegistryPostProcessor
创建一个类实现BeanDefinitionRegistryPostProcessor接口,重写其方法并且可以在其中注册Bean。与实现ImportBeanDefinitionRegistrar接口不同的是实现该接口的类所注册的Bean会在所有的实现ImportBeanDefinitionRegistrar接口的类注册完Bean完之后再注册,可以覆盖之前注册的Bean。若有多个实现BeanDefinitionRegistryPostProcessor接口的类则按加载这些类的顺序注册Bean。可以理解为Bean注册的后处理器
public class MyPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl4.class).getBeanDefinition();
registry.registerBeanDefinition("bookService", beanDefinition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
Bean加载控制
上文后四种加载方式可以用来实现Bean加载控制,但是也有较为简便的注解可以实现Bean加载控制。
使用注解实现还需要导坐标
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.5.4</version>
</dependency>
注解有很多种,下边仅列出几种以供参考
根据类判断是否加载
@ConditionalOnClass(name ="全类名”)
@ConditionalOnMissingClass("全类名")
前者可以传入一个类来判断,但是若类不存在将会报错。后者只可以传入字符串或字符串数组。不带Missing的是有才加载,带的是没有才加载
根据Bean加载
根据是否有某个Bean加载
@conditional0nBean(name="jerry")