Bean的配置

Spring如同一个工厂,用于生产和管理Spring容器中的Bean。在实际开发中,最常采用XML格式的配置方式,我们将通过XML文件来注册并管理Bean之间的依赖关系。

在Spring中,XML配置文件的根元素是< beans >,< beans >中可以包含多个< bean >子元素,每一个< bean >子元素定义了一个Bean,并描述了该Bean如何被装配到Spring 容器中。< bean >子元素中包含多个属性和子元素,常用的属性和子元素如下表所示:
在这里插入图片描述
在Spring的配置文件中,通常一个普通的Bean只需要定义id(或name)和class两个属性即可。定义Bean的方式如下:

<?xml version="1.0" encoding="UTF-8"?>
<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.xsd">

    <!--将指定类配置给Spring 让Spring创建其对象的实例-->
    <!--使用id属性定义bean1,其对应的实现类为com.ssm.Bean1-->
    <bean id="bean1" class="com.ssm.Bean1"/>
    <!--使用name属性定义bean2,其对应的实现类为com.ssm.Bean2-->
    <bean name="bean2" class="com.ssm.Bean2"> </bean>
</beans>

需要注意的是: 如果在Bean中未指定id和name,那么Spring会将class值当作id使用。

Bean的作用域

作用域的种类

Spring中为Bean的实例定义了7种作用域,如下图所示:

在这里插入图片描述
其中,singleton和prototype是常用的两种。

singleton作用域

singleton是Spring容器默认的作用域,当Bean的作用域为singleton时,Spring容器就只会存在一个共享的Bean实例,并且所有对Bean的请求,只要id与该Bean的id属性相匹配,就会返回同一个Bean的实例。singleton作用域对于无会话状态的Bean(如Dao组件、Service组件)来说是最理想的选择。

在Spring配置文件中,Bean的作用域是通过< bean >元素的scope属性来指定的,该属性值可以设置为singleton、prototype、request、session、globalSession、application、websocket七个值。 比如,要将作用域定义成singleton,只需要将scope属性值设置为singleton,代码如下:

<bean id="scope" class="com.ssm.scope.Scope" scope="singleton">
测试singleton作用域

项目创建在上一节中,已经详细介绍过,这里就不多说了。

Scope.java

在com.ssm.scope中创建Scope类,该类不需要写任何方法

package com.ssm.scope;

public class Scope {
}

applicatonContext.xml

在com.ssm.scope包中创建Spring的配置文件applicationContext.xml,并在配置文件中创建一个id为scope的Bean,通过class属性指定其对应的实现类为Scope

<?xml version="1.0" encoding="UTF-8"?>
<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.xsd">

<!--将指定类配置给Spring 让Spring创建其对象的实例-->
    <bean id="scope" class="com.ssm.scope.Scope" scope="singleton"></bean>
</beans>
ScopeTest.java

在com.ssm.scope包中创建测试类ScopeTest来测试singleton作用域,代码如下:

package com.ssm.scope;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ScopeTest {
    public static void main(String[] args) {
        //1.初始化Spring容器,加载配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

        //2.输出获得的实例
        System.out.println(applicationContext.getBean("scope"));
        System.out.println(applicationContext.getBean("scope"));
    }

运行结果如下:
在这里插入图片描述
从中可以看出,两次输出的结果相同,这说明Spring容器只创建了一个Scope类的实例

注意: Spring容器默认的作用域就是singleton。

prototype作用域

对需要保持会话状态的Bean应用使用prototype作用域。在使用prototype作用域时,Spring容器会为每个对该Bean的请求都创建一个新的实例。

要将Bean定义为prototype作用域,只需在配置文件中将< bean >元素的scope属性值设置为prototype即可,代码如下:

<bean id="scope" class="com.ssm.scope.Scope" scope="prototype">

修改完配置文件后,我们再次运行测试类ScopeTest,输出结果如下:

在这里插入图片描述
从中可以看到,两次输出的Bean实例并不相同,这说明在prototype作用域下创建了两个不同的Scope实例。

Bean的装配方式

Bean的装配可以理解为依赖关系注入,Spring容器支持多种形式的Bean装配方式,如基于XML的装配、基于Annotation(注解)的装配和自动装配等。

基于XML的装配

Spring提供了两种基于XML的装配方式; 设值注入(Setter)和构造注入.

在Spring实例化Bean的过程中,Spring首先会调用Bean的默认构造方法来实例化Bean对象,然后通过反射的方式调用setter()方法来注入属性值。因此,设置注入要求Bean必须满足以下两点要求:

  1. Bean类必须提供一个默认的无参构造方法。
  2. Bean类必须为需要注入的属性提供对应的setter()方法。

使用设置注入时,在Spring配置文件中需要使用< bean >元素的子元素< property >来为每个属性注入值;而使用构造注入时,在配置文件中需要使用< bean >元素的子元素< constructor-arg >来定义构造方法的参数,可以使用其values属性(或子元素) 来设置该参数的值。

代码实现
User.java

在src/java目录下创建一个com.ssm.assemble包,在该包中创建User类,并在类中定义userName、password和list集合3个属性。代码如下:

package com.ssm.assemble;

import java.util.List;

public class User {
    private  String userName;
    private  String password;
    private List<String> list;

    /**
     * 1.使用构造注入:
     * 1.1提供所有参数的构造方法
     */
    public User(String userName, String password, List<String> list) {
        this.userName = userName;
        this.password = password;
        this.list = list;
    }

    @Override
    public String toString() {
        return "User{" +
                "userName='" + userName + '\'' +
                ", password='" + password + '\'' +
                ", list=" + list +
                '}';
    }

    /**
    * 2.使用设值注入
    * 2.1提供默认的空参构造方法
    * 2.2为所有属性提供setter()方法
    */
    public User() {
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setList(List<String> list) {
        this.list = list;
    }
}

applicationContext.xml

在Spring的配置文件中,增加通过构造注入和设置注入的方法装配User实例的两个Bean

<?xml version="1.0" encoding="UTF-8"?>
<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.xsd">


    <!--通过构造注入装配Bean-->
    <bean id="user1" class="com.ssm.assemble.User">
        <constructor-arg index="0" value="小鑫"/>
        <constructor-arg index="1" value="726599123"/>
        <constructor-arg index="2">
            <list>
                <value>"小鑫1"</value>
                <value>"小鑫2"</value>
            </list>
        </constructor-arg>
    </bean>

    <!--通过设值注入装配Bean-->
    <bean id="user2" class="com.ssm.assemble.User">
        <property name="userName" value="小鑫123"/>
        <property name="password" value="721020"/>
        <property name="list">
            <list>
                <value>"小鑫3"</value>
                <value>"小鑫4"</value>
            </list>
        </property>
    </bean>
</beans>

< constructor-arg >元素用于定义构造方法的参数,其属性idnex表示其索引(从0开始),value属性用于设置注入的值,其子元素< list >为User类中对应的list集合属性注入值。然后又通过设置注入的方法装配User类的实例,其中< property >元素用于调用Bean实例中的setter()方法完成属性赋值,从而完成依赖注入。

XmlAssembleTest.java

在com.ssm.assemble包中创建测试类XmlAssembleTest,在类中分别获取并输出配置文件中的user1和user2实例,代码如下;

package com.ssm.assemble;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class XmlAssembleTest {
    public static void main(String[] args) {
        //1.初始化Spring容器,加载配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

        //2.输出获得的实例
        System.out.println(applicationContext.getBean("user1"));
        System.out.println(applicationContext.getBean("user2"));
    }
}

运行程序,结果如下:
在这里插入图片描述

基于Annotation的装配

在Spring中,虽然可以使用XML配置文件可以实现Bean的装配工作,但是一旦应用中有很多Bean,就会导致XML配置文件过于臃肿。因此,Spring提供了对Annotation(注解)技术的全面支持。

Spring中定义了一系列的注解,如下表所示:
在这里插入图片描述
注意: 虽然@Repository、@Setvice和@Controller的功能与@Component注解的功能相同,但能使标注类本身用途更加清晰,建议使用@Repository、@Setvice和@Controller注解。

代码实现
UserDao.java

在src的目录下创建一个com.ssm.annotation包,在该包中创建接口UserDao,并在接口中定义一个save()方法

package com.ssm.annotation;

public interface UserDao {
    public  void save();
}

UserDaoImpl.java

在com.ssm.annotation包中创建UserDao接口的实现类UserDaoImpl

package com.ssm.annotation;


import org.springframework.stereotype.Repository;

//使用@Repository注解将UserDaoImpl类标识为Spring中的Bean
@Repository("userDao")
public  class UserDaoImpl implements  UserDao {
    @Override
    public void save() {
        System.out.println("userDao.save()");
    }
}

在该类中,首先使用@Repository注解将UserDaoImpl类标识为Spring中的Bean,其写法相当于配置文件中< bean id=“userDao” class=“com.ssm.annotation.UserDaoImpl” >的编写

UserService.java

在com.ssm.annotation包创建接口UserService,在接口中同样定义一个save()方法, 代码如下:

package com.ssm.annotation;

public interface UserService {
    public  void save();
}

UserServiceImpl.java

在com.ssm.annotation包中创建UserService接口的实现类UserServiceImpl。代码如下:

package com.ssm.annotation;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;


//使用@Service注解将UserServiceImpl类标识为Spring中的Bean
@Service("userService")
public class UserServiceImpl implements  UserService {

    //使用@Resource 注解注入
    @Autowired
    @Qualifier("userDao")
    private UserDao userDao;

    @Override
    public void save() {
        userDao.save();
        System.out.println("执行 userService.save()");
    }
}

在该类中,首先使用@Repository注解将UserDaoImpl类标识为Spring中的Bean,其写法相当于配置文件中< bean id=“userDao” class=“com.ssm.annotation.UserDaoImpl” >的编写;然后使用@Autowired+@Qualifier(“userDao”)标注在属性userDao上,这相当于配置文件中<property name="userDao"ref="userDao”/>的写法,相当于实现了setter()注入。

UserController.java

在com.ssm.annotation包中创建控制器类UserController,代码如下:

package com.ssm.annotation;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;


//使用@Controller注解将UserController类标识为Spring中的Bean
@Controller("UserController")
public class UserController {

    //使用@Resource注解注入
    @Autowired
    @Qualifier("userService")
    private  UserService userService;

    public  void save(){
        userService.save();
//        System.out.println(userService);
        System.out.println("运行userController.save()");
    }
}

在该类中,我们使用@Controller注解标注了UserController类,这相当于在配置文件中编写< bean id=“userController” class=" com.ssm.annotation.UserController" />;其余的和UserServiceImpl类似,就不多说了。

applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd>
    <!--使用context命名控件在配置文件中开启相应的注解处理器-->
    <context:annotation-config/>
    <!--分别定义3个Bean实例-->
    <bean id="userDao" class="com.ssm.annotation.UserDaoImpl"/>
    <bean id="userService" class="com.ssm.annotation.UserServiceImpl"/>
    <bean id="userController" class="com.ssm.annotation.UserController"/>
 </beans>

首先,在< beans >元素中添加了包含context的约束信息;然后通过配置< context: annotation-config/>来开启注解处理器,最后分别定义了3个Bean对应的3个实例。与XML配置方式有所不同的是,这里不再需要配置子元素。

上述Spring配置文件中的注解方式虽然较大程度地简化了XML文件中Bean的配置,但仍需在Spring配置文件中一一配置相应的Bean,为此Spring注解提供了另一种高效的注解配置方法(对包路径下的所有Bean文件进行扫描),代码如下:

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

这一行代码就相当于将annotation包下,只要添加了Spring注解的类,都添加到了Spring容器中。
需要注意的是:对指定包中的注解进行扫描前,先向项目中导入SpringAOP的JAR包spring-aop-5.0.2.RELEASE.jar,不然会报错。

AnnotationAssembleTest.java

在com.ssm.annotation包中创建测试类AnnotationAssembleTest

package com.ssm.annotation;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AnnotationAssembleTest {
    public static void main(String[] args) {
        //1.初始化Spring容器,加载配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

       //获取UserController实例
        UserController userController = (UserController) applicationContext.getBean("userController");
        //调用UserController中的save()方法
        userController.save();
    }
}

执行程序后,效果如下图所示:
在这里插入图片描述

自动装配

Spring的< bean >元素中包含一个autowire属性,我们可以通过设置autowire的属性值来自动装配Bean,所谓自动装配,就是将一个Bean自动注入其他Bean的Property中

antowire属性有5个值,如下表所示:
在这里插入图片描述

代码实现
修改UserServiceImpl.java和UserController.java
//使用@Service注解将UserServiceImpl类标识为Spring中的Bean
@Service("userService")
public class UserServiceImpl implements  UserService {
    
    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void save() {
        userDao.save();
        System.out.println("执行 userService.save()");
    }
}
//使用@Controller注解将UserController类标识为Spring中的Bean
@Controller("UserController")
public class UserController {
    
    private  UserService userService;

    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public  void save(){
        userService.save();
//        System.out.println(userService);
        System.out.println("运行userController.save()");
    }
}

我们取消了通过注解注入的,为其属性设置了setter()方法.

修改applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd>
    <!--使用context命名控件在配置文件中开启相应的注解处理器-->
    <context:annotation-config/>
    <!--分别定义3个Bean实例-->
    <bean id="userDao" class="com.ssm.annotation.UserDaoImpl"/>
    <bean id="userService" class="com.ssm.annotation.UserServiceImpl" autowire="byName"/>
    <bean id="userController" class="com.ssm.annotation.UserController" autowire="byName"/>
</beans>

在配置文件中,用于配置userService和userController的< bean >元素中除了id和class属性外,还增加了autowire属性,将其属性值设置为byName; 设置了autowire="byName"后,Spring会自动寻找userServiceBean中的属性,并将其属性名称与配置文件中定义的Bean做匹配,由于UserServiceImpl中定义了userDao属性及其setter()方法,这与配置文件中id为userDao的Bean相匹配,因此Spring会自动地将id为userDao的Bean装配到id为userService的Bean中。

运行程序,效果如下:
在这里插入图片描述

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐