第2章 Spring中的Bean

2.1 Bean的配置

Bean本质是Java中的类。Spring可以被看做一个大型工厂,这个工厂的作用就是生产和管理Spring容器zho中的Bean。想在项目中使用这个工厂,就需要对Spring的配置文件进行配置。

Spring支持XML和Properties两种格式的配置文件。常用XML文件配置,该方式通过XML文件来注册并管理Bean之间的依赖关系。

XML配置文件的根元素是<beans>,包含了多个<bean>子元素,每个子元素地定义一个Bean。

<bean>元素的常用属性及其子元素

如果在Bean中未指定id和name,则Spring会把class的值当做id使用。

getBean( id/name/class );

2.2 Bean的实例化:

2.21 构造器实例化:Spring容器通过Bean对应类中默认的无参构造方法来实例化Bean

package com.itheima.instance.constructor;public class Bean1 {
<?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-4.3.xsd">
    <bean id="bean1" class="com.itheima.instance.constructor.Bean1" />
</beans 1 package com.itheima.instance.constructor;
package com.itheima.instance.constructor;
import org.springframework.context.ApplicationContext;
import
    org.springframework.context.support.ClassPathXmlApplicationContext;
public class InstanceTest1 {
    public static void main(String[] args) {
        // 定义配置文件路径
        String xmlPath = "com/itheima/instance/constructor/beans1.xml";
        // ApplicationContext在加载配置文件时,对Bean进行实例化
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        Bean1 bean = (Bean1) applicationContext.getBean("bean1");
        System.out.println(bean);
    }
}

如果xml文件不在包里,就不需要在路径上加入包名;如果在包里,需要加上包名。

输出类Bean1的地址:

[email protected]

2.22静态工厂方式实例化:要求开发者创建一个静态工厂的方法来创建Bean的实例,其Bean配置中的class属性所指定的不再是Bean实例的实现类,而是静态工厂类,同时还需要使用factory-method属性来指定所创建的静态工厂方法。

package com.itheima.instance.static_factory;
public class Bean2 {
}
package com.itheima.instance.static_factory;
public class MyBean2Factory {
    //使用自己的工厂创建Bean2实例
    public static Bean2 createBean222(){
        return new Bean2();
    }
}
<?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-4.3.xsd">
    <bean id="bean2" class="com.itheima.instance.static_factory.MyBean2Factory"
        factory-method="createBean222" />
    <!-- factory-method后面等于的东西是方法 -->
</beans>
package com.itheima.instance.static_factory;
public class MyBean2Factory {
    //使用自己的工厂创建Bean2实例
    public static Bean2 createBean222(){
        return new Bean2();
    }
}

输出类Bean2的地址:

[email protected]

说白了就是,有一个类叫Bean2,要实例化Bean2,这种方法不直接实例化它,要再创一个工厂类MyBean2Factory,工厂类里有个方法返回实例化的Bean2,return new Bean2(),先new再返回,并且这个方法名和Factory-method对应。

2.23实例工厂方法实例化:采用实例工厂,不再是静态工厂,采用直接创建Bean实例的方式。

package com.itheima.instance.factory;
public class Bean3  {
}
package com.itheima.instance.factory;
public class MyBean3Factory {
    public MyBean3Factory() {
        System.out.println("bean3工厂实例化中");
    }
    //创建Bean3实例的方法
    public Bean3 createBean111(){
        return new Bean3();
    }
}
<?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-4.3.xsd">
    <!-- 配置工厂 -->
    <bean id="myBean3Factory"
            class="com.itheima.instance.factory.MyBean3Factory" />
    <!-- 使用factory-bean属性指向配置的实例工厂,
          使用factory-method属性确定使用工厂中的哪个方法-->
    <bean id="bean3" factory-bean="myBean3Factory"
           factory-method="createBean111" />
</beans>
package com.itheima.instance.factory;
import org.springframework.context.ApplicationContext;
import
    org.springframework.context.support.ClassPathXmlApplicationContext;
public class InstanceTest3 {
    public static void main(String[] args) {
        // 指定配置文件路径
        String xmlPath = "com/itheima/instance/factory/beans3.xml";
        // ApplicationContext在加载配置文件时,对Bean进行实例化
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext(xmlPath);
        System.out.println(applicationContext.getBean("bean3"));

        //顺便尝试构造器实例化
        String xmlPath2 = "com/itheima/instance/factory/beans3.xml";
        ApplicationContext applicationContext2 =
                new ClassPathXmlApplicationContext(xmlPath2);
        System.out.println(applicationContext2.getBean("myBean3Factory"));
    }
} 

输出:

bean3工厂实例化中
[email protected]

bean3工厂实例化中
[email protected]

这种方式说白了就是:有一个类Bean3,要实例化它,不直接实例化,再造一个工厂类MyBean3Factory来return new Bean3();

在xml文件中,先配置实例工厂类的bean;再配置要类Bean3的bean,并通过factory-bean指明是哪个实例工厂类(谁)要实例它,再通过factory-method指明是哪个方法来返回实例后的它。

(回顾旧知识:实例工厂类MyBean3Factory里面有一个无参构造函数,在实例MyBean3Factory的时候自动执行该方法,构造函数要求是无参无返回值,方法名和类名一样)

2.3 Bean的作用域

Spring 4.3中为Bean的实例定义了7种作用域。

singleton和prototype最常用,解释如下。

1.singleton作用域:

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

package com.itheima.scope;
public 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">

    <bean id="scope" class="com.itheima.scope.Scope" scope="singleton"/>
</beans>
package com.itheima.scope;
import org.springframework.context.ApplicationContext;
import
    org.springframework.context.support.ClassPathXmlApplicationContext;
public class ScopeTest {
    public static void main(String[] args) {
        // 定义配置文件路径
        String xmlPath = "com/itheima/scope/beans4.xml";
        // 加载配置文件
        ApplicationContext applicationContext =
                    new ClassPathXmlApplicationContext(xmlPath);
        // 输出获得实例
        System.out.println(applicationContext.getBean("scope"));
        System.out.println(applicationContext.getBean("scope"));
    }
}

输出:

[email protected]

[email protected]

2.prototype作用域:

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

xml文件中的<bean>改一下,<bean id="scope" class="com.itheima.scope.Scope" scope="prototype" />

输出:

[email protected]
[email protected]

2.4 Bean的生命周期

例如singleton和prototype作用域的生命周期。

singleton关闭时销毁,prototype长时间不用自动销毁。

Bean生命周期流程图:

2.5 Bean的装配方式:

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

2.51 基于XML的装配:设值注入(Setter Injectiion)和构造注入(Constructor Injection)

构造注入要求:提供默认无参构造方法,为所有属性提供setter方法

设值注入要求:Bean类必须提供一个默认的无参构造方法,并且为需要注入的属性提供对应的setter方法

package com.itheima.assemble;
import java.util.List;
public class User {
    private String username;
    private Integer password;
    private List<String> list;
    /**
     * 1.使用构造注入
     * 1.1提供带所有参数的有参构造方法。
     */
    public User(String username, Integer password, List<String> list) {
        super();// 调用父类的无参构造方法,可以不写
        this.username = username;
        this.password = password;
        this.list = list;
    }
    /**
     * 2.使用设值注入
     * 2.1提供默认空参构造方法 ;
     * 2.2为所有属性提供setter方法。
     */
    public User() {//无参构造方法
        super();//// 调用父类Object的无参构造方法,可以不写
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public void setPassword(Integer password) {
        this.password = password;
    }
    public void setList(List<String> list) {
        this.list = list;
    }
    @Override
    public String toString() { // 重写父类的Object的toString方法
        return "User [username=" + username + ", password=" + password +
                ", list=" + list + "]";
    }
}
<?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-4.3.xsd">
    <!--1.使用构造注入方式装配User实例 -->
    <bean id="user1" class="com.itheima.assemble.User">
        <constructor-arg index="0" value="tom" />
        <constructor-arg index="1" value="123456" />
        <constructor-arg index="2">
            <list>
                <value>"constructorvalue1"</value>
                <value>"constructorvalue2"</value>
            </list>
        </constructor-arg>
    </bean>
    <!--2.使用设值注入方式装配User实例 -->
    <bean id="user2" class="com.itheima.assemble.User">
        <property name="username" value="张三"></property>
        <property name="password" value="654321"></property>
        <!-- 注入list集合 -->
        <property name="list">
            <list>
                <value>"setlistvalue1"</value>
                <value>"setlistvalue2"</value>
            </list>
        </property>
    </bean>
</beans>

构造注入:constructor-arg元素中的index表示的是有参构造方法的参数顺序,value表示注入的值。

设值注入:property元素中的name表示要注入的属性名,value表示要注入的值,子元素list同样表示要注入的值。

package com.itheima.assemble;
import org.springframework.context.ApplicationContext;
import
    org.springframework.context.support.ClassPathXmlApplicationContext;
public class XmlBeanAssembleTest {
    public static void main(String[] args) {
        // 定义配置文件路径
        String xmlPath = "com/itheima/assemble/beans5.xml";
        // 加载配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        // 构造方式输出结果
        System.out.println(applicationContext.getBean("user1"));
        // 设值方式输出结果
        System.out.println(applicationContext.getBean("user2"));
    }
}

为了能看到结果,重写toString方法。

输出:

User [username=tom, password=123456, list=["constructorvalue1", "constructorvalue2"]]
User [username=张三, password=654321, list=["setlistvalue1", "setlistvalue2"]]

2.52 基于注解(Annotation)的装配

XML文件可以实现Bean的装配工作,但是Bean多时,XML文件臃肿巨大,为后续的维护和升级带来困难。为此,提供了对注解技术的全面支持。

package com.itheima.annotation;
public interface UserDao {
    public void save();
}
package com.itheima.annotation;
import org.springframework.stereotype.Repository;

/**首先使用@Repository注解将UserDaoImpl类标识为Spring中的Bean,相当于配置文件中的
<bean id="userDao" class="com.itheima.annotation.UserDaoImpl"/> 很普通的配置
*/
@Repository("userDao")
public class UserDaoImpl implements UserDao{
   public void save(){
      System.out.println("userdao...save...");
   }
}
package com.itheima.annotation;
public interface UserService {
    public void save();
}
package com.itheima.annotation;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;

/**使用@Service注解将UserServiceImpl类标识为Spring中的Bean,相当于
<bean id="userService" class="com.itheima.annotation.UserServiceImpl"/> 很普通的配置*/
@Service("userService") 

public class UserServiceImpl implements UserService{

    /**使用@Resource注解标注属性uesrDao上,相当于配置文件中的
     <property name="userDao" ref="userDao"/>,
     不是普通的配置,依赖注入,将id为userDao的Bean实例注入到userService实例中
     */
    @Resource(name="userDao")
    private UserDao userDao;
    public void save() {
         //调用userDao中的save方法
        this.userDao.save();
        System.out.println("userservice....save...");
    }
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}
package com.itheima.annotation;
import javax.annotation.Resource;
import org.springframework.stereotype.Controller;

/**使用@Controller 注解标注了 UserController类,这相当于配置文件中编写
 <bean id="userController" class="com.itheima.annotation.UserController"/>;普通配置
*/
@Controller("userController")

public class UserController {
    /**
     @Resource 注解标注在userService属性上,相当于配置文件中编写
     <property name="userService" ref="userService"/>,依赖注入
     */
    @Resource(name="userService")
    private UserService userService;
    public void save(){
        this.userService.save();
        System.out.println("userController...save...");
    }
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
}
<?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-4.3.xsd
            http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-4.3.xsd">

     <!-- 凡出现context都是约束信息,使用 context 命名空间 ,在配置文件中开启相应的注解处理器 -->
     <context:annotation-config />
    <!--使用 context 命名空间 ,通知Spring扫描指定包下所有Bean类,进行注解解析-->
     <context:component-scan base-package="com.itheima.annotation" />
</beans>
package com.itheima.annotation;
import org.springframework.context.ApplicationContext;
import
   org.springframework.context.support.ClassPathXmlApplicationContext;
public class AnnotationAssembleTest {
    public static void main(String[] args) {
        // 定义配置文件路径
        String xmlPath = "com/itheima/annotation/beans6.xml";
        // 加载配置文件
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext(xmlPath);
        // 获取UserController实例
        UserController userController =
          (UserController) applicationContext.getBean("userController");
        // 调用UserController中的save()方法
        userController.save();
    }
}

输出:

userdao...save...
userservice....save...
userController...save...

说白了,先配置类Dao,再把Dao用依赖注入的方式注入到Service,再把Service用依赖注入的方式注入到Controller。注解的配置和注入形式不一样,最后在控制层调用say方法,层层往下,先到服务层,再到数据层,数据层(Dao层)是底层,再层层往上分别调用say方法,因此输出顺序是Dao,Service,Controller。

(上述案例中用@Autowired注解替换@Resource也可以达到同样效果)

2.53 自动装配

注解方式装配一定程度减少配置文件的代码量,但是也有企业项目是没有使用注解方式开发的,自动装配也可以减少代码量。

Bean元素中包含一个autowire属性,通过属性值来自动装配Bean元素。所谓自动装配,就是将一个Bean自动地注入到其他Bean的Property中。autowire属性有5个值。

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-4.3.xsd
            http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-4.3.xsd">
        <!-- 使用bean元素的autowire属性完成自动装配 -->
    <bean id="userDao" class="com.itheima.annotation.UserDaoImpl" />
    <bean id="userService"
      class="com.itheima.annotation.UserServiceImpl" autowire="byName" />
    <bean id="userController"
      class="com.itheima.annotation.UserController" autowire="byName"/>
</beans>

用于配置userService和userController的<bean>元素中除了id和class属性外,还增加了autowire属性,并将其属性值设置为byName。在默认情况下,配置文件中要通过ref来装配Bean,但设置了autowire=“byName”后,Spring会自动寻找userService Bean中的属性,并将其属性名称与配置文件中定义的Bean做匹配。由于UserServiceImpl中定义了userDao属性及其setter方法,这与配置文件中的id为userDao的Bean相匹配,所以Spring会自动地将id为userDao的Bean装配到id为userService的Bean中。自动装配同样能完成依赖注入。

原文地址:https://www.cnblogs.com/shoulinniao/p/10884386.html

时间: 2024-10-25 05:09:27

第2章 Spring中的Bean的相关文章

spring配置,spring中的bean 的id不能相同

lib下加入包 spring.jar commons-logging.jar src下添加 applicationContext.xml 1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLS

JSP访问Spring中的bean

JSP访问Spring中的bean <%@page import="com.sai.comment.po.TSdComment"%> <%@page import="com.sai.comment.service.CommentService"%> <%@page contentType="text/html" pageEncoding="UTF-8"%> <%@page import

传统javabean与spring中的bean的区别

javabean已经没人用了 springbean可以说是javabean的发展, 但已经完全不是一回事儿了 用处不同:传统javabean更多地作为值传递参数,而spring中的bean用处几乎无处不在,任何组件都可以被称为bean. 写法不同:传统javabean作为值对象,要求每个属性都提供getter和setter方法:但spring中的bean只需为接受设值注入的属性提供setter方法. 生命周期不同:传统javabean作为值对象传递,不接受任何容器管理其生命周期:spring中的

spring 中的 bean 是线程安全的吗?

Spring 不保证 bean 的线程安全.默认 spring 容器中的 bean 是单例的.ZFX代理申请www.fx61.com/brokerlist/zfx.html,当单例中存在竞态条件,即有线程安全问题.如下面的例子计数类package constxiong.interview.threadsafe;/** 计数类 @author ConstXiong @date 2019-07-16 14:35:40*/public class Counter {private int count

Spring 中的bean 是线程安全的吗?

结论: 不是线程安全的 Spring容器中的Bean是否线程安全,容器本身并没有提供Bean的线程安全策略,因此可以说Spring容器中的Bean本身不具备线程安全的特性,但是具体还是要结合具体scope的Bean去研究. Spring 的 bean 作用域(scope)类型 1.singleton:单例,默认作用域. 2.prototype:原型,每次创建一个新对象. 3.request:请求,每次Http请求创建一个新对象,适用于WebApplicationContext环境下. 4.ses

spring中bean的五种作用域?Spring中的bean是线程安全的吗?

spring中bean的五种作用域 当通过spring容器创建一个Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定的作用域.Spring支持如下5种作用域: singleton:单例模式,在整个Spring IoC容器中,使用singleton定义的Bean将只有一个实例 prototype:原型模式,每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例 request:对于每次HTTP请求,使用request定义的Bea

Spring中的Bean——装载

Bean的装配方式 Bean的装配可以理解为依赖关系注入 基于XML的装配 a) 设值注入 i.要求: Bean 类必须提供一个默认的无参构造方法. Bean 类必须为需要注入的属性提供对应的setter方法. b) 构造注入 package com.itheima.assemble; import java.util.List; public class User { private String username; private Integer password; private List

半夜思考之查漏补缺 , Spring 中的 Bean 继承机制

这里的继承 , 不是 Java 中的继承 , 下面就总结下 Bean继承与Java继承的区别: Spring 中的子类 Bean 和父 Bean 可以是不同类型 , 但是 Java 中的继承则可保证子类是一种特殊的父类 ; Spring 中 Bean 的继承时实例之间的关系 , 因此主要表现为参数值的延续 ; 而 Java 中的继承是类之间的关系 , 主要表现为方法和属性的延续 ; Spring 中的子 Bean 不可作为父 Bean 使用 , 不具备多态性 ; 而 Java 中的子类实例完全可

Spring讲解二:Spring中的Bean配置1---基于XML文件的方式

一.在Spring的IOC容器中配置Bean 在xml文件中通过bean节点配置bean id:Bean的名称: (1) 在IOC容器中必须是唯一的 (2) 若id没有指定,Spring自动将权限限定性类名作为bean的名字 (3) id可以指定多个名字,名字之间可以用逗号.分号.或空格分隔 二.Spring容器 在Spring IOC容器读取Bean配置创建Bean实例之前,必须对它进行初始化.只有在容器实例化后,才可以从IOC容器中获取Bean实例并使用. Spring提供了两种类型的IOC