配置文件
1.在xml中声明自定义的bean
指定bean输出
输出自定义bean结果
2.在xml中声明第三方bean
# 首先在pom.xml中导入第三方bean坐标
com.alibaba
druid
1.2.9
输出所有bean结果
进行包扫描,查找需要加载的bean
对需要加载的bean进行注解,使用@Component及其衍生注解@Controller 、@Service、@Repository,@Configuration定义bean
@Configuration配置项如果不用于被扫描可以省略
这里使用的是AnnotationConfigApplicationContext加载配置
1.拓展1 初始化实现FactoryBean接口的类,实现对bean加载到容器之前的批处理操作
使用@ComponentScan进行包扫描加载配置bean
输出返回的bean不是DogFactoryBean,而是dog
重写FactoryBean<>中的isSingleleton方法,返回false,所以生成的对象非单例
2.扩展2 加载配置类并加载配置文件
用于使用注解加载bean时,如何加载之前使用xml文件配置的bean
使用@ImportResource加载xml配置文件
3.扩展3 proxyBeanMethods
使用proxyBeanMethods=true可以保障调用此方法得到的对象是从容器中获取的而不是重新创建的
当proxyBeanMethods=true时输出结果。proxyBeanMethodtrue
被导入的bean无需使用注解声明为bean
此形式可以有效的降低源代码与Spring技术的耦合度,在spring技术底层及诸多框架的整合中大量使用
输出bean的全路径类名
扩展 使用@Import注解导入其他配置类,配置类无需使用注解,也可加载出来
使用 AnnotationConfigApplicationContext,在上下文对象初始化完毕后,手工加载bean
输出结果,相同的bean,后面的会把前面的覆盖
结果
在某类上@Import导入ImportSelector配置类,可以检查该类的某些属性
package com.huangzx.bean;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.MultiValueMap;
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata Metadata) {
System.out.println("--------------------------");
//检查加载该配置的类
System.out.println(Metadata.getClassName());
//检测加载该配置的类是否有注解@Configuration
System.out.println(Metadata.hasAnnotation("org.springframework.context.annotation.Configuration"));
//检查加载该配置的类是否有@ComponentScan属性
MultiValueMap attributes = Metadata.getAllAnnotationAttributes("org.springframework.context.annotation.ComponentScan");
System.out.println(attributes);
System.out.println("--------------------------");
//完成条件检查后,加载指定的bean
boolean flag = Metadata.hasAnnotation("org.springframework.context.annotation.Configuration");
if(flag){
return new String[] {"com.huangzx.bean.Dog"};
}
return new String[] {"com.huangzx.bean.Cat"};
}
}
结果
--------------------------
com.huangzx.config.SpringConfig6
true
{basePackageClasses=[[Ljava.lang.Class;@53f65459], basePackages=[[Ljava.lang.String;@3b088d51], excludeFilters=[[Ljava.util.LinkedHashMap;@1786dec2], includeFilters=[[Ljava.util.LinkedHashMap;@74650e52], lazyInit=[false], nameGenerator=[interface org.springframework.beans.factory.support.BeanNameGenerator], resourcePattern=[**/*.class], scopeResolver=[class org.springframework.context.annotation.AnnotationScopeMetadataResolver], scopedProxy=[DEFAULT], useDefaultFilters=[true], value=[[Ljava.lang.String;@15d0c81b]}
--------------------------
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
springConfig6
com.huangzx.bean.Dog
Process finished with exit code 0
导入实现了ImportBeanDefinitionRegistrar接口的类,通过BeanDefinition的注册器注册实名bean,实现对容器中bean的裁定,例如对现有bean的覆盖,进而达成不修改源代码的情况下更换实现的效果
package com.huangzx.bean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
public class MyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//首先使用元数据做判定,然后再导入需要的bean
BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Dog.class).getBeanDefinition();
registry.registerBeanDefinition("yyf",beanDefinition);
}
}
结果
导入实现了BeanDefinitionRegistryPostProcessor接口的类,通过BeanDefinition的注册器注册实名bean, 实现对容器中bean的最终裁定
Service接口:BookService
Service实现:BookServiceImpl1、BookServiceImpl2、BookServiceImpl3、BookServiceImpl4
1.@Import导入BookServiceImpl1.class
结果
2.创建配置类定义bean BookServiceImpl2,并导入该类
package com.huangzx.bean;
import com.huangzx.service.impl.BookServiceImpl2;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
public class MyRegistrar_PostProcessor1 implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl2.class).getBeanDefinition();
registry.registerBeanDefinition("bookService",beanDefinition);
}
}
结果
3.创建配置类定义bean BookServiceImpl3,并导入该类
package com.huangzx.bean;
import com.huangzx.service.impl.BookServiceImpl3;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
public class MyRegistrar_PostProcessor2 implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl3.class).getBeanDefinition();
registry.registerBeanDefinition("bookService",beanDefinition);
}
}
结果 MyRegistrar_PostProcessor1和MyRegistrar_PostProcessor2的导入顺序,决定了执行这两个中的哪个实现类,后导入的会覆盖之前导入的
4.定义后配置类MyPostProcessor,并定义bean BookServiceImpl4
package com.huangzx.bean;
import com.huangzx.service.impl.BookServiceImpl4;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
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 configurableListableBeanFactory) throws BeansException {
}
}
@Import导入MyPostProcessor
package com.huangzx.config;
import com.huangzx.bean.MyPostProcessor;
import com.huangzx.bean.MyRegistrar_PostProcessor1;
import com.huangzx.bean.MyRegistrar_PostProcessor2;
import com.huangzx.service.impl.BookServiceImpl1;
import org.springframework.context.annotation.Import;
@Import({BookServiceImpl1.class, MyRegistrar_PostProcessor1.class, MyRegistrar_PostProcessor2.class, MyPostProcessor.class})
public class SpringConfig8 {
}
结果 执行BookServiceImpl4 与是否最后导入无关
AnnotationConfigApplicationContext调用register方法
@Import导入ImportSelector接口
@Import导入ImportBeanDefinitionRegistrar接口
@Import导入BeanDefinitionRegistryPostProcessor接口
以ImportSelector为例
1.根据任意条件确认是否加载bean
2. 使用@Conditional注解的派生注解设置各种组合条件控制bean的加载
使用@ConditionalOn***注解为bean的加载设置条件
package com.huangzx.config;
import com.huangzx.bean.Cat;
import com.huangzx.bean.Mouse;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
//@Import(MyImportSelector.class)
@Import(Mouse.class)
public class SpringConfig {
@Bean
//@ConditionalOnClass(Mouse.class) 一般不使用这种方式
//@ConditionalOnClass(name = "com.huangzx.bean.Mouse") //有Mouse时加载
//@ConditionalOnMissingClass("com.huangzx.bean.Wolf") //没有Wolf时加载
@ConditionalOnBean(name = "jerry") //有Mouse bean,且Mouse的名字是jerry时加载
@ConditionalOnMissingClass("com.huangzx.bean.Dog") //有Mouse bean,且Mouse的名字是jerry时加载,且没有Dog时加载
@ConditionalOnWebApplication //是web程序时加载
public Cat tom(){
return new Cat();
}
}
3. 指定类上根据条件选择性加载
后续可以单独配置bean,当有某种环境时,加载某些bean
这里当有mysql数据库连接时,加载Druid数据源
public class SpringConfig {
@Bean
@ConditionalOnClass(name = "com.mysql.jdbc.Driver")
public DruidDataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
return ds;
}
}