01_Spring_快速入门

一. Spring概述

1.1 什么是Spring

Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建。简单来说,Spring是一个分层的JavaSE/EE (一栈式) 轻量级开源框架。

  • JEE分层
    • 表现层(页面数据显示、页面跳转调度)jsp/servlet
    • 业务层(业务处理和功能逻辑、事务控制)-service
    • 持久层(数据存取和封装、和数据库打交道)dao
  • 一站式

    Spring提供了JavaEE各层的解决方案:
        表现层:Spring MVC,持久层:JdbcTemplate、ORM框架整合,业务层:IoC、AOP、事务控制。
  • 轻量级:Spring的出现取代了EJB的臃肿、低效、繁琐复杂、脱离现实。

1.2 Spring的核心

IoC(Inverse of Control 反转控制): 将对象创建权利交给Spring工厂进行管理。

AOP(Aspect Oriented Programming 面向切面编程),基于动态代理的功能增强方式。

1.3 Spring的优点

  • 方便解耦,简化开发
    • Spring就是一个大工厂,可以将所有对象创建和依赖关系维护,交给Spring管理
  • AOP编程的支持
    • Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
  • 声明式事务的支持
    • 只需要通过配置就可以完成对事务的管理,而无需手动编程
  • 方便程序的测试
    • Spring对Junit4支持,可以通过注解方便的测试Spring程序
  • 方便集成各种优秀框架
    • Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts2、Hibernate、MyBatis、Quartz等)的直接支持
  • 降低JavaEE API的使用难度
    • Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低

关于框架的特性,我们也会俗称Spring为开发架构的粘合剂。

二. Spring框架的快速入门

2.1 搭建环境

  1. 下载开发包,导jar包
    
    下载网址:http://repo.spring.io/libs-release-local/org/springframework/spring/

    开发包目录结构:
        docs : api文档和开发规范
        libs : 开发需要的jar包(源码)
        schema : 开发需要的约束schema
    -----------------------------------------------------------------------------

    1. 新建web项目
    2. Spring项目的核心容器最基本的jar包(4个):
        1. Beans  2. Core  3. Context  4.Expression Language
    3. Spring框架需要的日志包(2个,依赖库中找)
        1. apache commons-logging(JCL)日志框架  
        2. log4j的日志实现
        3. log4j的配置文件 log4j.properties
    
    

2.2 业务代码

模拟用户保存。

01_Spring_快速入门_第1张图片
img01.png

    传统写法 :

    UserServiceImpl : 
        // 模拟用户注册
        public void save() {
            // 传统方式
            System.out.println("业务层........UserServiceImpl用户注册...");
            UserDAO dao = new UserDAOImpl();
            userDAO.save();
        }


    UserDAO : 
        //模拟用户注册
        public void save() {
            System.out.println("持久层.......UserDAOImpl用户注册...");
        }

    web层(这里是测试test):
        @Test
        public void test() {
            UserService service = new UserServiceImpl();
            service.save();
        }

    传统的方式代码过于耦合,上层代码过于依赖下层代码,如果业务有改动,要改变DAO的实现类时,需要改动代码:
    UserDAO userDAO = new UserDaoImpl();因此需要采取方式进行解耦合。

    解决方案:采用IoC(Inverse of Control)控制反转的思想进行解耦合.

    简单的说就是引入工厂(第三者),将原来在程序中手动创建管理的依赖的UserDAO对象,交给工厂来创建管理。
    在Spring框架中,这个工厂就是Spring中的工厂,因此,也可以说,将创建管理UserDAO对象的控制权被反转给了Spring框架了。

    -----------------------------------------------------------------------------

    概念:IoC中文翻译为控制反转,指以前程序自己创建对象,现在将创建对象的控制权交给了第三方(Spring)了。

    IoC底层实现:工厂(设计模式)+反射(机制) + 配置文件(xml)。

    IoC是一种思想,控制反转的思想、解耦合的思想。
    Spring的IoC是该思想的一种实现。因此Spring容器也通常称之为IoC容器。

01_Spring_快速入门_第2张图片
img02.png

2.3 IoC控制反转的实现

传统是自己创建对象,现在将创建对象交给Spring容器,我们获取就行了.

这种方式,即使更换实现类,也只需要修改配置文件中的实现类的路径。

2.3.1 Spring的核心配置文件编写applicationContext.xml

1. 习惯上: 在src建立applicationContext.xml (位置:src目录或者 WEB-INF目录)

2. 引入xml的头部信息bean schema约束,可以参考规范文档中的的xsd-config.html
    
    
    
    
            
        
        
            
                
    

3.  配置实现类的映射bean
    

2.3.2 通过Spring的工厂获取Bean完成相关操作

  1. 读取配置文件,获取Spring的Bean工厂

  2. 通过Spring的Bean工厂获取对象

     // Spring解耦合,使用配置文件:创建工厂+反射创建UserDAO对象
     // 加载配置文件,获取工厂对象
     ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
     // 实例化对象
     UserDAO dao = (UserDAO) applicationContext.getBean("userDAO");
     userDAO.save();
    

2.4 DI依赖注入的实现

DI:Dependency Injection 依赖注入,在Spring框架负责创建Bean对象时,动态的将依赖对象注入到Bean组件(简单的说,可以将另外一个bean对象动态的注入到另外一个bean中。)

耦合代码变成依赖注入代码的方法:

01_Spring_快速入门_第3张图片
img03.png

即:Spring创建了Service、DAO对象,在配置中将DAO传入Servcie,那么Service对象就包含了DAO对象的引用。

在Service对象创建调用时,也会产生一个DAO对象,并通过Service内提供的setter方法将该对象的引用注入进去。

applicationContext.xml核心配置文件:
    
    
    
    
    
        
        
     


Service层:
    声明注入的对象,提供setter方法
        private UserDAO userDAO;
        
        //提供setter方法Spring方法进行动态注入userDAO
        public void setUserDAO(UserDAO userDAO) {
            this.userDAO = userDAO;
        }
        
        @Override
        // 模拟用户注册
        public void save() {
            //Spring框架创建了userDAO对象并注入进来,因此不会是空
            userDAO.save();
        }

web层:
    //加载配置,获取Spring工厂(容器)
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    //获取bean对象
    UserService userService = (UserService) applicationContext.getBean("userService");
    //调用业务逻辑
    userService.save();

01_Spring_快速入门_第4张图片
img04.png

小结:

IoC:是一个大的思想,将某件事情(对象创建权利等)的控制前交给第三方管理。
DI:还是IoC的思想,将对象依赖注入权利交给第三方管理。

2.5 Spring的工厂

ApplicationContext用来加载Spring框架的配置文件,来构建Spring对象的工厂对象,它被称为Spring框架的上下文,
也被称为Spring的容器。

ApplicationContext是BeanFactory(Bean工厂,Bean就是一个java对象)的一个子接口。

为什么不直接使用顶层接口对象来操作呢?
因为ApplicationContext是对BeanFactory的扩展,它的功能更强。
    * 国际化处理
    * 事件传递
    * Bean的自动装配
    * 不同应用层的Context的实现

2.5.1 获取Spring工厂的两种方式

src:开发的时候,工程里的一个目录,存放的文件,会在编译发布后,放入classes下

01_Spring_快速入门_第5张图片
img05.png
  • 如果applicationContext.xml 在 src下, ClassPathXmlApplication读取
  • 如果applicationContext.xml 在WEB-INF下,FileSystemXmlApplicationContext读取

三. IoC容器装配Bean_基于XML配置方式

3.1 实例化Bean的四种方式(了解)

  • 无参构造/带参构造方式
  • 静态工厂方式
  • 实例工厂方式
  • FactoryBean方式

    1. 无参构造/带参构造方式:
    public class Bean1 {
        //无参构造
        public Bean1() {
            System.out.println("Bean1被创建了............无参构造");
        }
    }

    public class Bean2 {
    
        private Integer id;
        private String name;
        
        //提供带参构造
        public Bean2(Integer id, String name) {
            System.out.println("Bean2被创建了..........带参构造");
            this.id = id;
            this.name = name;
        }
    }


    配置文件applicationContext.xml:
        
        
        
        
        
            
            
        
    
img06.png

2. 静态工厂方式 : 通过静态工厂的静态方法创建bean对象

要被反转控制的Bean类:
    public class Bean3 {
        public Bean3() {
                System.out.println("Bean3被创建了.....静态工厂方式");
            }
        }
静态工厂类提供静态方法:
    public class StaticBean3Factory {
    
        public static Bean3 getBean3() {
            //在实例化时,可以进行其它操作,例如逻辑判断等
            return new Bean3();
        }
    }   

配置文件:
    
    

3. 实例化工厂方式:

要被反转控制的Bean类:
    public class Bean4 {
        public Bean4() {
            System.out.println("Bean4被创建了.......实例化工厂方式");
        }
    }

实例化工厂类提供创建Bean的方法:
    public class Bean4Factory {
        // 实例化工厂方式创建Bean对象
        public Bean4 initBean() {
            // 可以在new Bean4之前进行很多的逻辑判断
            // 例如判断new哪一个对象
            return new Bean4();
        }
    }

配置文件:
    
    
    
    

4. FactoryBean方式:
    实现接口,实现getObject方法,返回要创建的Bean类.Spring检查到实现了FactoryBean接口时,会在实例化
    FactoryBean时自动调用getObject方法获取Bean对象。

    public class FactoryBean5 implements FactoryBean {
    
        @Override
        public Bean5 getObject() throws Exception {
            return new Bean5();
        }


    
    

小结:
四种方式:
第一种最常用,第二、三、一些框架初始化的时候用的多、第四种spring底层用的多。


    
    
    
    
    
    
        
        
    
    
    
    
    
    
    
    
    
    
    

    ---------------------------------------------------------------------------

    BeanFactory和FactoryBean的区别?
 
    BeanFactory(ApplicationContext):
        是一个工厂(其实是构建了一个spring上下文的环境,容器),用来管理和获取很多Bean对象.
    FactoryBean:
        是一个Bean生成工具,是用来获取一种类型对象的Bean,它是构造Bean实例的一种方式。

3.2 Bean的作用域

01_Spring_快速入门_第6张图片
img07.png

项目开发中通常会使用:singleton 单例、 prototype多例 。

Singleton: 在一个spring容器中,对象只有一个实例。(默认值)

Prototype: 在一个spring容器中,存在多个实例,每次getBean 返回一个新的实例。

单例是默认值,如果需要单例对象,则不需要配置scope。
01_Spring_快速入门_第7张图片
img08.png

3.3 在xml配置Bean的初始化和销毁方法(了解)

  • 说明:Spring初始化bean或销毁bean时,有时需要作一些处理工作,因此spring可以在创建和拆卸bean的时候调用bean的两个生命周期方法
  • init-method -- 当bean被载入到容器的时候调用init-method属性指定的方法
  • destroy-method -- 当bean从容器中删除的时候调用destroy-method属性指定的方法

    想查看destroy-method的效果,有如下条件
        1. 单例(singleton)的bean才可以手动销毁。
        2. web容器中会自动调用,但是main函数或测试用例需要手动调用(需要使用ClassPathXmlApplicationContext的close()方法)


    public class LifeCycleBean {
        public LifeCycleBean() {
            System.out.println("实例化................");
        }
        
        public void init() {
            System.out.println("初始化...............");
        }
        
        public void destroy() {
            System.out.println("销毁................");
        }
    }

    配置文件:
    
    
    

测试:

01_Spring_快速入门_第8张图片
img09.png

3.4 Bean的属性依赖注入

3.4.1 属性依赖注入的三种方式

  • 构造器参数注入
  • setter方法属性注入
  • 接口注入(了解)

Spring 框架规范中通过配置文件配置的方式,只支持构造器参数注入和setter方法属性注入,不支持接口注入 !

3.4.2 构造器参数注入constructor-arg

当Spring初始化Car时,如果发现有constructor-arg标签,会自动调用带参构造,而不会使用无参构造。

constructor-arg的属性:

  • name : 根据属性名称定位属性
  • index : 根据索引定位属性
  • type : 根据属性的类型定位属性
  • ================================
  • value : 简单值,数字,字符串,其他对象等等
  • ref : 复杂的对象(就是指bean),值:bean的引用名字

    Bean类:

    public class Car {
        private Integer id;
        private String name;
        private Double price;
    
        // 必须提供带参构造,用于属性注入
        public Car(Integer id, String name, Double price) {
            super();
            this.id = id;
            this.name = name;
            this.price = price;
        }
    
        @Override
        public String toString() {
            return "Car [id=" + id + ", name=" + name + ", price=" + price + "]";
        }
    }


    配置文件applicationContext.xml:

    
    
        
        
        
     

    测试:
    @Test
    public void test() {
        // 加载配置文件,获取Spring工厂
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        
        //获取Bean对象
        Car car = (Car) applicationContext.getBean("car");
        System.out.println(car);
    }

    结果:
        Car [id=1, name=宝马, price=999999.0]

补充:

1. 定位属性的标签,可以混用
    即:

2. 自标签的属性赋值问题,可以使用子标签的value,效果和value属性一样
    如:
    
        宝马
    

3.4.3.setter方法属性注入 property【推荐】

使用的默认的构造器(new Bean()),但必须提供属性的setter方法。

Spring创建出Bean对象,再通过setter方法属性注入值。

两步:在类中加入setter方法,在配置文件中使用property

    
    Bean类:

    public class Person {
    
        private Integer pid;
        private String name;
        private Car car;
        
        //必须提供setter方法,用于属性注入
        public void setPid(Integer pid) {
            this.pid = pid;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setCar(Car car) {
            this.car = car;
        }
    
        @Override
        public String toString() {
            return "Person [pid=" + pid + ", name=" + name + ", car=" + car + "]";
        }
    }

    配置文件applicationContext.xml:

        
        
            
            
            
        

        
        
            
            
            
         

    测试:

        @Test
        public void test() {
            // 加载配置文件,获取Spring工厂
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
            
            //获取Bean对象
            //将创建对象与属性注入的权利交给Spring,我们直接从容器拿到这个对象就可以了(已经包含了属性的值)
            Person person = (Person) applicationContext.getBean("person");
            System.out.println(person);
        }

    结果:
        Person [pid=1, name=jack, car=Car [id=1, name=宝马, price=999999.0]]

setter方法属性注入的属性:

property : 用于setter方式进行属性注入的标签
name : 与Bean类中的setter方法对应.例如setCar --- name就是car.
value : 简单值.
ref : 复杂值。要注入的Bean对象的id/name名字

3.4.4.p名称空间的使用(了解)

什么是名称空间? 
作用:Schema区分同名元素。(有点类似于java的包)

xmlns="http://www.springframework.org/schema/beans"
Xmlns没有前缀是默认的名称空间.

p名称空间的作用是为了简化setter方法属性依赖注入配置的,它不是真正的名称空间。

它的使用方法:
    p:<属性名>="" 引入常量值
    p:<属性名>-ref =""引入其他Bean对象


具体使用步骤:
    1. 引入p名称空间
    

    2. 将 子元素 简化为 元素的属性 (以上面的person为例)
    
    

    结果:
    Person [pid=2, name=coco, car=Car [id=1, name=宝马, price=999999.0]]

    配置时不需要 子元素,简化了配置 .

3.4.5 spEL表达式的使用 –会使用

spEL(Spring Expression Language)是一种表达式语言,它是spring3.x版本的新特性。

作用:支持在运行时操作和查询对象,其语法类似统一的EL语言,但是SpEL提供了额外的功能,功能更强大。

img11.png

语法: #{…} , 引用另一个Bean 、属性、 方法

  • #{bean_id}引用Bean(具体对象)
  • #{bean_id.属性}引用Bean的属性
  • #{bean_id.方法(参数)}引用Bean的方法

    例1:

    //修改了p:pid的值为#{2*3},修改p:name为#{car.name},car是创建car对象的id。
        car.name相当于调用了它的getName()方法,因此Car的Bean类中必须提供getName方法。
    

    测试结果:
    Person [pid=6, name=宝马, car=Car [id=1, name=宝马, price=999999.0]]    


    例2:
    //修改了p:pid的值为#{car.id},修改p:name为#{car.name},car是创建car对象的id。
        car.id相当于调用了它的getId()方法,因此Car的Bean类中必须提供getId方法。
    

    测试结果:
    Person [pid=1, name=BMW, car=Car [id=1, name=宝马, price=999999.0]]

3.4.6.集合类型属性注入 (了解-使用时查看即可)

作用:主要用于框架整合配置。

Spring为集合提供了对应的标签:
     注入 list元素
     注入 set元素
     注入 map元素
     注入 properties 元素 (hashtable类的子类,是特殊的map,key和value都是String )

    
    Bean类:提供四种集合,List,Map,Set,Properties,使用setter方式进行属性注入:

    public class CollectionBean {
    
        private List list;
        private Set set;
        private Map map;
        private Properties properties;
    
        // 提供setter方式,供Spring框架属性注入
        public void setList(List list) {
            this.list = list;
        }
    
        public void setSet(Set set) {
            this.set = set;
        }
    
        public void setMap(Map map) {
            this.map = map;
        }
    
        public void setProperties(Properties properties) {
            this.properties = properties;
        }
    
        @Override
        public String toString() {
            return "CollectionBean [list=" + list + ", set=" + set + ", map=" + map + ", properties=" + properties + "]";
        }
    }
    ======================================================================================

    applicationContext.xml :

        value注入简单类型。   ref注入复杂类型。

        
        
            
                1
                2
                3
                4
             
        
        
        
            
                aa
                bb
                cc
                dd
            
        
        
        
            
                
                
                
                
            
        
        
        
            
                林心如
                李诗诗
            
        
    

    测试:
        // 加载配置文件,获取Spring工厂
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        
        //获取Bean对象
        CollectionBean collectionBean = (CollectionBean) applicationContext.getBean("collectionBean");
        System.out.println(collectionBean);

    结果:
    CollectionBean [list=[1, 2, 3, 4], set=[aa, bb, cc, dd], map={罗贯中=三国演义, 施耐庵=水浒传, 曹雪芹=红楼梦, 吴承恩=西游记}, properties={霍建华=林心如, 吴奇隆=李诗诗}]

3.5.配置文件分开管理(了解)

在开发中,所有的bean不可能只写在一个配置文件中,如果在src的目录下又多创建了一个配置文件,现在是两个核心的配置文件,那么加载这两个配置文件的方式有两种:

  • 主配置文件中包含其他的配置文件:【推荐】

      在applicationContext.xml中:
      
    
  • 工厂创建的时候直接加载多个配置文件:

    ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
                "applicationContext.xml","applicationContext2.xml");

你可能感兴趣的:(01_Spring_快速入门)