Spring系列(一)装配Bean
Spring容器最常见的三种方法。
1. 隐式的bean发现机制和自动装配。
2. 在Java中进行显式配置。
3.在XML中进行显式配置。
总结 Spring3中推荐用xml方法进行配置 Spring4中,推荐使用类型安全并且比XML更加强大的JavaConfig。
1自动装配
1)组件扫描(componentscanning):Spring会自动发现应用上下文中所创建的bean。
2)自动装配(autowiring):Spring自动满足bean之间的依赖。
@ComponentScan和@Component和@Configuration
1)@ComponentScan和作用和在xml中配置的<context:component-scanbase-package="org.springframework.test"/>作用是相同的
不过@ComponentScan的默认扫描的是**/*.class路径所以最好设置basePackage属性指定扫描路径,减少加载时间
个人理解:自动扫描作用自动扫描路径下面所有的类(实现方式就是递归base-package下面所有的文件,把最后的文件以.class命名保存,之后可以利用反射机制创建该类)
Spring会把Bean的数据结构存放在beanDefinition中 主要包括BeanName和BeanClass 其中BeanName默认为类名小写,并保存在一个beanDefinitionMap(ConcurrentHashMap)中
2)@Component告知Spring要为这个类创建bean。
需要创建Bean的标签有
1、@controller 控制器(注入服务)
用于标注控制层,相当于struts中的action层
2、@service 服务(注入dao)
用于标注服务层,主要用来进行业务的逻辑处理
3、@repository(实现dao访问)
用于标注数据访问层,也可以说用于标注数据访问组件,即DAO组件.
4、@component (把普通pojo实例化到spring容器中,相当于配置文件中的
<bean id=""class=""/>)
注意:只有在ComponentScan扫描过的包才会创建这些bean
个人理解:在SpringIOC容器中,调用getBean()方法或(lazy-init= false)(默认为ture)才会创建Bean,根据beanDefinitionMap来创建的Bean的会保存在在一个BeanCacheMap(注册式单利容器)中,之后再把BeanCacheMap包装成BeanWrapper,我们造作的Bean都是BeanWrapper,这样的好处1、保留原来的OOP关系2、我需要对它进行扩展,增强(为了以后AOP打基础)最后进行注解的扫描,存在上面注解的进行自动注入,不存在的不进行注入。
3)@Configuration 表示这个类是一个spring 配置类,一般这里面会定义Bean,会把这个类中bean加载到spring容器中
因为Spring默认的BeanName为类名小写可以用@Configuration给bean设置不同的ID
案例
@Configuration(”mypay”) Public class Pay{} 或者用 @Named(”mypay”) Public class Pay{}
|
2在Java中进行显式配置JavaConfig
JavaConfig在java中显示配置主要依赖的标签为@Configuration
上面解释过加有@Configuration表示这个类是一个Spring的配置类
这种配置方式主要通过配置文件进行注入Bean
案例
public class LogDao {
|
public class UserDao {
|
public class LogonService {
|
|
public class ConfigTest {
|
输出:
3. 在XML中进行显式配置。
<?xml version="1.0" encoding="UTF-8"?>
|
<constructor-arg>表示构造器注入,注入方式会根据参数类型,进行注入。
4处理自动装配的歧义性
当一个接口有多个实现类的时候进行Bean的装配就会出现歧义,Spring会傻傻分不清,你到底要装配那个Bean,此时Spring会报错,会抛出NoUniqueBeanDefinitionException:
案例 有一个支付接口,有两种支付方式一种为微信支付,一种为支付宝支付
@Component
|
@Component
|
@Component
|
@Component
|
public class test {
|
<?xml version="1.0" encoding="UTF-8"?> |
报错信息
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'shopping': Unsatisfied dependency expressed through field 'pay'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'springinaction3.wiringbean.qiyi.Pay' available: expected single matching bean but found 2: weiXin,zhiFuBao
错误显示 pay有两个实现类weiXin,zhiFuBao Spring不知道注入那个Bean |
这就是产生歧义的原因
解决方式
第一种(注入具体类)
依赖出入的时候可以注入具体类,而不是接口
@Component
|
第二种(@Primary)
用(@Primary)标示首选的bean
@Component
|
第三种(@Qualifier)
设置首选bean的局限性在于@Primary无法将可选方案的范围限定到唯一一个无歧义性的选项中。它只能标示一个优先的可选方案。当首选 bean的数量超过一个时,我们并没有其他的方法进一步缩小可选范围。
@Qualifier注解是使用限定符的主要方式。它可以与@Autowired和@Inject协同使用,在注入的时候指定想要注入进去的是哪个bean。
@Component |
5.bean的作用域
Spring应用上下文中所有bean都是作为以单例(singleton)的形式创建的。也就是说,不管给定的一个bean被注入到其他bean 多少次,每次所注入的都是同一个实例。
Spring定义了多种作用域,可以基于这些作用域创建bean,包括:
单例(Singleton):在整个应用中,只创建bean的一个实例。
原型(Prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例。
会话(Session):在Web应用中,为每个会话创建一个bean实例。
请求(Rquest):在Web应用中,为每个请求创建一个bean实例。
1.通过@Scope的ConfigurableBeanFactory属性设置单例和原型作用域
2. .通过@Scope的WebApplicationContext属性设置会话和请求作用域
3.通过Xml设置作用域
或在Xml中通过scope属性设置