Spring学习笔记

Spring,轻量级JavaEE解决方案,是众多优秀设计模式的整合,学习笔记

[TOC]

Spring框架

引言

什么是Spring

轻量级JavaEE解决方案,是众多优秀设计模式的整合

设计模式(公式)

解决一些特定问题的经典代码

Spring框架中主要的设计模式

工厂
代理
模板

工厂模式简介

  • 作用:生产对象
  • 耦合:代码之间具有强关联性
  • 好处:解耦合
  • 工厂设计思路:建立一个工厂类,有工厂类负责对象的创建

Spring开发步骤(通过工厂设计模式创建对象)

搭建环境

引入jar包

引入Spring配置文件

放置位置随意,命名随意,默认 ApplicationContext.xml

核心API

ApplicationContext(工厂)

重量级资源,内存多,功能强,一个应用只创建一个,线程安全

接口的实现类

  • ClassPathXmlApplicationContext(非Web环境)

  • WebXmlApplicationContext(Web环境)

Srping工厂的开发步骤

创建类

配置文件

1
2
<bean id="userService" class="fancylab.hibiscidai.service.UserServiceImpl">
</bean>

通过Spring的工厂类创建对象

1
2
3
4
5
6
7
8
9
10
@Test
//通过Spring工厂创建UserServiceImpl对象
public void testSpring() {
//创建工厂
ApplicationContext ac = new ClassPathXmlApplicationContext("/applicationContext.xml");
//利用工厂创建对象
UserService us = (UserService)ac.getBean("userService");

us.register();
}

Spring工厂创建对象的原理

  1. 读取配置文件
  2. 获得全限定名
  3. 通过反射获取对象
1
2
Class clazz = Class.forName("全限定名");
clazz.newInstance();//创建对象

注入(Injection)

通过Spring的配置文件为对象的成员变量赋值

Set注入

原理

  1. 通过Spring工厂创建对象
  2. 调用兑现给的set方法通过配置文件映射进行设值

配置文件中 < property name="id" > 属性要和类的成员变量名对应,并一定要在类中书写setter和getter方法

JDK类型成员变量

现有 User
类结构如下

1
2
3
4
5
6
7
8
9
10
11
12
13
public class User {
private Integer id;
private String username;
private String password;
private int[] tels;
private List<String> l = new ArrayList<String>();
private Set<String> s = new HashSet<String>();
private Map<Integer, String> m = new HashMap<Integer, String>();
private Properties p = new Properties(); // 特殊的Map 键值都是String类型
//setter与getter方法
//toString方法
//无参有参构造方法
}

8种基本类型及String类型

在配置文件中声明如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<bean id="user" class="org.fancylab.hibiscidai.entity.User">
<!-- 为成员变量赋值 -->
<property name="id">
<value>20</value>
</property>

<property name="username">
<value>小黑</value>
</property>

<property name="password">
<value>123456</value>
</property>
</bean>

数组类型的成员变量

1
2
3
4
5
6
7
8
9
<!-- 数组成员变量赋值 -->
<property name="tels">
<list>
<value>1</value>
<value>2</value>
<value>3</value>
<value>4</value>
</list>
</property>

List类型的成员变量

1
2
3
4
5
6
7
8
9
<!-- List成员变量赋值 -->
<property name="l">
<list>
<value>xiaohei</value>
<value>xiaohua</value>
<value>xiaobai</value>
<value>xiaowb</value>
</list>
</property>

Set类型的成员变量

1
2
3
4
5
6
7
8
<!-- Set成员变量赋值 -->
<property name="s">
<set>
<value>xiao1</value>
<value>xiao2</value>
<value>xiao3</value>
</set>
</property>

Map类型的成员变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- Map成员变量赋值 -->
<property name="m">
<map>
<entry>
<key>
<value>1</value>
</key>
<value>zkf1</value>
</entry>
<entry>
<key>
<value>2</value>
</key>
<value>zkf2</value>
</entry>
<entry>
<key>
<value>3</value>
</key>
<value>zkf3</value>
</entry>
</map>
</property>

Properties类型的成员变量

1
2
3
4
5
6
7
<!-- Propertis类型的成员变量赋值 -->
<property name="p">
<props>
<prop key="1">value1</prop>
<prop key="2">value2</prop>
</props>
</property>

自建(自定义)类型注入成员变量

对于三层架构

1
2
3
4
dao
daoImpl
service
serviceImpl

service 层引用 dao 层作为成员变量

书写创建对象的类
1
2
3
4
5
public class UserServiceImpl implements UserService {
private UserDao userDao;
//setter和getter方法
//实现接口方法
}
在Spring配置中配置对应的 < bean > 标签
1
2
3
4
5
6
7
8
9
10
11
<!-- 配置UserDAOIMpl的Bean标签 -->
<bean id="userDao" class="org.fancylab.hibiscidai.dao.UserDao">
</bean>

<!-- 配置该类的信息 UserServiceImpl -->
<bean id="userService" class="org.fancylab.hibiscidai.service.impl.UserServiceImpl">
<!-- 成员变量定义引入 -->
<property name="userDao">
<ref local="userDao" />
</property>
</bean>

在目标实体类中定义成员变量,并且在配置文件中进行引入

自动注入
1
2
3
4
5
6
7
<!-- 自动注入,在spring配置文件中查询该成员变量指向的实际类型(通过类型) -->
<bean id="userService" class="org.fancylab.hibiscidai.service.impl.UserServiceImpl" autowire="byType">
</bean>

<!-- 通过成员变量的名字,匹配spring配置文件中的bean标签的id值 -->
<bean id="userService" class="org.fancylab.hibiscidai.service.impl.UserServiceImpl" autowire="byName">
</bean>

构造方法注入(了解)

spring通过构造方法完成对于成员变量的赋值

前提:提供有参构造

开发步骤

以类 Account 为例

1
2
3
4
5
6
7
8
9
10
public class Account {
private Integer id;
private String name;
private String password;
private Integer age;

//set和get方法
//构造方法
//toString
}

提供有参构造

1
2
3
4
5
public Account(Integer id, Integer age) {
super();
this.id = id;
this.age = age;
}

spring的配置文件配置

1
2
3
4
5
6
7
8
9
<bean id="account" class="org.fancylab.hibiscidai.entity.Account">
<!-- 为成员变量进行构造方法注入 -->
<constructor-arg type="Integer">
<value>123456</value>
</constructor-arg>
<constructor-arg type="Integer">
<value>18</value>
</constructor-arg>
</bean>

有参构造中的成员变量的个数与顺序和构造注入时保持一致

构造方法可以重载

  • 如果构造方法中,参数的个数不同时,通过 < contructor-arg > 标签的数量进行区分

  • 如果构造方法的个数相同时,通过 < Contructor-arg type="" > 通过参数类型区分

IOC与DI概念

IOC (Inversion of Control) 反转控制

  • 控制
    对于成员变量的控制权

  • 反转
    把对于成员变量赋值的控制权从代码中转移到配置文件中完成

例如 UserServiceImpl

  • 使用前声明方式
1
2
3
public class UserServiceImpl {
private UserDao ud = new UserDaoImpl();
}
  • 使用后声明方式
1
2
3
4
public class UserServiceImpl {
private UserDao ud;
//set和get方法
}

在配置文件中进行set注入,把成员变量的赋值控制权从代码中转移到配置文件中

DI (dependency injection) 依赖注入

当一个类型需要使用另一个类型时,就意味着他依赖另一个类型,那么就可以把另一个类型作为成员变量通过Spring的配置文件进行赋值。

解耦合

构造方法注入例中已说明

FactoryBean(接口)

有些简单对象可以通过 new 的方式直接创建
复杂对象不能通过new对象创建,例如 SqlSessionFactory

作用:在Spring的工厂中创建复杂对象

开发步骤

该复杂类实现 FactoryBean 接口

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
public class ConnectionFactory implements FactoryBean {
// 作用:用于书写创建复杂对象的代码,并把创建的复杂对象作为方法的返回值返回
@Override
public Object getObject() throws Exception {
// 创建连接对象
// 加载驱动
Class.forName("oracle.jdbc.OracleDriver");
// 获取连接
Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "hr", "hr");
return connection;
}

// 返回创建的复杂对象的类对象
@Override
public Class getObjectType() {
return Connection.class;
}

// 控制复杂对象的创建次数,根据对象的特点进行返回
// true:Spring工厂只会创建一次该复杂对象
// false:每一次调用Spring工厂 Spring都会创建新的复杂对象
@Override
public boolean isSingleton() {
return false;
}
}

Spring配置文件中配置

1
2
3
<!-- 配置创建复杂对象 -->
<bean id="conn" class="org.fancylab.hibiscidai.factory.ConnectionFactory">
</bean>

获取对象

1
2
3
4
// 创建工厂
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
// 创建Connection对象 注意:直接返回 所要创建的复杂对象
Connection conn = (Connection) ac.getBean("conn");

通过bean标签的id值,直接创建对象时,拿到的是复杂对象
如果想要拿到原始对象,则需要在Spring创建对象时加上 &

1
2
ConnectionFactory cf = (ConnectionFactory) ac.getBean("&conn");
System.out.println(cf);

控制简单对象的创建次数

1
<bean id="" class="" scope="singleton|prototype" />

singleton 默认,简单对象只会被创建一次。
prototype 简单对象每次使用时都会创建新的对象。

Spring工厂的高级特性

工厂创建对象的生命周期

工厂被创建,对象被创建
工厂被关闭,对象被销毁

生命周期方法

init-method

对象中任意定义一个初始化方法·。Spring会在这个对象创建之后,自动调用初始化方法的功能。

destroy-method

对象中任意定义一个销毁方法。Spring会在这个对销毁之前调用销毁方法。

Account类中声明方法

1
2
3
4
5
6
7
8
9
10
<bean id="account" class="org.fancylab.hibiscidai.entity.Account"
init-method="init" destroy-method="destory">
<!-- 为成员变量进行构造方法注入 -->
<constructor-arg type="Integer">
<value>123456</value>
</constructor-arg>
<constructor-arg type="Integer">
<value>18</value>
</constructor-arg>
</bean>

配置信息参数化

作用:把Spring配置文件中,需要修改的jdbc相关参数,提取到一个小的专一化的配置文件中

好处:利于后续的维护

开发步骤

准备小配置文件

创建文件 jdbc.properties 文件要以 .properties 结尾

1
2
3
4
driverclassname=oracle.jdbc.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:xe
name=hr
password=hr

与spring配置文件整合

1
2
3
4
5
6
7
8
9
10
11
12
<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-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
">

<!-- 使用Context标签 -->
<!-- 通过Context标签读取对应的配置文件 -->
<context:property-placeholder location="/jdbc.properties" />

其中,引入context标签

1
xmlns:context="http://www.springframework.org/schema/context"

1
2
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd

通过占位符替换Spring配置文件中的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- 配置创建复杂对象 -->
<bean id="conn" class="org.fancylab.hibiscidai.factory.ConnectionFactory">
<!-- Set注入 -->
<property name="driverclassname">
<value>${driverclassname}</value>
</property>
<property name="url">
<value>${url}</value>
</property>
<property name="name">
<value>${name}</value>
</property>
<property name="password">
<value>${password}</value>
</property>
</bean>

AOP(Aspect Oriented Program) | 面向切面编程

静态代理设计模式(Proxy)

概念

  • 原始对象(目标对象)

只做核心功能

  • 原始方法

原始对象中的方法,只做核心功能

  • 额外功能

事务 日志 性能

  • 代理对象

原始对象+额外功能+与原始对象实现相同的接口

  • 好处

利于维护

其他

学习源码HibisciDai/TestSpring

文章作者: HibisciDai
文章链接: http://hibiscidai.com/2018/05/08/2018-5-8-Spring学习笔记/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 HibisciDai
好用、实惠、稳定的梯子,点击这里