跟着柴毛毛学Spring(3)——简化Bean的配置

通过前面的学习,我们会感觉到对于一个有较多Bean的大项目,Spring的配置会比较复杂。那么接下来我们就介绍如何简化Spring的配置。

简化Spring的配置主要分为两类: 1. 自动装配 2. 自动扫描

下面就详细介绍这两种简化配置的方式。

自动装配

自动装配的种类

  1. byName:根据属性的名字自动装配
  2. byType:根据属性的类型自动装配
  3. constructor:根据构造器的参数类型自动装配
  4. autodetect:最佳自动装配。首先采用constructor自动装配,若没有发现与构造器相匹配的Bean时,采用byType进行自动装配。

使用XML实现自动装配

  1. byName:根据属性的名字装配 在bean标签中添加属性autowire=”byName”。当Spring启动时,会寻找与person中成员变量名字相同的bean,并将该bean注给person的成员变量。
    <bean id="person" class="com.njupt.Person" autowire="byName">
    </bean>
  1. byType:根据属性的类型装配 在bean标签中添加属性autowire=”byName”。当Spring启动时,会寻找与person中成员变量类型相同的bean,并将该bean注给person的成员变量。
    <bean id="person" class="com.njupt.Person" autowire="byType">
    </bean>

byType的缺点:如果某一类型的bean有多个,那Spring在通过byType为属性寻找同类型的bean时就会抛出异常。 解决方案: - 为相同类型的bean设置是否首选 在需要被首选的bean中作如下设置:

<bean id="person" class="com.njupt.Person" primary="true">
    </bean>

在不需要被首选的bean中作如下设置:

<bean id="person" class="com.njupt.Person" primary="false">
    </bean>
  • 取消某一些相同类型bean的候选资格 使用auto-candidate属性取消某些bean的候选资格,Spring在为属性寻找同类型的bean时直接排除这些bean。
<bean id="person" class="com.njupt.Person" default-candidate="false">
    </bean>
  1. constructor:根据构造器的参数的类型装配 autowire设置为constructor后,Spring会寻找与构造函数的参数类型相同的bean,并注入给这个构造函数。
<bean id="person" class="com.njupt.Person" autowire="constructor">
    </bean>

构造器的自动装配本质上仍是通过byType进行装配,只不过autowire=”constructor”时,Spring会对构造器的参数进行自动装配,而autowire=”byType”时,Spring会对bean的成员变量进行自动装配。

构造器的自动装配和byType自动装配具有相同的缺点:当某一类型的bean有多个时,Spring无法确定究竟选择哪个bean,就直接抛出异常。 此外,构造器的自动装配还有个独特的缺点:当构造器有多个时,Spring也无法选择究竟初始化哪个构造器,因此也直接跑出异常。

  1. autodetect:最佳自动装配。Spring要初始化一个设置了autowire=”autodetect”的bean时,首先采用构造器装配,若没有发现与构造器相匹配的Bean或构造器有多个时,就采用byType对属性进行装配。

使用默认自动装配 上述自动装配的方法都是针对单个bean,如果要让beans下的所有bean均使用某种自动装配策略,那么在beans标签中增加如下配置:

default-autowire="byType"
  • 注意1:在beans中设置了default-autowire后,这个参数仅对当前beans标签之间的bean有效。
  • 注意2:采用默认自动装配后,仍然可以在bean中设置特有的自动装配策略,bean中的自动装配策略会覆盖默认策略。
  • 注意3:使用了自动装配后,我们仍然可以在bean中通过constructor-arg属性和property属性对bean进行显示装配。 这种混合使用显示装配和自动装配的方式能够成功地解决byType出现的不确定性问题
  • 注意4:如果使用了constructor来实现构造器参数的自动装配,那么就不能混合使用autowire=”constructor”属性和constructor-arg标签。

使用注解实现自动装配

使用注解装配其实就是把原本XML中bean中的autowire=”xxx”属性搬到了Bean类的Java代码中了。功能上没啥差别。 下面就来介绍如何使用注解实现自动装配。

1. 开启注解自动装配

在beans中作如下配置:

<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans    
    http://www.springframework.org/schema/beans/spring-beans-4.5.xsd">

    <context:annotation-config>

</beans>

2. 使用@Autowired标注需要自动装配的函数或属性

当Bean中的属性、函数被标记@Autowired后,Spring在创建这个bean的对象时,会通过byType寻找与属性、函数参数相同类型的bean进行自动装配。 - 用@Autowired标注构造函数

    @Autowired
    public Person(String name,long id){
        this.name = name;
        this.id = id;
    }
  • 用@Autowired标注普通函数
    @Autowired
    public void createInstance(){
        System.out.println("对象被创建啦!");
    }
  • 用@Autowired标注属性
    @Autowired
    private Father father;

@Autowired本质上采用byType进行自动装配,因此也存在与byType一样的问题:若同一类型的bean有多个时,或找不到该类型的bean,Spring就会抛出异常。

@Autowired弊端的应对策略

  1. 若同一类型的bean有多个 若采用xml设置bean的自动装配,则可以使用显示装配的方式,手动设置需要注入的参数,而使用注解自动装配时,可以使用@Qualifier缩小候选bean的范围,具体操作如下:
    @Autowired
    @Qualifier("father")
    private Father father;

@Qualifier(“ID”)会根据bean的id为father装配。

  1. 若找不到某一类型的bean 如果bean中的某些属性、参数不需要初始化值也能接受的话,那就为该属性或参数的@Autowired添加required属性:
    @Autowired(required="false")
    public Person(String name,long id){
        this.name = name;
        this.id = id;
    }

此时,如果Spring找不到与构造函数的参数相同类型的bean的话,就赋上null。 注意:若一个bean有多个构造函数时,只有一个构造函数可以设为@Autowired(required=true),其余的构造函数都只能设为@Autowired(required=false)

在注解中使用SpEL表达式

通过前面学习我们知道,在Spring的XML配置中,可以使用SpEL表达式来实现手动装配。同样,在注解中也可以使用SpEL表达式实现手动装配。 - 将名为father的bean注入给构造函数:

    @Value("#{father}")
    public Person(Father father){
        this.father = father;
    }
  • 将father对象中的id注入给id:
    @Value("#{father.id}")
    public void setId(long id){
        this.id = id;
    }

自动检测

自动装配能够减少bean标签下property标签和constructor-arg标签的数量,而自动检测能降低bean标签的数量。

1. 开启Spring的自动检测

腰开启自动检测功能,需要在XML的beans标签中作如下配置: - base-package: 表示要扫描的包

<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans    
    http://www.springframework.org/schema/beans/spring-beans-4.5.xsd">

    <context:component-scan base-package="com.xxx"></context:component-scan>

</beans>

2. 为需要自动减的bean添加@Component注解

要让一个Java类变成一个Bean,需要在类上加上@Component注解。Spring在启动的时候会到base-package指定的包下寻找被@Component标记的类,把他们初始化为bean,保存在SpringContext中。 - 将类型的小写作为bean的名字:

@Component
class Person{
}
  • 指定bean的名字:
@Component("person")
class Person{
}

3. 过滤被扫描的bean

使用Java代替XML配置

虽然使用注解已经大大减少Spring中的XML配置,但仍然需要少量的XML配置,我们可以将XML配置用Java代码实现,从而完全避免了XML配置。

1. 定义一个Spring配置类

用@Configuration标签标注一个类,表示这个类是Spring的配置类:

@Comfiguration
class Person{
    ……
}

2. 声明一个bean

在Spring的配置类中,使用@Bean标签标注一个bean。 - 函数名:bean的id - 返回值:bean的类型 - 函数体:初始化这个bean

@Comfiguration
class Person{
    @Bean
    public Person person(){
        //构造器注入
        Person person = new Person("柴毛毛");
        //属性注入
        person.setAge(22);
        return person;
    }
}

3. 使用Java进行注入

在采用Java进行Spring的配置中,对bean属性和构造器的注入非常简单,只需在函数中操作即可:

@Comfiguration
class Person{
    @Bean
    public Person person(){
        return new Person();
    }
}

采用Java代替XML配置的好处

在XML配置中,bean的类型是用String表示的,因此只有在运行结点才能发现bean的类型是否写错;而在Java配置中,在编译阶段就能发现bean的类型是否出错,从而能够尽早地发现错误。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏fixzd

redis系列:通过队列案例学习list命令

这一篇文章将讲述Redis中的list类型命令,同样也是通过demo来讲述,其他部分这里就不在赘述了。

762
来自专栏SDNLAB

ODL源码分析之flowmod下发流程

上一篇简单分析了openflowjava到openflowplugin(介绍的hello消息),本篇介绍如何从openflowplugin到openflowja...

2777
来自专栏Python

解决有关flask-socketio中服务端和客户端回调函数callback参数的问题(全网最全)

2064
来自专栏Linyb极客之路

web前端性能优化

网站的划分一般为二:前端和后台。我们可以理解成后台是用来实现网站的功能的,比如:实现用户注册,用户能够为文章发表评论等等。而前端呢?其实应该是属于功能的表现。并...

602
来自专栏大数据智能实战

Redis中有序集(Sorted Set)判断某个键的成员存在的设计

一般而言,Redis的ZSet提供了丰富的功能,可以形成诸多应用。 在Redis中,提供了如下诸多功能。 有序集(Sorted Set) ZADD ZREM Z...

2947
来自专栏Java技术分享

Redis特性和应用场景

Redis特性 速度快 Redis使用标准C编写实现,而且将所有数据加载到内存中,所以速度非常快。官方提供的数据表明,在一个普通的Linux机器上,Redis读...

2597
来自专栏Java技术分享

Redis特性和应用场景

Redis使用标准C编写实现,而且将所有数据加载到内存中,所以速度非常快。官方提供的数据表明,在一个普通的Linux机器上,Redis读写速度分别达到81000...

1977
来自专栏小工匠技术圈

【Java小工匠】JavaNIO-缓存区基础

  缓冲区(Buffer)就是在内存中预留指定大小的存储空间用来对输入/输出(I/O)的数据作临时存储,这部分预留的内存空间就叫做缓冲区。

392
来自专栏崔庆才的专栏

爬虫速度太慢?来试试用异步协程提速吧!

在执行一些 IO 密集型任务的时候,程序常常会因为等待 IO 而阻塞。比如在网络爬虫中,如果我们使用 requests 库来进行请求的话,如果网站响应速度过慢,...

1100
来自专栏大数据智能实战

REDIS并行多线程写入时出现“如果基础流不可搜寻,则当读取缓冲区不为空时,将无法写入到 BufferedStream。”解决办法

在并行写入REDIS的时候,有时候会碰到这样的问题,即:  System.NotSupportedException: 如果基础流不可搜寻,则当读取缓冲区不为空...

26710

扫描关注云+社区