为了简化开发,整合了现有的框架技术,是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器(框架)。有了它之后不需要再new对象了,所有的对象都可以托管到spring中,需要用的时候通过spring来取即可
官网:https://spring.io/
官方下载地址:https://repo.spring.io/libs-release-local/org/springframework/spring/
GitHub地址:https://github.com/spring-projects
基础maven依赖:
1.2 优点org.springframework spring-webmvc 5.3.16
开源免费的框架,容器轻量级,非侵入式(项目中引入它不会影响到原本的代码运行)控制反转(IOC):依赖注入(DI)面向切面编程(AOP)支持事务,整合了其他框架的支持 1.3 七大模块
2、控制反转(IOC) 2.1 概念控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做**依赖注入(Dependency Injection,简称DI**),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
2.2 实践- 创建新项目,然后按照传统步骤编写dao层和Service层
Dao接口
public interface UserDao {
public void getUser();
}
Dao实现
public class UserDaoImpl implements UserDao{
@Override
public void getUser() {
System.out.println("获取用户数据");
}
}
Service接口
public interface UserService {
public void getUser();
}
Service实现
public class UserServiceImpl implements UserService{
private UserDao userDao = new UserDaoImpl();
@Override
public void getUser() {
userDao.getUser();
}
}
Test
public class IocTest {
@Test
public void test(){
UserService userService = new UserServiceImpl();
userService.getUser();
}
}
- 如果UserDao有两个实现类,而用户想要换一种UserDao的实现方式,按照传统思路,此时就需要修改UserService的实现类了
UserDaoMysqlImpl
public class UserDaoMysqlImpl implements UserDao{
@Override
public void getUser() {
System.out.println("Mysql获取用户数据");
}
}
修改UserServiceImpl
public class UserServiceImpl implements UserService{
private UserDao userDao = new UserDaoMysqlImpl();
@Override
public void getUser() {
userDao.getUser();
}
}
如上所述,客户需求一旦发生变化,服务端的代码就需要进行相应的修改,假设这种需求非常大,这种方式就根本不适用了,因为它的耦合性太高了,牵一发而动全身,因此就需要引入控制反转的概念,将控制权移交到客户手上。
改造代码
根据上面的代码不难发现,修改前后的UserServiceImpl其实变化并不大,只是参数userDao的实现方式发生了变化而已,那么我们可以考虑在需要用到userDao的地方,不去实现它,而是留出一个接口,利用set方法,让调用UserService的人来决定他到底要使用哪种userDao的实现方式。
public class UserServiceImpl implements UserService{
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
public class IocTest {
@Test
public void test(){
UserServiceImpl userService = new UserServiceImpl();
userService.setUserDao(new UserDaoImpl());
userService.getUser();
userService.setUserDao(new UserDaoMysqlImpl());
userService.getUser();
}
}
改变的意义
改进后的代码可能目前看起来也没比之前的方式简单多少,但是实际上已经发生了根本性的变化,以前所有的东西都是由程序自己去控制创建(我要用什么,我就自己创建什么),而现在是由调用者自行控制创建对象,把主动权交给调用者,程序不用去管怎么创建,它只负责提供一个接口。
这种思想,从本质上解决了问题,我们程序员不再去管理对象的创建了,更多的去关注对象的实现,耦合性大大降低,这就是IOC的原型。
流程变化:
原本:调用者告诉开发者我要用这个账号登录,开发者根据调用者需求修改程序代码,把原来写进程序里的账号改成新的。
现在:开发者告诉调用者,我给你弄了个登录界面,你要用哪个账号自己把账号输进去就好了,不要再来找我了。
控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认 为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系 完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为 所谓控制反转就是:获得依赖对象的方式反转了。
Class A中用到了Class B的对象b,一般情况下,需要在A的代码中显式的new一个B的对象。
采用依赖注入技术之后,A的代码只需要定义一个私有的B对象,不需要直接new来获得这个对象,而是通过相关的容器控制程序来将B对象在外部new出来并注入到A类里的引用中。而具体获取的方法、对象被获取时的状态由配置文件(如XML)来指定。
IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解, 新版本的Spring也可以零配置实现IoC。 Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用 时再从Ioc容器中取出需要的对象。
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为 一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。 控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现 控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
3、HelloSpring编写hello实体类
public class Hello {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("hello,"+name);
}
}
编写spring配置文件
测试
public class MyTest {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Hello hello = context.getBean("hello",Hello.class);
hello.show();
}
}
思考
Hello时谁创建的
Hello由Spring创建
Hello中的name属性是怎么设置的
由Spring容器创建Hello对象时设置的
由此可见,Spring容器就是控制反转中的第三方,当对象在Spring中注册了bean时,该对象就相当于托管给了Spring,对象由Spring创建,程序本身不创建对象,而变成被动的接收对象,而所谓的依赖注入本质上就是利用set方法来注入的。
4、IOC案例修改由HelloSpring我们初步了解到,Spring可以作为第三方帮助我们new对象,那么我们就可以对控制反转中的案例进行如下改造:
新增Spring的配置文件,将UserDao的两种实现类和Service的实现类在Spring中注册
修改测试代码
public class IocTest {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserServiceImpl userService = context.getBean("serviceImpl",UserServiceImpl.class);
userService.getUser();
}
}
经过如上改造我们就彻底不需要对程序做出改动了,要实现不同的操作只需要在xml配置文件中进行相应的修改即可,IOC到这里就可简单理解为:对象都有Spring来创建,管理,装配。
5、Spring创建对象方式 5.1 无参构造当实体类有无参构造方式时,Spring可以直接通过bean来创建,在创建对象的同时也可以通过标签给它的属性赋值,前提是有该属性的set方法,因为依赖注入的本质就是通过set来进行注入的。
package com.yirui.dao;
public class User {
private String name;
public User(){
System.out.println("User的无参构造");
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name:"+name);
}
}
5.2 有参构造
package com.yirui.dao;
public class UserT {
private String name;
public UserT(String name){
System.out.println("User的有参构造,name:"+name);
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name:"+name);
}
}
通过index注入构造参数
通过name注入构造参数
通过type注入构造参数(不推荐,因为只有当每个参数的类型都不一致的时候才能使用,而且必须指定全限定类名)
5.3 测试
public class DiTest {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user = context.getBean("user",User.class);
user.show();
UserT userT = context.getBean("userT",UserT.class);
userT.show();
}
}
观察结果,不难发现当ClassPathXmlApplicationContext被创建时,在Spring中注册的bean会被一次性全部实例化
6、Spring配置和依赖注入(DI) 6.1 配置介绍别名
alias 设置别名 , 为bean设置别名 , 可以设置多个别名
bean标签
import
团队的合作通过import来实现,可以将多个spring配置文件整合到一起
依赖:一指bean对象的创建依赖于spring容器,二指bean对象创建时的依赖资源注入:指bean对象创建时的依赖资源,由spring容器来设置和装配
构造器注入和简单的常量注入已经在前面阐述了,这里主要描述set注入的一些复杂情况
- 新建Address和Student对象
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
public class Student {
private String name;
private Address address;
private String[] books;
private List hobby;
private Map card;
private Set games;
private String wife;
private Properties info;
@Override
public String toString() {
return "Student{" +
"name='" + name + ''' +
", address=" + address +
", books=" + Arrays.toString(books) +
", hobby=" + hobby +
", card=" + card +
", games=" + games +
", wife='" + wife + ''' +
", info=" + info +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public String[] getBooks() {
return books;
}
public void setBooks(String[] books) {
this.books = books;
}
public List getHobby() {
return hobby;
}
public void setHobby(List hobby) {
this.hobby = hobby;
}
public Map getCard() {
return card;
}
public void setCard(Map card) {
this.card = card;
}
public Set getGames() {
return games;
}
public void setGames(Set games) {
this.games = games;
}
public String getWife() {
return wife;
}
public void setWife(String wife) {
this.wife = wife;
}
public Properties getInfo() {
return info;
}
public void setInfo(Properties info) {
this.info = info;
}
}
return card;
}
public void setCard(Map card) {
this.card = card;
}
public Set getGames() {
return games;
}
public void setGames(Set games) {
this.games = games;
}
public String getWife() {
return wife;
}
public void setWife(String wife) {
this.wife = wife;
}
public Properties getInfo() {
return info;
}
public void setInfo(Properties info) {
this.info = info;
}
}



