一 容器
容器是spring中最核心的部分,他管理着spring中bean的创建、配置和管理。
容器创建完bean后,通过DI依赖注入来实现不同bean之间的关系。
1容器的两种实现方式:
BeanFactory 最基础的
ApplicationContext 基于BeanFactory实现,可以实现更多功能
两者区别:
ApplicationContext 初始化时会实例化所有bean, 只实例化一次,后面调用可以直接引用同一份;
BeanFactory 初始化时不会实例化bean, 只是在第一次使用bean时才会实例化;
ApplicationContext 启动时会慢些,但是使用的时候比BeanFactory快,不需要在实例化。
2 ApplicationContext的几种实现
AnnotationConfigApplicationContext:从一个或多个基于Java的配置类中加载 Spring应用上下文。
AnnotationConfigWebApplicationContext:从一个或多个基于Java的配置类中 加载Spring Web应用上下文。
ClassPathXmlApplicationContext:从类路径下的一个或多个XML配置文件中加 载上下文定义,把应用上下文的定义文件作为类资源。
FileSystemXmlapplicationcontext:从文件系统下的一个或多个XML配置文件 中加载上下文定义。
XmlWebApplicationContext:从Web应用下的一个或多个XML配置文件中加载上下 文定义。
常用:
ApplicationContext context = new ClassPathXmlApplicationContext("config.xml"); //从类路径下找配置文件来加载上下文
ApplicationContext context = new AnnotationConfigApplicationContext(com.*.*.Config.class);//从配置类中加载上下文
二 装配Bean
有3种装配bean的方式:
1)隐式的bean发现机制和自动装配 (优先推荐使用)
2)在Java中进行显式配置 (第三方类库加载推荐)
3)在XML中进行显式配置 (配置较繁琐,不推荐)
1 自动装配(优先推荐使用)
分成2个步骤
组件扫描:使用@ComponentScan去扫描basePackage下带有@Component注解的bean, 对其初始化
自动装配:含有@Component的类如果想引入其他组件, 可以使用@Autowired 注解进行自动装配进来
组件扫描如下:
自动装配如下:
组件扫描后会为bean分配一个默认的ID,默认使用类名,但是首字母为小写,如果想修改ID可以指定@Component注解中ID参数。
2 通过java代码装配bean
当想把第三方类库中的bean注入到应用中,使用组件扫描、自动装配解决不了, 只能使用javaConfig和xml配置方式来装配,javaConfig和xml装配的选择,优先使用javaConfig, 因为配置使用的也是java代码,更加灵活。
申明bean的方式实例化:
使用注解@Bean 加到实例化的方法上,如下:
1)默认bean的id是方法名,如果想自定义id可以修改@Bean中name属性值
2)需要和@Configuration 注解一起使用,使用@Configuration 方便该类被扫描到,如下图,该注解实际
上也是@Component 组件,所以可以被@ComponentScan 扫到进行初始化
借助javaConfig来实现注入:
在CDPlaer中注入SgtPeppers 引入对方实例化的方法,并不会每次都执行sgtPeppers方法,spring会拦截返回实例化的bean给调用处。
另一种javaConfig注入方式:
把需要注入的bean写到方法参数中,这样在实例化当前bean的时候, 就会取CompactDisc的实例化bean来作为参数了,此方式推荐使用
三 高级装配
1 条件化bean
有些bean需要在特定的条件下才可以创建,例如在profile=dev的时候才允许bean创建,其他profile不允许, 引入@Conditional 注解来实现。
使用时直接在@Bean的位置引入@Conditional 注解属性中需要实现 Condition接口, 接口的matches返回为true,则代表条件满足,则可以创建该bean,否则不允许创建该bean.
MagicExistsCondition实现了Condition接口,检查是否有magic属性,存在就允许创建bean
2 自动装配的歧义性
当一个接口有多个实现类时,使用@Autowired 引入bean时就无法选择使用具体哪个实现类的bean,执行过程会抛出异常。
有两种解决方式:
1)使用@Primary 设置一个默认首选的bean (不推荐)
@Primary能够与@Component组合用在组件扫描的bean上,也可以与@Bean组合用在Java配置的bean声明中,如下
但是当同一个接口的实现类出现了2个(含)以上的@Primary 注解时,@Autowired 自动装配的时候又出现歧义了,无法选择其中的一个,所以此方式很容易出现这种问题, 不推荐使用。
2) 使用@Qualifier限定符来设置需要引入的bean (推荐)
可以@Qualifier和 @Autowired 一起使用,@Qualifier 属性中填需要引入bean的ID, 下面例子就是引入了Dessert的实现类IceCream.
可以不依赖bean Id的限定符,使用自定义名称的限定符,如下在声明@Component 时给bean设置一个cold的限定符
具体使用自定义限定符如下:
说明:
自定义的限定符需要在bean类和需要注入bean的上都加上自定义限定符才能生效