Spring学习笔记(1)

Spring的概述

Spring是什么

Spring是分层的Java SE/EE应用 full-stack轻量级开源框架,以IoC(Inverse Of Control:反转控制)AOP(Aspect Oriented Programming:面向切面编程)为内核,提供展现层 SpringMVC 和持久层 Spring JDBC 以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库。


程序耦合以及解耦

  • 程序的耦合
    • 耦合: 程序间的依赖关系
    • 包括:
      • 类之间的依赖
      • 方法间的依赖
    • 解耦: 降低程序间的依赖关系
    • 实际开发中:
      • 应该做到编译期不依赖,运行时才依赖
    • 解耦思路:
      1. 使用反射来创建对象,而避免用new
      2. 通过读取配置文件来获取要创建对象的全限定类名

用工厂模式创建对象(解耦)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/**
* 一个创建Bean对象的工厂
*
* Bean: 在计算机英语中,有可重用组件的含义。
* JavaBean: 用Java语言编写的可重用组件
* JavaBean > 实体类
*
* 他就是创建service和dao对象的。
*
* 1. 需要一个配置文件来配置service和dao
* 配置的内容: 唯一标志=全限定类名(key=value)
* 2. 通过读取配置文件中的配置的内容,反射创建对象
*
* 配置文件可以是xml也可以是properties
*/
public class BeanFactory {
// 定义一个Properties对象
private static Properties prop;

// 定义一个Map,用于存放我们要创建的对象。我们把它称之为容器
private static Map<String, Object> beans;

// 使用静态代码块为Properties对象赋值
static {
try {
prop = new Properties();
// 获取properties文件的流对象【一定要用类加载器来访问,不然程序一旦部署就找不到,放在resources下的配置文件,最后会成为根路径下的文件】
InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
prop.load(in);
// 实例化容器
beans = new HashMap<String, Object>();
// 取出配置文件中所有的key
Enumeration<Object> keys = prop.keys();
// 遍历枚举
while (keys.hasMoreElements()) {
// 取出每个key
String key = keys.nextElement().toString();
// 根据key获取value
String beanPath = prop.getProperty(key);
// 反射创建对象
Object value = Class.forName(beanPath).newInstance();
// 把key和value存入容器中
beans.put(key, value);
}
} catch (Exception e) {
// 没有读取到这个配置文件,直接抛出异常。无法继续进行下去。
throw new ExceptionInInitializerError("初始化properties失败");
}
}

/**
* 用这种方式将方法名和Bean存放在HashMap中,通过key(方法名)来取出对象。这样的对象是单例的
* @param beanName
* @return
*/
public static Object getBean(String beanName) {
return beans.get(beanName);
}

有了这样的工厂就可以通过
AccountService service = (AccountService) BeanFactory.getBean("accountService");
方式来创建对象,就是将创建对象的控制权交给了工厂,这就是控制反转

通过这种方式降低了程序之间的耦合


IOC的概念和Spring中的IOC

控制反转(IOC)把对象创建的权利交给了框架,是框架的重要特征,它包括了依赖注入(DI)和依赖查找(Dependency Lookup)。其主要作用就是削减计算机程序的耦合(程序间的依赖关系)

Spring中基于XML的IOC环境搭建

  1. 在pom.xml的依赖中加入

    1
    2
    3
    4
    5
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.0.2.RELEASE</version>
    </dependency>
  2. 然后在resources中创建一个bean.xml文件并导入约束

    1
    2
    3
    4
    5
    6
    <?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">
    </beans>
  3. 把对象的创建交给Spring来管理

    1
    2
    <bean id="accountService" class="com.xushui.service.Impl.AccountServiceImpl"></bean>
    <bean id="accountDao" class="com.xushui.dao.Impl.AccountDaoImpl"></bean>

4.测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 获取spring的IOC核心容器,并根据id获取对象
* @param args
*/
public static void main(String[] args) {
// 1.获取核心容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
// 2.根据id获取bean对象
AccountService accountService = (AccountService) ac.getBean("accountService");
// 两种方式都可以,一种是强制转换,一种是加上你要转的类的字节码文件
AccountDao accountDao = ac.getBean("accountDao",AccountDao.class);

System.out.println(accountService);
System.out.println(accountDao);
}

一些要注意的地方

ApplicationContext的三个常用实现类

1. ClassPathXmlApplicationContext: 它可以加载类路径下的配置文件,要求配置文件必须在类路径下(常用)
2. FileSystemXmlApplicationContext: 它可以加载磁盘任意路径下的配置文件(必须有访问权限)
3. AnnotationConfigApplicationContext: 它是用于读取注解创建容器的

核心容器的两个接口引发的问题

ApplicationContext(大多数采用这个):            单例对象适用
    它在构建核心容器时,创建对象采取的策略是立即加载的方式(一读取完配置文件马上创建配置文件中配置的对象)
    Spring是个很智能的框架,当你选择作用范围为prototype时,它会自动变为延迟加载策略
BeanFactory:                多例对象适用
    它在构建核心容器时,采用的是延迟加载的策略(什么时候根据id获取对象了,什么时候才创建对象)

Spring对bean管理的细节

创建bean的三种方式

  1. 使用默认构造函数创建,若类中没有默认构造方法,则对象无法创建
1
<bean id="accountService" class="com.xushui.service.Impl.AccountServiceImpl"></bean>
  1. 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)
1
2
<bean id="instanceFactory" class="com.xushui.factory.InstanceFactory"></bean>
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>
  1. 使用工厂中的静态方法创建对象(使用某个类的静态方法创建对象,并存入spring容器)
1
<bean id="accountService" class="com.xushui.factory.StaticFactory" factory-method="getAccountService"></bean>

bean对象的作用范围

bean作用范围调整

  • bean标签的scope属性:
    • 作用:用于指定bean的作用范围
    • 取值: 前两个比较常用
      • singleton: 单例的(默认值)
      • prototype: 多例的
      • request: 作用于web项目的请求范围
      • session: 作用于web项目的会话范围
      • global-session: 作用于集群环境的会话范围(全局会话范围),当不是集群环境时,他就是session

bean对象的生命周期

  • 单例对象
    • 出生: 当容器创建时,对象出生
    • 活着: 只要容器还在,对象一直活着
    • 死亡: 容器销毁,对象死亡
    • 总结: 单例对象的生命周期和容器相同
  • 多例对象
    • 出生: 当我们使用对象时,Spring框架为我们创建
    • 活着: 对象只要是在使用过程中。一直是活着
    • 死亡: 当对象长时间没用,且没有别的对象引用,由Java的垃圾回收机制回收

依赖注入(Dependency Injection)

  • 依赖关系的管理:
    • 都交由Spring框架来维护
    • 当前类需要其他类的对象,由Spring提供,我们只用在配置文件中说明
  • 依赖关系的维护我们就称之为依赖注入

注意:
经常变化的数据,并不适合注入方式

支持注入的数据类型

  1. 基本类型和String
  2. 其他bean类型(配置文件中或者注解配置过的bean)
  3. 复杂类型/集合类型

注入类型

  1. 使用构造函数提供
  2. 使用set方法提供
  3. 使用注解提供

构造函数的注入

  1. 使用的标签: constructior-arg
  2. 标签出现的位置: bean标签的内部
  3. 标签中的属性
    1. type: 用于指定要注入的数据的数据类型,该数据赋值给构造函数中该数据类型的一个或多个
    2. index: 用于给构造函数中指定索引位置的参数赋值 索引从0开始
    3. name: (常用)用于给构造函数中指定名字的参数赋值
    4. value: 用于提供String类型和基本类型的数据
    5. ref: 用于指定其他bean类的数据,值得就是Spring的IOC核心容器中出现过的bean对象

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class AccountServiceImpl implements AccountService {
private String name;
private Integer age;
private Date birthday;

public AccountServiceImpl(String name, Integer age, Date birthday){
this.name = name;
this.age = age;
this.birthday = birthday;
}

public void saveAccount() {
System.out.println("保存了 " + "名字: " + name +", 年龄: "+age+", 生日: " + birthday);
}
}

bin.xml中

1
2
3
4
5
6
7
<bean id="accountService" class="com.xushui.service.Impl.AccountServiceImpl">
<constructor-arg name="name" value="张三"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>

<bean id="now" class="java.util.Date"></bean>

优势:
在获取bean对象时,注入数据是必须的操作,否则对象无法创建。
弊端:
改变了bean的实例化方式,即使我们在创建对象时,用不到这些数据,也必须提供

set方法注入(常用)

  1. 使用的标签: property
  2. 出现的位置: bean标签的内部
  3. 标签属性:
    1. name:用于指定注入时所调用set的方法的名称
    2. value和ref与构造函数注入一样

优势:
创建对象是没有明确的限制,可以直接使用默认的构造函数
弊端:
如果有某个成员必须有值,set方法无法保证

复杂类型/集合类型注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<bean id="accountService3" class="com.xushui.service.Impl.AccountServiceImpl3">
<property name="myStrs">
<array>
<value>aaa</value>
<value>bbb</value>
<value>ccc</value>
</array>
</property>
<property name="myList">
<list>
<value>aaa</value>
<value>bbb</value>
<value>ccc</value>
</list>
</property>
<property name="mySet">
<set>
<value>aaa</value>
<value>aaa</value>
<value>aaa</value>
</set>
</property>

<property name="myMap">
<map>
<entry key="keyA" value="aaa"></entry>
<entry key="keyB"><value>bbb</value></entry>
<entry key="keyC" value="ccc"></entry>
</map>
</property>
<property name="myProps">
<props>
<prop key="AAA">bbb</prop>
<prop key="CCC">Ddd</prop>
</props>
</property>
</bean>
  • 用于给List结构集合注入标签:
    • listarrayset
  • 用于给Map结构集合注入标签:
    • mapprops
  • 结构相同标签可以互换


# Spring

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×