@
1,Spring 的概述
在学习 SSM 框架中, 我建议初学者最好先学 Spring 框架, 其次 mybatis 接着 springMVC, 先学 mybatis 当然也是可以的, 今天我们就以绝对优雅的姿态闯进 Spring 世界, 系好安全带, 准备好了吗, 出发了哦!!! 咳咳.... 平时开发接触最多的估计就是 IoC 容器, 它可以装载 bean(所谓的 bean 也就是我们 java 中的类, 当然也包括 servicedao 里面), 有了这个机制, 我们就不用在每次使用这个类的时候为它初始化, 很少看到键字 new. 另外 spring 的 aop, 事务管理等等都是我们经常用到的, 可见 Spring 的尤为重要的作用 Spring 的核心是控制反转 (IoC) 和面向切面(AOP)
1.1 什么是 Spring
肯定有熊 dei 会问 SE/EE 开发的一站式框架所谓的一站式是什么意思,(哼, 人类, 我早就猜到你会问了)
所谓一站式框架指的是有 EE 开发的每一层解决方案.
web 层 :SpringMVC
Service 层 :Spring 的 Bean 管理, Spring 声明式事务
DAO 层 :Spring 的 Jdbc 模板, Spring 的 ORM 模块
1.2 为什么学习 Spring
俗话说, 人狠话不多(兄嘚看图)
1.3Spring 的版本
Spring3.x,Spring4.x 和 Spring5.x
1.4Spring 的体系结构
正所谓, 人狠话不多(兄嘚看图)
2,Spring 的入门(IoC)
2.1 什么 IoC
一说起 IoC 我就想起了武哥对 IoC 的理解的几个例子, 可谓通俗易懂, 非常适合刚入门 Spring 的兄嘚! 有兴趣的可以去了解了解武哥, 武哥博客: https://blog.csdn.net/eson_15
IoC(Inverse of Control): 控制反转, 也可以称为依赖倒置.
控制反转: 将对象的创建权反转给(交给)Spring.
所谓依赖, 从程序的角度看, 就是比如 A 要调用 B 的方法, 那么 A 就依赖于 B, 反正 A 要用到 B, 则 A 依
赖于 B. 所谓倒置, 你必须理解如果不倒置, 会怎么着, 因为 A 必须要有 B, 才可以调用 B, 如果不倒
置, 意思就是 A 主动获取 B 的实例: B b = new B(), 这就是最简单的获取 B 实例的方法(当然还有各种
设计模式可以帮助你去获得 B 的实例, 比如工厂, Locator 等等), 然后你就可以调用 b 对象了. 所
以, 不倒置, 意味着 A 要主动获取 B, 才能使用 B; 到了这里, 就应该明白了倒置的意思了. 倒置就是
A 要调用 B 的话, A 并不需要主动获取 B, 而是由其它人自动将 B 送上门来.
2.2 通俗理解 IoC
形象的举例就是:
通常情况下, 假如你有一天在家里口渴了, 要喝水, 那么你可以到你小区的小卖部去, 告诉他们, 你需要一瓶水, 然后小卖部给你一瓶水! 这本来没有太大问题, 关键是如果小卖部很远, 那么你必须知道: 从你家如何到小卖部; 小卖部里是否有你需要的水; 你还要考虑是否开着车去; 等等等等, 也许有太多的问题要考虑了. 也就是说, 为了一瓶水, 你还可能需要依赖于车等等这些交通工具或别的工具, 问题是不是变得复杂了? 那么如何解决这个问题呢?
解决这个问题的方法很简单: 小卖部提供送货上门服务, 凡是小卖部的会员, 你只要告知小卖部你需要什么, 小卖部将主动把货物给你送上门来! 这样一来, 你只需要做两件事情, 你就可以活得更加轻松自在:
第一: 向小卖部注册为会员.
第二: 告诉小卖部你需要什么.
这和 Spring 的做法很类似! Spring 就是小卖部, 你就是 A 对象, 水就是 B 对象
第一: 在 Spring 中声明一个类: A
第二: 告诉 Spring,A 需要 B
假设 A 是 UserAction 类, 而 B 是 UserService 类
- <bean id="userService" class="org.leadfar.service.UserService"/>
- <bean id="documentService" class="org.leadfar.service.DocumentService"/>
- <bean id="orgService" class="org.leadfar.service.OrgService"/>
- <bean id="userAction" class="org.leadfar.web.UserAction">
- <property name="userService" ref="userService"/>
- </bean>
在 Spring 这个商店 (工厂) 中, 有很多对象 / 服务: userService,documentService,orgService, 也有很多会员: userAction 等等, 声明 userAction 需要 userService 即可, Spring 将通过你给它提供的通道主动把 userService 送上门来, 因此 UserAction 的代码示例类似如下所示:
- package org.leadfar.Web;
- public class UserAction{
- private UserService userService;
- public String login(){
- userService.valifyUser(xxx);
- }
- public void setUserService(UserService userService){
- this.userService = userService;
- }
- }
在这段代码里面, 你无需自己创建 UserService 对象 (Spring 作为背后无形的手, 把 UserService 对象通过你定义的 setUserService() 方法把它主动送给了你, 这就叫依赖注入!), 当然咯, 我们也可以使用注解来注入. Spring 依赖注入的实现技术是: 动态代理
2.3 下载 Spring 的开发包以及解压说明
官网下载: http://spring.io/
什么? 不会下载? what???
好吧, 已打包好了 QAQ:https://pan.baidu.com/s/18wyE-5SRWcCu12iPOX56pg
什么? 没有网盘? what???
有事请烧香谢谢...
解压之后, 文件说明:
docs :Spring 的开发规范和 API
libs :Spring 的开发的 jar 和源码
schema :Spring 的配置文件的约束
2.4 创建 Web 项目, 引入 jar 包
2.5 创建普通接口和实现类
创建普通接口, 定义一个 eat 方法
- package com.gx.sping;
- public interface IUserDao {
- public void eat();
- }
创建普通实现类
- package com.gx.sping;
- public class UserDaoimpl implements IUserDao {
- @Override
- public void eat() {
- // TODO Auto-generated method stub
- System.out.println(用户 eat 了 ");
- }
- }
2.6Spring 的 IoC 底层实现原理
创建普通接口和类出现的问题:
如果底层的实现切换了, 需要修改源代码, 能不能不修改程序源代码对程序进行扩展?
重点来了, 要想不改变源码, Spring 的 IoC 就能实现! 如下图: Spring 的 IoC 底层实现
2.7 将实现类交给 Spring 管理
1, 在 classpath 下 (也就是 src ) 创建一个 xml 文件
2, 文件名最好统一叫 applicationContext.xml
3, 其 xml 文件的内容头为 schema 约束
4, 约束文件位置在 spring 的解压路径下 lspring-framework-4.2.4.RELEASE\docs\spring-framework-reference\html\xsd-configuration.htm
5, 不要求 xml 文件的内容头能够背出来, 但要了解的是你要知道它是怎么来的
6,xml 文件的内容头添加后, 将实现类交给 Spring 管理
applicationContext.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"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd">
- <!-- 实现类 UserDaoimpl 交给 Spring 管理 -->
- <bean id="IuserDao" class="com.gx.Ioc.UserDaoimpl"></bean>
- </beans>
2.8 编写测试类
package com.gx.IoC; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpingDemo1 { @Test public void demo11() { // 面向接口传统方式 UserDaoimpl userdao = new UserDaoimpl(); userdao.eat(); } //Spring 的 bean 管理方式 @Test public void demo22() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); IUserDao userdao = (IUserDao) applicationContext.getBean("IuserDao"); userdao.eat(); } }
兄嘚, 如果测试不成功最好看看二者是否对应!!!
兄 dei, 到这里, Spring 的入门 (IoC) 算是入门了, 是不是觉得很有成就感啊?
拉倒吧! 我都不好意思说了.(兄 dei, 我错了, 是我飘了, 呀呀呀, 兄 dei 别打脸鸭 QAQ)
但是我依旧是阻止不了你骄傲的心.
那就顶我, 让我感受感受你的骄傲! 哈哈哈 QAQ
2.9 IoC 和 DI
IoC 不是什么技术, 而是一种设计思想, IoC 能指导我们如何设计出松耦合, 更优良的程序. 传统应用程序都是由我们在类内部主动创建依赖对象, 从而导致类与类之间高耦合, 难于测试; 有了 IoC 容器后, 把创建和查找依赖对象的控制权交给了 Spring 容器, 由容器进行注入组合对象, 所以对象与对象之间是松散耦合, 这样利于功能复用, 更重要的是使得程序的整个体系结构变得非常灵活.
IoC: 控制反转, 将对象的创建权反转给了 Spring.
DI: 依赖注入, 前提必须有 IoC 的环境, Spring 管理这个类的时候将类的依赖的属性注入 (设置) 进来. 比如说下面讲到的 Spring 的属性注入其实就是典型的 DI
所谓继承: is a
Class A{ } Class B extends A{ }
所谓依赖:
Class A{ } Class B{ public void xxx(A a){ } }
所谓聚合: has a
3,Spring 的工厂类
3.1Spring 工厂类的结构
3.2 老版本的工厂类: BeanFactory
BeanFactory: 调用 getBean 的时候, 才会生成类的实例.
3.3 新版本的工厂类: ApplicationContext
ApplicationContext: 加载配置文件的时候, 就会将 Spring 管理的类都实例化.
ApplicationContext 有两个实现类
1,ClassPathXmlApplicationContext : 加载类路径下的配置文件
2,FileSystemXmlApplicationContext : 加载文件系统下的配置文件
4,Spring 的配置
4.1XML 的提示配置(Schema 的配置)
在 xml 文件中要使用各种标签来给 spring 进行配置, 博主我这佩奇脑袋怎么可能记住 spring 中所有的标签呢, 不怕不怕, 博主我会配置 xml 的提示配置 QAQ, 会了这一招就算兄 dei 你是乔治脑袋也不用担心(再说了我看兄 dei 各各英俊潇洒, 玉树临风, 聪明绝顶... 咳咳, 暴露了暴露了)
4.2Bean 的相关的配置(<bean > 标签的 id 和 name 的配置)
id : 使用了约束中的唯一约束. 里面不能出现特殊字符的. 上面提及到了要与 getbean 参数值对应
name : 没有使用约束中的唯一约束(理论上可以出现重复的, 但是实际开发不能出现的). 里面可以出现特殊字符.
4.3Bean 的生命周期的配置(了解)
init-method :Bean 被初始化的时候执行的方法
destroy-method :Bean 被销毁的时候执行的方法(Bean 是单例创建, 工厂关闭)
4.4Bean 的作用范围的配置(重点)
scope 属性 : Bean 的作用范围
scope 属性值 如下 (主要用的是前二者)
singleton : scope 属性的默认值 ,Spring 会采用 单例 模式创建这个对象.
prototype : 多例 模式.(Struts2 和 Spring 整合一定会用到)
request : 应用在 Web 项目中, Spring 创建这个类以后, 将这个类存入到 request 范围中.
session : 应用在 Web 项目中, Spring 创建这个类以后, 将这个类存入到 session 范围中.
globalsession : 应用在 Web 项目中, 必须在 porlet 环境下使用. 但是如果没有这种环境, 相对于 session.
5,Spring 的属性注入
首先, 创建几个普通类
com.gx.spring.demo.Car public class Car { private String name; private Double price; public Car(String name, Double price) { super(); this.name = name; this.price = price; } @Override public String toString() { return "Car [name=" + name + ", price=" + price + "]"; } } com.gx.spring.demo.Car2 /** * 用作 set 方法的属性注入类 */ public class Car2 { private String name; private Double price; public void setName(String name) { this.name = name; } public void setPrice(Double price) { this.price = price; } @Override public String toString() { return "Car2 [name=" + name + ", price=" + price + "]"; } } com.gx.spring.demo.Person /** * 用作 set 方法的对象属性注入类 */ public class Person { private String name; private Car2 car2; public void setName(String name) { this.name = name; } public void setCar2(Car2 car2) { this.car2 = car2; } @Override public String toString() { return "Employee [name=" + name + ", car2=" + car2 + "]"; } }
5.1 构造方法的方式的属性注入
构造方法的属性注入
constructor-arg 标签用于配置构造方法的属性注入
name : 参数的名称
value: 设置普通数据
ref: 引用数据, 一般是另一个 bean id 值
当然了, 构造方法的方式的属性注入也支持对象属性的注入, 标签中对应属性也是 ref
如果只有一个有参数的构造方法并且参数类型与注入的 bean 类型匹配, 那就会注入到该构造方法中
applicationContext.xml 中配置:
<!-- 构造方法的方式 --> <bean id="car" class="com.gx.spring.demo.Car"> <constructor-arg name="name" value="玛莎拉蒂"/> <constructor-arg name="price" value="800000"/> </bean>
测试方法:
/** * 构造方法方式的普通属性注入方法 */ public void demo1(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); Car car = (Car) applicationContext.getBean("car"); System.out.println(car); }
5.2Set 方法的方式的属性注入[开发常用]
Set 方法的普通属性注入
property 标签用于配置 Set 方法的属性注入
name : 参数的名称
value: 设置普通数据
ref : 引用数据, 一般是另一个 bean id 值
applicationContext.xml 中配置:
<!-- set 方法的方式 --> <bean id="car2" class="com.gx.spring.demo.Car2"> <property name="name" value="法拉利黄金跑车"/> <property name="price" value="10000000"/> </bean>
测试方法:
@Test /** * set 方法方式的属性注入 */ public void demo2(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); Car2 car2 = (Car2) applicationContext.getBean("car2"); System.out.println(car2); }
Set 方法设置对象类型的属性
applicationContext.xml 中配置:
<!-- set 方法注入对象类型的属性 --> <bean id="Person" class="com.gx.spring.demo.Person"> <!-- value: 设置普通类型的值, ref: 设置其他的类的 id 或 name--> <property name="name" value="涛哥"/> <property name="car2" ref="car2"/> </bean>
测试方法:
@Test /** * set 方法注入对象类型 */ public void demo3(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); Person person= (Person) applicationContext.getBean("Person"); System.out.println(person); }
5.3 注解的方式属性注入[开发常用]
@Component(作用在类上通用: 组件)
@Component("userService")相当于 < bean id="userService" class="...">
衍生:
@Controller Web 层
@Service 业务层
@Repository 持久层
这三个注解是为了让标注类本身的用途清晰
属性注入的注解 (可以没有 set 方法)
普通类型属性:@Value
对象类型属性: @Resource ( 对应 bean 中的 id )= @Autowired(类型) + @Qualifier(名称)
5.3.1 注解的理解
额, 初学框架, 注解二字可能对于大部分熊 dei 来说, 太过于陌生, 注解其实就是在一个类, 方法, 属性上, 使用 @注解名称, 就比如是我们最熟悉的接实现口中的方法默认会有一个 @Override (熊 dei, 这样理解能接受?)
5.3.2 注解的 jar 包导入
Spring3.x 注解的 jar 包
在 Spring3.x 的版本中, 使用注解开发, 只需要 spring 核心基础四包外 + log4j 包 + 1 个依赖包 即可
Spring4.x 注解的 jar 包
然而在 Spring4.x 版本之后则需在 再添加一个要引入 spring-aop 的 jar 包 , 因为, spring4.x 版本中一些注解的依赖方法封装在 spring-aop 的 jar 包中
5.3.3 引入注解的 context 约束
所谓约束就是就是就是约束啦(搽汗), 其中 bean 约束是最基本的约束!(下图也可以看出)
引入约束:(引入 context 的约束):
<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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> </beans>
5.3.4 编写相关的类
public interface UserDao { public void sayHello(); } public class UserDaoImpl implements UserDao { @Override public void sayHello() { System.out.println("Hello Spring..."); } }
5.3.5 配置注解扫描
Spring 的注解开发: 组件扫描(不使用类上注解的时候可以不用组件扫描)
使用注解方式, 需要开启组件扫描 < context:component-scan base-package = 直接包名或者包名. 类名 />, 当然开发中一般都是 base-package = 包名 , 毕竟这样可以扫描整个包, 方便开发
Spring 的注解开发: 组件扫描(类上注解: 可以直接使用属性注入的注解)
<!-- Spring 的注解开发: 组件扫描(类上注解: 可以直接使用属性注入的注解) --> <context:component-scan base-package="com.gx.spring.demo1" />
5.3.6 在相关的类上添加注解
1, 使用类上注解方式 @Component(value="userDao"), 相当于 < bean id="userDao class="com.gx. 类名 "></bean>
当然 value 属性名可以省去直接 @Component("userDao"), 当然 @Component("value 值任意写建议取的要有意义")
2, 注解方式可以没有 set 方法
@Component(value="userDao") // 相当于配置了 < bean id="userDao" class="com.gx.UserDaoImpl"></bean> public class UserDaoImpl implements UserDao { @Override public void sayHello() { System.out.println("Hello Spring Annotation..."); } }
5.3.7 编写测试类
@Test public void demo3() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); UserDao userDao = (UserDao) applicationContext.getBean("userDao"); userDao.sayHello(); }
5.4P 名称空间的属性注入(Spring2.5 以后)
通过引入 p 名称空间完成属性的注入:
写法:
普通属性 p: 属性名 ="值"
对象属性 p: 属性名 - ref="值"
P 名称空间的约束引入
使用 p 名称空间
5.5 SpEL 的属性注入(Spring3.0 以后)
SpEL:Spring Expression Language,Spring 的表达式语言.
语法: #{SpEL}
5.6 集合类型属性注入(了解)
集合类型属性配置:
集合的注入都是在 < property > 标签中添加子标签
数组:<array>
List:<list> Set:<set>
Map:<map> ,map 存放 k/v 键值对, 使用
描述
Properties:<props> <prop key=""></prop>
普通数据:<value>
引用数据:<ref>
<!-- Spring 的集合属性的注入 ============================ --> <!-- 注入数组类型 --> <bean id="collectionBean" class="com.gx.spring.demo.CollectionBean"> <!-- 数组类型 --> <property name="arrs"> <list> <value > 天才</value> <value > 王二</value> <value > 冠希</value> </list> </property> <!-- 注入 list 集合 --> <property name="list"> <list> <value > 李兵</value> <value > 赵如何</value> <value > 邓凤</value> </list> </property> <!-- 注入 set 集合 --> <property name="set"> <set> <value>aaa</value> <value>bbb</value> <value>ccc</value> </set> </property> <!-- 注入 Map 集合 --> <property name="map"> <map> <entry key="aaa" value="111"/> <entry key="bbb" value="222"/> <entry key="ccc" value="333"/> </map> </property> </bean>
6,Spring 的分模块开发的配置
分模块配置:
在加载配置文件的时候, 加载多个, 没错, 这就是传说中的骚操作, 堪称开挂级别的操作(当然, 这是可以的不是开挂)
在一个配置文件中引入多个配置文件, 简直优秀!!!
到这里, 恭喜恭喜, 各位熊 dei 以优雅的仪式感闯进 Spring 世界, 对 Spring 的 IoC 以及 DI 有了一定了解了, 是不是也很期待 Spring 的 Aop 呐, 毕竟 Spring 的核心是控制反转 (IoC) 和面向切面(AOP).
[Spring 框架学习二] Spring 的 AOP 通俗理解以及 AOP 的入门开发 (哎哎, 别打.. 别打.. 别打脸....)
如果本文对你有一点点帮助, 就请点个赞呗, 手留余香, 谢谢!
最后, 欢迎各位关注我的公众号, 一起探讨技术, 向往技术, 追求技术...
来源: http://www.tuicool.com/articles/NBfuIbf