Spring Framework01-Spring起步

1、Spring前言

讲Spring以前先写段代码,体会一下Java建立对象的方式,这块你理解了对后面有好处!html

一、原始时代

直接new建立对象,代码以下:java

//User.java
package com.ty.bean;

public class User {
    private String username;
    private String password;

   /**
 	* 省略有参无参构造,getter/setter方法
 	*/
}
//UserDao.java
public interface UserDao {
    void getUser(String username,String password);
}

//UserDao的实现类UserDaoImpl.java
public class UserDaoImpl implements UserDao {
    @Override
    public void getUser(String username, String password) {
        System.out.println("用户名:"+username+"\t密码:"+password);
    }
}
//UserService.java
public interface UserService {
    void getUser(String username,String password);
}

//UserService的实现类UserServiceImpl.java
public class UserServiceImpl implements UserService {
    private UserDao userDao= new UserDaoImpl();
    @Override
    public void getUser(String username, String password) {
        userDao.getUser(username,password);
    }
}

正常来说这里还须要写一个UserController,可是咱们只是测试,因此就写一个TestUser类git

public class TestUser {
    @Test
    public void test(){
        UserService userService=new UserServiceImpl();
        userService.getUser("jack","root");
    }
}

这是以前学习常常写的方式用来完成某种功能,service层调用dao层;UserService的实现类调用UserDao的实现类。想象一下:若是咱们业务更改了,增长了一个UserService的实现类BUserServiceImpl,使用的时候代码就要变成这样程序员

public class TestUser {
    @Test
    public void test(){
        //UserService userService=new UserServiceImpl();
        UserService userService=new BUserServiceImpl();
        userService.getUser("jack","root");
    }
}

这就是所谓的耦合,调用的时候要修改代码,即直接new , 显然不符合面向对象的设计原则---------开闭原则github

二、过渡时代

工厂方式,再原来的代码修改一下web

先建立一个BeanFactory.java文件spring

//建立工厂类,BeanFactory.java
public class BeanFactory {
    public static UserService getUser(){
        return new UserServiceImpl();
    }
}

这样使用的时候就变成这样数据库

@Test
    public void test(){
        UserService userService= BeanFactory.getUser();
        userService.getUser("jack","root");
    }

这样虽然使用的时候没有耦合了,可是BeanFactory里面仍是有代码耦合的即:return UserService,那怎么办呢?能够利用反射建立对象编程

public class BeanFactory {
    public static UserService getUser(){
        UserService userService=null;
        try {
            Class<?> clazz = Class.forName("com.ty.service.UserServiceImpl");
            userService= (UserService) clazz.newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return userService;
    }

这样比直接new好多了,减小了耦合,可是还有些不妥,获取类限定名的时候仍是须要改来改去。即:安全

Class<?> clazz = Class.forName("com.ty.service.UserServiceImpl");

下面咱们能够用properties属性配置文件存储文件限定名,代码以下:

userService=com.ty.service.UserServiceImpl

#这就实现把具体的类限定名和代码相分离,将来只须要修改此配置文件便可
public class BeanFactory {
    private static UserService userService;
    //建立Properties对象来加载properties属性配置文件
    private static Properties environment = new Properties();
    private static InputStream resource;

    static {

        //加载applicationContext.properties配置文件
        resource = BeanFactory.class.getResourceAsStream("/applicationContext.properties");
        try {
            environment.load(resource);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                resource.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static UserService getUserService() throws Exception {

        Class<?> clazz = Class.forName(environment.getProperty("userService"));
        userService = (UserService) clazz.newInstance();
        return userService;
    }
}

这样将来增长了service代码,只须要修改properties配置文件便可,例如

public class BUserServiceImpl implements UserService {
    private UserDao userDao= new UserDaoImpl();
    @Override
    public void getUser(String username, String password) {
        System.out.println("B");
        userDao.getUser(username,password);
    }
}
#配置文件就改为这样
userService=com.ty.service.BUserServiceImpl
//测试文件
  @Test
  public void test2() throws Exception {
      UserService userService= BeanFactory.getUserService();
      userService.getUser("jack","root");
  }

咱们顺便用这种方式把UserService调用UserDao进行改进

public static UserDao getUserDao() {
        UserDao userDao=null;
        Class<?> clazz = null;
        try {
            clazz = Class.forName(environment.getProperty("userDao"));
            userDao = (UserDao) clazz.newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }

        return userDao;
    }

public class UserServiceImpl implements UserService {
    private UserDao userDao= BeanFactory.getUserDao();
    @Override
    public void getUser(String username, String password) {
        userDao.getUser(username,password);
    }
}
userDao=com.ty.dao.UserDaoImpl
@Test
    public void test2() throws Exception {
        UserService userService= BeanFactory.getUserService();
        userService.getUser("jack","root");
    }

工厂方法基本设计完成了,可是还有点小问题,那就是每次都须要在BeanFactory工厂类写一个与其对应的对象建立工厂方法,好麻烦,并且这些方法长得基本差很少,能不能设计一个通用的工厂方法呢,那必须能啊,上代码

public class BeanFactory {
    private static Properties environment = new Properties();
    private static InputStream resource;

    static {

        //加载applicationContext.properties配置文件
        resource = BeanFactory.class.getResourceAsStream("/applicationContext.properties");
        try {
            environment.load(resource);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                resource.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     *
     * @param key 配置文件对应的userService,userDao
     * @return
     */
   public static Object getBean(String key){
       Object returnedObject=null;
       try {
           Class<?> clazz = Class.forName(environment.getProperty(key));
           returnedObject=clazz.newInstance();
       } catch (ClassNotFoundException e) {
           e.printStackTrace();
       } catch (IllegalAccessException e) {
           e.printStackTrace();
       } catch (InstantiationException e) {
           e.printStackTrace();
       }
       return returnedObject;
   }
}
userService=com.ty.service.UserServiceImpl

userDao=com.ty.dao.UserDaoImpl
public class UserServiceImpl implements UserService {
    private UserDao userDao= (UserDao) BeanFactory.getBean("userDao");
    @Override
    public void getUser(String username, String password) {
        userDao.getUser(username,password);
    }
}

 @Test
    public void test2() throws Exception {
        UserService userService= (UserService) BeanFactory.getBean("userService");
        userService.getUser("jack","root");
    }
}

这样一个通用工厂就完成了,这种方式你还须要先本身提供工厂类和方法,咱们若是用Spring的话,工厂类不用咱们手动实现,Spring提供了工厂

ioc容器建立对象,这种方式咱们后面会详细讲解

public class UserServiceImpl implements UserService {
    private UserDao userDao;

    public UserDao getUserDao() {
        return userDao;
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void getUser(String username, String password) {
        userDao.getUser(username,password);
    }
}
<?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">
    <bean id="userService" class="com.ty.service.UserServiceImpl">
        <property name="userDao" ref="userDao"></property>
    </bean>

    <bean id="userDao" class="com.ty.dao.UserDaoImpl"></bean>
</beans>
@Test
    public void test3(){
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) context.getBean("userService");
        userService.getUser("jack","root");
    }

这样咱们就把建立对象的方式的一个小Demo写完了,只就是Spring框架的核心之一:ioc,咱们先简单介绍一下Spring

2、spring介绍

咱们常说的 Spring 其实是指 Spring Framework,而 Spring Framework 只是 Spring 家族中的一个分支而已。那么 Spring 家族都有哪些东西呢? 具体能够查看官网:https://spring.io/projects

官网地址:https://spring.io/projects/spring-framework

压缩包下载地址:https://repo.spring.io/release/org/springframework/spring/

源码地址:https://github.com/spring-projects/spring-framework

英文官网可能看不懂,github上还有一个中文网址,只不过不是最新版本的,不过没太大影响

https://gitee.com/fl_982659186/spring-docs

Spring 是为了解决企业级应用开发的复杂性而建立的。在 Spring 以前,有一个重量级的工具叫作 EJB,使用 Spring 可让 Java Bean 之间进行有效的解耦,而这个操做以前只有 EJB 才能完成,EJB 过于臃肿,使用不多。Spring 不只仅局限于服务端的开发,在测试性和松耦合方面都有很好的表现。 官网有一个简短的Spring介绍,说明Spring产生的缘由

Spring makes programming Java quicker, easier, and safer for everybody. Spring’s focus on speed, simplicity, and productivity has made it the world's most popular Java framework.

总结就是Spring能为咱们快速、轻松和安全的进行Java编程
详细:https://spring.io/why-spring

官网上还有一个Spring的概述

https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/overview.html#overview

中文翻译:https://gitee.com/fl_982659186/spring-docs/blob/master/pages/overview/overview.md

核心解释

spring是一个一站式开源框架。

spring是为了简化企业开发而生的,使得开发变得更加优雅和简洁。

spring是一个IOCAOP的容器框架。

​ IOC:控制反转

​ AOP:面向切面编程

​ 容器:包含并管理应用对象的生命周期,就比如用桶装水同样,spring就是桶,而对象就是水

3、Spring 特色

​ 一、Spring经过DI、AOP和消除样板式代码来简化企业级Java开发

​ 二、Spring框架以外还存在一个构建在核心框架之上的庞大生态圈,它将Spring扩展到不一样的领域,如Web服 务、REST、移动开发以及NoSQL

​ 三、低侵入式设计,代码的污染极低

​ 四、独立于各类应用服务器,基于Spring框架的应用,能够真正实现Write Once,Run Anywhere的承诺

​ 五、Spring的IoC容器下降了业务对象替换的复杂性,提升了组件之间的解耦

​ 六、Spring的AOP支持容许将一些通用任务如安全、事务、日志等进行集中式处理,从而提供了更好的复用

​ 七、Spring的ORM和DAO提供了与第三方持久层框架的的良好整合,并简化了底层的数据库访问

​ 八、Spring的高度开放性,并不强制应用彻底依赖于Spring,开发者可自由选用Spring框架的部分或所有

如何简化开发

​ 基于POJO的轻量级和最小侵入性编程

​ 经过依赖注入和面向接口实现松耦合

​ 基于切面和惯例进行声明式编程

​ 经过切面和模板减小样板式代码

4、Spring 框架结构

模块解释:
Test:Spring的单元测试模块
Core Container:核心容器模块,主要组件是 BeanFactory是否是好熟悉,上面我们实现了一个简易版的BeanFactory
AOP+Aspects:面向切面编程模块
Instrumentation:提供了class instrumentation支持和类加载器的实现来在特定的应用服务器上使用,几乎不用
Messaging:包括一系列的用来映射消息到方法的注解,几乎不用
Data Access/Integration:数据的获取/整合模块,包括了JDBC,ORM,OXM,JMS和事务模块
Web:提供面向web整合特性

5、ioc初识

ioc(Inversion of Control ):控制反转,这是一个思想,简单一句话就是建立对象的控制权利交给Spring的容器 咱们稍微详细展开一下

  • 谁控制谁
  • 控制什么
  • 什么是反转
  • 哪些方面被反转

先看一下官网如何介绍的

IoC is also known as dependency injection (DI). It is a process whereby objects define their dependencies (that is, the other objects they work with) only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse (hence the name, Inversion of Control) of the bean itself controlling the instantiation or location of its dependencies by using direct construction of classes or a mechanism such as the Service Locator pattern
 
 IOC与你们熟知的依赖注入同理,. 这是一个经过依赖注入对象的过程 也就是说,它们所使用的对象,是经过构造函数参数,工厂方法的参数或这是从工厂方法的构造函数或返回值的对象实例设置的属性,而后容器在建立bean时注入这些须要的依赖。 这个过程相对普通建立对象的过程是反向的(所以称之为IoC),bean自己经过直接构造类来控制依赖关系的实例化或位置,或提供诸如服务定位器模式之类的机制。

可能稍微晦涩,用现实的事物举个例子。咱们要找女盆友,传统的方式是你本身按照标准亲自一步步筛选,而后就须要打听她们的兴趣爱好、qq号、电话号、微信号等等,想办法认识她们再继续下一步事情。控制反转的方式的话就是有一个婚介所,这个媒介所就是一个容器,里面有不少女生的资料,你把你的标准告诉工做人员,而后剩下的步骤由他们去操做,最后给你就返回一个符合你标准的女盆友,你就和她谈恋爱、结婚就好了。

说到这咱们把上面演示过的demo画图演示一下

咱们总结一下上面说的4个小问题

  • 谁控制谁:之前咱们都是手动建立即new所需的对象,程序员本身来控制对象的建立过程。而有了IOC容器以后,就会变成由IOC容器来控制对象
  • 控制什么:实现过程当中所需的对象以及所需依赖的对象
  • 什么是反转:之前咱们本身new依赖对象就是正转,而有了反转以后,依赖的对象由ioc容器建立后注入到对象中,由主动建立变成了被动接受,这是反转
  • 哪些方面被反转:依赖的对象

DI

DI ( Dependency Injection ):依赖注入

不少人把IOC和DI说成一个东西,笼统来讲的话是没有问题的,可是本质上仍是有所区别的,但愿你们可以严谨一点,IOC和DI是从不一样的角度描述的同一件事,IOC是从容器的角度描述,而DI是从应用程序的角度来描述,也能够这样说,IOC是设计思想,而DI是具体的实现方式

上面的控制反转概念实际上是模糊的 (可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系) ,因此后来就有了 “依赖注入” ,这个就很好理解,很直截了当就能说明IOC容器用来维护对象的依赖关系。

6、其它

咱们稍微说点其它的,额外说两个点

  1. 一个就是咱们面向对象设计的过程尽可能达到低耦合,在面向对象设计的软件系统中,底层的实现都是由N个对象组成的,全部的对象经过彼此的合做,最终实现系统的业务逻辑。

​ 须要注意的是,在这样的组合关系中,一旦某一个对象出现了问题,那么其余对象确定回有所影响,这就是耦合性过高的缘故,可是对象的耦合关系是没法避免的,也是必要的。随着应用程序愈来愈庞大,对象的耦合关系可能愈来愈复杂,常常须要多重依赖关系,所以,不管是架构师仍是程序员,在面临这样的场景的时候,都须要减小这些对象的耦合性。

​ 耦合的关系不只仅是对象与对象之间,也会出如今软件系统的各个模块之间,是咱们须要重点解决的问题。而为了解决对象之间的耦合度太高的问题,咱们就能够经过IOC来实现对象之间的解耦,spring框架就是IOC理论最最普遍的应用。

从上图中能够看到,当引入了第三方的容器以后,几个对象之间就没有了耦合关系,所有对象都交由容器来控制,这个容器就至关于粘合剂,将系统的对象粘合在一块儿发挥做用。

  1. 任何一个语言或者任何一个框架想要立于不败之地,那么很重要的就是它的生态。Java语言如今为何那么火爆,就是由于20多年的历练,出现了不少技术,这些技术被普遍使用,若是出现新的编程语言想替代Java,短期内没法替代。Spring框架也同样,发展到今天,咱们都离不开它了,如今不多的公司不用Spring

这些都是Spring家族的产品,而咱们如今学的包括不久我更新的SpringMVC都是属于Spring Framework的范畴

因此咱们说Spring不只仅是框架,它主要是一个生态,几乎在Spring中能找到JavaEE各类解决方案,Spring框架更新的还很频繁!

ps:Spring全系列我后面打算都更新一遍,组件多,我会一点点更新,你们也是须要一点点积累!也欢迎你们多多提建议!

相关文章
相关标签/搜索