Spring总结
Java Bean
类的定义,符合如下规则的Java对象称为Java Bean
- 必须有包
- 必须有无参数构造器
- 必须实现 序列化接口
- 所有属性为private
- 有getXXX setXXX 方法声明的"Bean属性".
Bean 的生命周期管理
- Spring 在默认情况下, 其中Bean都是单例的
- 设置 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对象的生命周期管理.
-
单例对象 singleton(单例)
- 创建: 在Spring容器初始化时候, 创建单例对象, 如果设置了init-method属性, 则在创建对象以后调用初始化方法.
- 使用: 每次调用getBean时候, 返回的都是同一个对象
- 销毁: 在Spring容器关闭时候,Spring会自动销毁单例对象, 如果指定了destroy-method属性, 则会在销毁之前执行 销毁 方法.
-
多例对象 prototype(原型)
- 创建: 在调用getBean方法时候, 创建对象, 如果设置了init-method属性, 则在创建对象以后调用初始化方法.
- 使用: 每次调用getBean时候, 返回的都是新对象
- 销毁: Spring 不管,也不会调用 destroy-method
Bean 生命周期与延迟实例化
问题:
单例对象默认情况下在容器启动时立即初始化, 如果这些对象内存耗用高, 则启动会很慢.
解决办法:
对于内存占用高, 使用少的对象, 可以设置延迟(懒惰,按需)实例化, 在bean标签上使用懒惰属性设置即可.
设置了懒惰属性为true:
- 容器启动时候, bean不实例化
- 在第一次getBean时候实例化
- 是单例bean对象.
- 多例对象没有延迟初始化问题.
Spring 创建对象的3种方式
Spring 帮助创建JavaBean对象, Spring 支持3种对象创建方式
- 利用构造器创建Java Bean
- 利用静态"工厂方法"创建对象
- 利用动态工厂方法创建对象
案例:
<!-- 利用静态工厂方法创建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:
- IoC全称是Inversion of Control,被译为控制反转;
- IoC是指程序中对象的获取方式发生反转,由最初的new方式创建,转变为由第三方框架创建、注入(DI),它降低了对象之间的耦合度。
- Spring容器是采用DI方式实现了IOC控制,IOC是Spring框架的基础和核心;
DI:
- DI全称是Dependency Injection ,被译为依赖注入;
- DI的基本原理就是将一起工作具有关系的对象,通过构造方法参数或方法参数传入建立关联,因此容器的工作就是创建bean时注入那些依赖关系。
- DI主要有两种注入方式,即Setter注入和构造器注入
Setter注入(Bean属性注入)
实现步骤:
-
创建接口 Tools
public interface Tools { String getName(); }
-
创建 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 + "]"; } }
-
斧子 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 + "]"; } }
-
创建类型 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 + "]"; } }
-
编写配置文件 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>
-
测试:
@Test public void testQiang(){ Man qiang = ctx.getBean("qiang",Man.class); qiang.work(); }
优点: 更换光头强的工具只需要修改配置文件即可,不需要改变任何Java代码
构造器参数注入
Spring 支持构造器参数注入:
案例:
-
给Man增加有参数构造器:
public Man(String name) { this.name = name; }
-
利用配置文件调用有参数构造器
<!-- 构造器参数注入 --> <bean id="miniQiang" class="spring.Man"> <!-- constructor-arg 标签用于实现构造器参数注入, index 用与指定构造器参数序号 --> <constructor-arg index="0" value="小强"/> <property name="tool" ref="saw"/> </bean>
-
测试:
@Test public void testMiniQiang(){ //测试: 构造器参数注入 Man qiang = ctx.getBean("miniQiang", Man.class); qiang.work(); }
自动注入
Spring 为了简化注入,提供了自动注入功能:
案例:
当指定 autowire=byName时候, Spring会按照set方法的名字找到一致的id名一致的Bean, 并实现自动装配.
实现步骤:
-
定义id为tool的bean
<bean id="tool" class="spring.Saw"/>
-
在自动装配的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>
-
测试:
@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>