Spring总结

Java Bean

类的定义,符合如下规则的Java对象称为Java Bean

  1. 必须有包
  2. 必须有无参数构造器
  3. 必须实现 序列化接口
  4. 所有属性为private
  5. 有getXXX setXXX 方法声明的"Bean属性".

Bean 的生命周期管理

  1. Spring 在默认情况下, 其中Bean都是单例的
  2. 设置 scope="prototype" 以后就是多例的对象了

案例:

<!-- 设置 scope="prototype" 
  scope 范围 prototype 原型 
  设置 scope="prototype" 属性后, Spring会在
  每次调用 getBean时候创建对象! Spring会为对象
  创建多个实例! 也就是多例的!-->
<bean id="time2" scope="prototype" 
    factory-bean="cal"
    factory-method="getTime"></bean>

Spring 中的Bean对象, 由Spring控制对象的创建和销毁, 这个过程称为Spring中Bean对象的生命周期管理.

  1. 单例对象 singleton(单例)

    • 创建: 在Spring容器初始化时候, 创建单例对象, 如果设置了init-method属性, 则在创建对象以后调用初始化方法.
    • 使用: 每次调用getBean时候, 返回的都是同一个对象
    • 销毁: 在Spring容器关闭时候,Spring会自动销毁单例对象, 如果指定了destroy-method属性, 则会在销毁之前执行 销毁 方法.
  2. 多例对象 prototype(原型)

    • 创建: 在调用getBean方法时候, 创建对象, 如果设置了init-method属性, 则在创建对象以后调用初始化方法.
    • 使用: 每次调用getBean时候, 返回的都是新对象
    • 销毁: Spring 不管,也不会调用 destroy-method 

Bean 生命周期与延迟实例化

问题:

单例对象默认情况下在容器启动时立即初始化, 如果这些对象内存耗用高, 则启动会很慢.

解决办法:

对于内存占用高, 使用少的对象, 可以设置延迟(懒惰,按需)实例化, 在bean标签上使用懒惰属性设置即可.

设置了懒惰属性为true:

  1. 容器启动时候, bean不实例化
  2. 在第一次getBean时候实例化
  3. 是单例bean对象.
  4. 多例对象没有延迟初始化问题.

Spring 创建对象的3种方式

Spring 帮助创建JavaBean对象, Spring 支持3种对象创建方式

  1. 利用构造器创建Java Bean
  2. 利用静态"工厂方法"创建对象
  3. 利用动态工厂方法创建对象

案例:

<!-- 利用静态工厂方法创建Java Bean对象 -->
<bean id="cal" class="java.util.Calendar"
     factory-method="getInstance"></bean>

<!-- 利用bean(对象)的工厂方法创建对象-->
<!-- Spring会调用cal对象的getTime方法创建对象 -->
<bean id="time" factory-bean="cal"
    factory-method="getTime"></bean>

测试:

@Test
public void testCal(){
    //初始化 Spring 容器
    ApplicationContext ctx=
        new ClassPathXmlApplicationContext(
        "applicationContext.xml");

    //获取Java Bean, 进行测试
    Calendar cal=ctx.getBean(
            "cal", Calendar.class);
    System.out.println(cal); 
}

@Test
public void testTime(){
    //初始化Spring 容器
    ApplicationContext ctx=
        new ClassPathXmlApplicationContext(
        "applicationContext.xml");

    //检查是否成功创建了 time 对象
    Date time=ctx.getBean(
            "time", Date.class);
    System.out.println(time); 
}

什么是IOC/DI

IOC:

  1. IoC全称是Inversion of Control,被译为控制反转;
  2. IoC是指程序中对象的获取方式发生反转,由最初的new方式创建,转变为由第三方框架创建、注入(DI),它降低了对象之间的耦合度。
  3. Spring容器是采用DI方式实现了IOC控制,IOC是Spring框架的基础和核心;

DI:

  1. DI全称是Dependency Injection ,被译为依赖注入;
  2. DI的基本原理就是将一起工作具有关系的对象,通过构造方法参数或方法参数传入建立关联,因此容器的工作就是创建bean时注入那些依赖关系。
  3. DI主要有两种注入方式,即Setter注入和构造器注入

Spring总结

Setter注入(Bean属性注入)

实现步骤:

  1. 创建接口 Tools

    public interface Tools {
        String getName();
    }
    
  2. 创建 Saw

    /**
     * 电锯
     */
    public class Saw 
        implements Tools, Serializable {
    
        private String name;
    
        public Saw() {
            name = "电锯";
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "Saw [name=" + name + "]";
        }
    
    }
    
  3. 斧子 Axe

    /**
     * 斧子 
     */
    public class Axe 
        implements Tools, Serializable{
        private  String name;
        public Axe() {
            name = "斧子";
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        @Override
        public String toString() {
            return "Axe [name=" + name + "]";
        }
    
    }
    
  4. 创建类型 Man

    public class Man implements Serializable {
        private Tools tool;
        private String name;
    
        public Man() {
        }
    
        public void work(){
            System.out.println(name+"使用"+
                    tool.getName()+"砍树!");
        }
    
        public Tools getTool() {
            return tool;
        }
    
        public void setTool(Tools tool) {
            this.tool = tool;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "Man [tool=" + tool + ", name=" + name + "]";
        }
    
    }
    
  5. 编写配置文件 applicationContext.xml:

    <bean id="axe" class="spring.Axe"></bean>
    
    <bean id="saw" class="spring.Saw"></bean>
    
    <!-- ref="axe" 表示将id为axe的bean对象注入到 bean属性tool 中! 
                  ref 属性用于注入bean对象
                  value 属性用于注入基本值, 包括字符串-->
    <bean id="qiang" class="spring.Man">
        <property name="tool" ref="saw"></property>
        <property name="name" value="光头强"></property>
    </bean>
    
  6. 测试:

    @Test
    public void testQiang(){
        
        Man qiang = ctx.getBean("qiang",Man.class);
        qiang.work();
    }
    

    优点: 更换光头强的工具只需要修改配置文件即可,不需要改变任何Java代码

构造器参数注入

Spring 支持构造器参数注入:

案例:

  1. 给Man增加有参数构造器:

    public Man(String name) {
        this.name = name;
    }
    
  2. 利用配置文件调用有参数构造器

    <!-- 构造器参数注入 -->
    <bean id="miniQiang" 
        class="spring.Man">
        <!-- constructor-arg 标签用于实现构造器参数注入, index 用与指定构造器参数序号 -->
        <constructor-arg index="0" value="小强"/>
        <property name="tool" ref="saw"/>
    </bean>
    
  3. 测试:

    @Test
    public void testMiniQiang(){
        //测试: 构造器参数注入
        Man qiang = ctx.getBean("miniQiang", Man.class);
        qiang.work();
    }

自动注入

Spring 为了简化注入,提供了自动注入功能:

案例:

Spring总结

当指定 autowire=byName时候, Spring会按照set方法的名字找到一致的id名一致的Bean, 并实现自动装配.

实现步骤:

  1. 定义id为tool的bean

    <bean id="tool" class="spring.Saw"/>
    
  2. 在自动装配的bean上使用 autowire="byName"

    <!-- 当指定了  autowire="byName" 属性时候,
    Spring会根据 setTool 名字查找 id为tool的
    bean , 然后自动的注入(装配) 执行setTool方法-->
    <bean id="man" class="spring.Man" autowire="byName">
        <constructor-arg index="0" value="男人"/>
    </bean>
    
  3. 测试:

    @Test
    public void testMan(){
        //测试: 按照名字自动参数注入
        Man man = ctx.getBean("man", Man.class);
        man.work();
    }
    

Spring支持各种类型的参数注入

  • 注入基本值
  • 注入Bean对象
  • 注入集合

在配置文件中注入属性:

<!-- 多种类型的参数注入 -->
<bean id="demo" class="spring.day02.DemoBean">
    <!-- 注入基本值 -->
    <property name="times" value="56"/>
    <property name="name" value="Hello"/>
    <property name="price" value="5.8"/> 
    <!-- 注入一个Bean对象 -->
    <property name="date" ref="dt"/>
    <!-- 注入集合 -->
    <property name="list">
        <list>
            <value>Tom</value>
            <value>Jerry</value>
        </list>
    </property>
    <!-- 注入空值 -->
    <property name="phone">
        <null/>
    </property>
</bean>
<bean id="dt" class="java.util.Date"/>

Spring 注解

编写声明组件扫描

<!-- 设置注解组件扫描 -->
<context:component-scan base-package="package1[,pagkage2,…,pagkageN]"/>
/*
 * Spring 会主动扫描 package 包,将标注了
 * @Component的类Xxx自动实例化为Java bean, 并且绑定id为 "xxx"
 */

注册Bean组件:@Component 与 @Repository/@Service/@Controller功能一样.

自定义bean组件ID:@Component("id") 

属性注入:@Resource(javax.annotation),@Autowired(Spring)可以注入Bean组件  /  @Value 可以注入基本值

Bean声明周期管理注解: @PostConstruct  /  @PreDestroy

<dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>javax.annotation-api</artifactId>
</dependency>