Java Web框架篇:Spring

  • Post author:
  • Post category:java




Spring



一、什么是Spring?


pring是J2EE应用程序框架,是轻量级的IoC和AOP的容器框架,主要是针对javaBean的生命周期进行管理的轻量级容器,可以单独使用,也可以和Struts框架,ibatis框架等组合使用。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为J2EE应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式)轻量级开源框架。



特点

(1)轻量级:轻量级是针对重量级容器(EJB)来说的,Spring的核心包就不到1M大小,而使用Spring的核心包所需的资源也很小,所以可以在小型设备中使用。

(2)非入侵式:Spring目标是一个非入侵式的服务框架。原因是所有框架都是提供大量的功能供用户去使用,从而简化开发时间和成本,但由于大量的使用了框架的API,使应用程序和框架发生了大量的依赖性,无法从框架中独立出来,更加无法使程序组件在其他程序中使用。

(3)容器:Spring提供了容器功能,容器可以管理对象的生命周期、对象与对象间的关系、我们可以通过编写XML来设置对象关系和初始值,这样容器在启动之后,所有的对象都直接可以使用,不用编写任何编码来产生对象。Spring有两种不同的容器:Bean工厂以及应用上下文



优势

  1. spring是最大的工厂
  2. spring负责业务逻辑组件的框架和生成, 并管理业务逻辑组件的生命周期
  3. spring可以生产所有实例, 从控制器、 业务逻辑组件、 持久层组件



什么是耦合?

  1. 耦合是指程序间的

    依赖关系

    • 它包括 :
    • 类之间的依赖、方法之间的依赖

    • 解耦

    • 降低程序之间的依赖关系
    • 实际开发中:
    • 编译器不依赖、运行时才依赖

      .
  • 对象之间的耦合度过高将会出现牵一发而动全身的情况,降低耦合度是软件工程中的目标之一
  • IOC的目标是降低各个对象之间的耦合度
  • 各个对象之间的耦合关系
  • 在这里插入图片描述



模块划分

Spring的核心是控制反转(IoC)和面向切面(AOP)。



1.核心模块Core Container)


Spring的核心模块实现了IOC的功能,它将类与类之间的依赖代码中脱离,用配置的方法进行依模块赖描述,由IOC容器负责类的创建管理获取等。BeanFactory

Context模块构建与核心模块之上,扩展了BeanFactory的功能,包括国际化,资源加载,邮件服务,任务调度等多项功能。ApplicationContext是Context模块的核心接口

表达式语言(Expression Langguage)是统一表达式语言EL的一个扩展,支持设置和获取对象属性,调用对象方法,操作数组,集合等。使用它可以很方便地通过表达式Spring IOC容器进行交互




2.AOP模块

Spring AOP模块提供了满足AOP Alliance规范的实现,还整合了AspectJ这种AOP语言级的框架。通过AOP能降低耦合。




3.数据访问集成模块(Data Access/Integration )

数据访问集成模块
JDBC 提供一个JBDC模板,使用模板能消除冗长的JDBC编码和必须的事务控制,而且能享受到Spring管理事务的好处。
ORM 提供与流行的“对象-关系”映射框架的无缝集成,包括hibernate、JPA、MyBatis等。而且可以使用Spring事务管理,无需额外控制事务。
OXM 提供了一个对Object/XML映射实现,将Java对象映射成XML数据,或者将XML数据映射成java对象,Object/XML映射实现包括JAXB、Castor、XMLBeans和XStream
JMS 用于JMS(Java Messaging Service),提供一套 “消息生产者、消息消费者”模板用于更加简单的使用JMS,JMS用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。
事务管理 该模块用于Spring管理事务,只要是Spring管理对象都能得到Spring管理事务的好处,无需在代码中进行事务控制了,而且支持编程和声明性的事务管理。



4、Web模块

  • 建立在ApplicationContext模块之上
  • 提供了Web应用的功能(文件上传、FreeMarker等。)
  • Spring可以整合Struts2等MVC框架.
  • Spring自己提供了MVC框架Spring MVC。



5、测试模块

Spring可以用非容器依赖的编程方式进行几乎所有的测试工作,支持JUnit和TestNG等测试框架。



二、初识Spring的IoC容器



1.概念

IoC(控制反转:Inverse of Control)是Spring容器的核心,但是IoC这个概念却比较晦涩,让人不太容易望文生义



2.IoC控制反转和DI依赖注入

传统程序 IOC
需要主动new一个对象,才能调用方法 将创建的对象交给IOC容器,由IOC容器帮忙创建以及注入依赖对象,程序被动的接受IoC容器创建的对象(控制反转)
直接操作 IoC确实不够开门见山,所以提出了DI(依赖注入:Dependency Injection)的概念,


DI(依赖注入:Dependency Injection)

:即让第三方来实现注入,以移除我们类与需要使用的类之间的依赖关系。

目的:IoC是目的,DI是手段,创建对象的过程往往意味着依赖的注入。我们为了实现IoC,让生成对象的方式由传统方式(new)反转过来,需要创建相关对象时由IoC容器帮我们注入(DI)。

简单的说,就是我们类里需要另一个类,只需要让Spring帮我们创建 ,这叫做控制反转;然后Spring帮我们将需要的对象设置到我们的类中,这叫做依赖注入。



IoC和DI的区别?

IoC:控制反转,指将对象的创建权,反转到spring容器。

DI:依赖注入,指在创建对象的过程中,将对象依赖的属性通过配置进行注入。DI的实现依赖于IoC,是IOC中的一种具体实现,先有控制反转才有依赖注入



属性注入的三种方式



使用set方法进行注入


CellPhone类

package com.openlab.pojo;
//注解包  --我用的maven导入的  idea插件里也可以下载
import lombok.*;

//lombok  注解  相当于帮你写了Set方法
@Setter
@ToString
public class CellPhone {
    /**
     *
     * @ClassName: CellPhone
     * @Description:
     * @author: 奋斗小新人
     * @date: 2021年9月13日 18点37分
     */

    //创建属性
    private  String color;
    private String phone;
}



beans.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">

    <!-- 一、set方法注入属性-->

    <!-- 1、配置对象的创建-->
    <bean id="cellphone" class="com.openlab.pojo.CellPhone">
        <!-- 2、使用property完成属性注入
            name:类里面的属性名称
            value:向属性中注入的值
        -->
        <property name="color" value="白色"></property>

        <!--  向属性注入null值-->
        <!--<property name="color" >
            <null/>
        </property>-->

        <!--属性值包含特殊符号
            1.把<>进行转义
            2.把带特殊符号的内容写到CDATA
        -->

        <!-- <property name="phone" value="&lt;&lt;电话&gt;&gt;"></property> -->
  
<!--        用XML文件的特性注入    -->
        <property name="phone">
            <value><![CDATA[<<电话>>]]></value>
        </property>
    </bean>
    </beans>


测试类

package com.openlab.test;

import com.openlab.pojo.CellPhone;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        CellPhone cellphone = context.getBean("cellphone", CellPhone.class);
        System.out.println(cellphone.toString());
    }
}


测试结果

在这里插入图片描述



使用有参构造函数进行注入


CellPhone类

package com.openlab.pojo;
import lombok.*;
//lombok  注解
@ToString
@RequiredArgsConstructor
@AllArgsConstructor
//@NoArgsConstructor   无参构造器注释
//部分参数构造器、全参构造器、
public class CellPhone {
    /**
     *
     * @ClassName: CellPhone
     * @Description:
     * @author: 奋斗小新人
     * @date: 2021年9月13日 18点58分
     */
    //创建属性
    private  String color;
    private String phone;
}


beans.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">


<!--二、有参构造注入属性-->
    <bean id="cellphone" class="com.openlab.pojo.CellPhone">
        <constructor-arg name="color" value="黑色"/>
        <constructor-arg name="phone" value="电话" />
    </bean>

</beans>


测试类

package com.openlab.test;

import com.openlab.pojo.CellPhone;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        CellPhone cellphone = context.getBean("cellphone", CellPhone.class);
        System.out.println(cellphone.toString());
    }
}


测试结果

在这里插入图片描述



使用p名称空间注入


第一步

:添加p名称空间xmlns:p=“http://www.springframework.org/schema/p”。


第二步

:进行属性注入,在bean标签里。


CellPhone类

package com.openlab.pojo;
import lombok.*;
//lombok  注解
@ToString
@Setter
public class CellPhone {
    /**
     *
     * @ClassName: CellPhone
     * @Description:
     * @author: 奋斗小新人
     * @date: 2021年9月13日 19点25分
     */
    //创建属性
    private  String color;
    private String phone;
}


beans.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"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
        
<!--三、p名称空间注入属性-->
    <bean id="cellphone" class="com.openlab.pojo.CellPhone" p:color="颜色" p:phone="电话"  />
</beans>


测试类

package com.openlab.test;

import com.openlab.pojo.CellPhone;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        CellPhone cellphone = context.getBean("cellphone", CellPhone.class);
        System.out.println(cellphone.toString());
    }
}


测试结果

在这里插入图片描述



Spring对象集合属性注入


CellPhone类

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

//lombok  注解
@Getter
@Setter
@ToString
@NoArgsConstructor
public class CellPhone {
    /**
     *
     * @ClassName: CellPhone
     * @Description:
     * @author: 奋斗小新人
     * @date: 2021年9月13日 19点52分
     */
    //创建属性
    private String[] names=new String[3];
    private List<String> listData;
    private Set<String> setData;
    private Map<String,Object> mapData;
    private Properties propsData;

}


beansdata.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">

    <bean class="com.openlab.pojo.CellPhone" name="cellphone">
        <property name="arrdata">
            <array>
                <value>这是数组</value>
                <value>白色手机</value>
                <value>灰色手机</value>
            </array>
        </property>
        <property name="listData">
            <list>
                <value>这是列表</value>
                <value>中国手机</value>
                <value>外国手机</value>
            </list>
        </property>
        <property name="setData">
            <set>
                <value>这是集合</value>
                <value>智能手机</value>
                <value>按键手机</value>
            </set>
        </property>
        <property name="mapData">
            <map>
                <entry key="1" value="map键值对用的entry"/>
                <entry key="2" value="小米"/>
                <entry key="3" value="华为"/>
            </map>
        </property>
        <property name="propsData">
            <props>
                <prop key="1">key为1的属性为张三</prop>
                <prop key="2">李四</prop>
                <prop key="3">王五</prop>
            </props>
        </property>
    </bean>
</beans>


测试类

package com.openlab.test;

import com.openlab.pojo.CellPhone;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class TestData {
    public static void main(String[] args) {
        ApplicationContext factory=new ClassPathXmlApplicationContext("beansdata.xml");
        //通过getBean()获取到beansdata.xml文件中Bean对象
        CellPhone ce=factory.getBean("cellphone", CellPhone.class);

        System.out.println("---数组---");
        //遍历数组
        for (String str:ce.getArrdata()){
            System.out.println(str);
        }

        System.out.println("---list---");
        for (String str:ce.getListData()){
            System.out.println(str);
        }

        System.out.println("---set---");
        for (String str:ce.getSetData()){
            System.out.println(str);
        }

        System.out.println("---map---");
        //拿到所有的key
        Set<String> set=ce.getMapData().keySet();
        for (String str:set){
            System.out.println(str+"--"+ce.getMapData().get(str));
        }

        System.out.println("*********通过Propertis取出数据(通过Entry对象取)******");
        Properties pp=ce.getPropsData();
        for (Map.Entry<Object,Object> entry:pp.entrySet()){
            System.out.println(entry.getKey().toString()+"---"+entry.getValue().toString());
        }

        System.out.println("*********通过Propertis取出数据(通过Enumeration对象取)******");
        Enumeration<Object> en = ce.getPropsData().keys();
        while (en.hasMoreElements()) {
            String key = (String) en.nextElement();
            String value = ce.getPropsData().getProperty(key);
            System.out.println(key + "---" + value);
        }

    }
}


结果

在这里插入图片描述



3.Spring管理bean的作用域

在这里插入图片描述

第一种:(默认)

单例模式



CellPhone 类

package com.openlab.pojo;
import lombok.*;

//lombok  注解
@Getter
@Setter
@ToString
@NoArgsConstructor
public class CellPhone {
    /**
     *
     * @ClassName: CellPhone
     * @Description:
     * @author: 奋斗小新人
     * @date: 2021年9月13日 20点34分
     */
    //创建属性
    private String name;
    private Integer price;
}


beansdata.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">


    <bean class="com.openlab.pojo.CellPhone" name="cellphone" >
           <property name="name" value="小米" />
        <property name="price" value="500" />
    </bean>
</beans>


测试类

package com.openlab.test;

import com.openlab.pojo.CellPhone;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestData {
    public static void main(String[] args) {
        ApplicationContext factory=new ClassPathXmlApplicationContext("beansdata.xml");
        //通过getBean()获取到beansdata.xml文件中Bean对象
        CellPhone ce=factory.getBean("cellphone", CellPhone.class);
        CellPhone ce2=factory.getBean("cellphone", CellPhone.class);
        System.out.println(ce==ce2);
        }
     }


测试结果

在这里插入图片描述


默认单例小结

这个bean就是一个单实例(单例模式)的,即每次调用getBean()方法,获取到的都是同一个bean实例。

第二种:

scope=”prototype”


scope=“prototype” 可以保证

当有请求的时候 都创建一个对象


xml文件中加入了

scope="prototype"

    <bean class="com.openlab.pojo.CellPhone" name="cellphone"  scope="prototype">
           <property name="name" value="小米" />
        <property name="price" value="500" />
    </bean>


测试结果

在这里插入图片描述

第三种:当一个bean的作用域为Request,表示在一次HTTP请求中,一个bean定义对应一个实例;即

每个HTTP请求都会有各自的bean实例

,它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:

<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

第四种:当一个bean的作用域为Session,表示

在一个HTTP Session中,一个bean定义对应一个实例

。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:

<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

第五种:当一个bean的作用域为Global Session,表示在

一个全局的HTTP Session中,一个bean定义对应一个实例

。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:

<bean id="user" class="com.foo.Preferences "scope="globalSession"/>

global session作用域类似于标准的HTTP Session作用域,不过仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个portlet web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。



4.Bean的生命周期

创建一个类BeanLife和Spring配置文件BeanLife.xml,用于测试无参构造方法、init方法和destroy的调用顺序。


五步

  • BeanLife类
package com.openlab.pojo;
public class BeanLife  {
    /**
     * @ClassName BeanLife
     * @author 奋斗小新人
     * @date: 2021年9月14日 16点52分
     */
    private  String name;
    public String getName() {
        System.out.println("get方法执行了");
        return name;
    }
    public void setName(String name) {
        System.out.println("调用set方法");
        this.name = name;
    }
    public BeanLife() {
        System.out.println("构造方法执行");
    }
    public void init(){
        System.out.println("init执行了");
    }

    public void destroy(){
        System.out.println("destory执行了");
    }
}

  • BeanLife.xml文件
        <bean class="com.openlab.pojo.BeanLife" id="beanlife" init-method="init" destroy-method="destroy" lazy-init="true">
                <property name="name" value="生命周期测试"/>
        </bean>
  • 测试方法和运行结果如图:

在这里插入图片描述

由运行结果可以知道,类中的构造方法优先调用,然后才会调用初始化函数。销毁函数只有以ClassPathXmlApplicationContext来创建对象调用getBean()方法后,调用close()函数才会执行。


七步



测试类BeaLife1类

package com.openlab.pojo;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class BeaLife1 implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("创建之前");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("创建之后");
        return bean;
    }
}


xml

        <bean class="com.openlab.pojo.BeanLife" id="beanlife" init-method="init" destroy-method="destroy" lazy-init="true">
                <property name="name" value="生命周期测试"/>
        </bean>
        <bean class="com.openlab.pojo.BeaLife1" id="beanlife1" />


测试类

package com.openlab;

import com.openlab.pojo.BeaLife1;
import com.openlab.pojo.BeanLife;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanLifeTest {
    public static void main(String[] args) {

        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println("------------加载配置文件-----------------");
        BeanLife beanlife = context.getBean("beanlife", BeanLife.class);
        System.out.println("对象可以正常使用");
        System.out.println("------从Spring容器中获取对象");
        BeaLife1 beanlife1 = context.getBean("beanlife1", BeaLife1.class);
        context.close();
    }
}


结果

在这里插入图片描述



4.Spring中bean的两种

  1. 创建普通的Bean对象
package com.openlab;
import com.openlab.pojo.BeanLife;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanLifeTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        BeanLife beanlife = context.getBean("beanlife", BeanLife.class);
    }
}

2.创建工程Bean工厂

package com.openlab.pojo;

import org.springframework.beans.factory.FactoryBean;

public class Factory implements FactoryBean<User> {
    @Override
    public User getObject() throws Exception {
        return new User();
    }

    @Override
    public Class<?> getObjectType() {
        return User.class;
    }
}

然后通过工厂来创建队列的创建。



版权声明:本文为qq_43665704原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。