Spring Spring

  • Spring的概述
  • Spring的入门

什么是spring框架?

  • Spring是一个开源框架
  • Spring为简化企业级应用开发而生。使用Spring可以使简单的JavaBean实现以前只有EJB才能实现的功能
  • Spring使javaSE/JavaEE的一站式框架

Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。

◆目的:解决企业应用开发的复杂性

◆功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能

◆范围:任何Java应用

Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架。

Spring的优点

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

Spring IOC的底层原理实现

传统方式的开发

UserService us=new UserService();

​ ↓ 面向接口编程

UserService us=new UserSerivceImpl();

​ ↓ ocp原则:open-close 原则,对程序拓展是open的,对修改程序代码是close

​ ↓ 尽量做到不修改程序的源码,实现对程序的扩展

​ 工厂模式

工厂类创建 示例对象

1
2
3
4
5
6
7
class {
public static UserService getUs(){
return new UserServiceImpl();
}

}
UserService us=FactoryBean.getUs();

工厂+反射+配置文件

1
<bean id="us" class="com.imooc.UserServiceImpl"/>
1
2
3
4
5
6
class {
public static Object getBean(String id){
...
反射
}
}

Spring IOC的快速入门案例

  1. 创建Maven工程

    pom.xml

    spring相关依赖

    spring-core/spring-context/spring-beans/spring-logging

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92


    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>sipc</groupId>
    <artifactId>food</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>food Maven Webapp</name>

    <url>http://www.example.com</url>

    <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
    </properties>

    <dependencies>
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>5.1.8.RELEASE</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.8.RELEASE</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>5.1.8.RELEASE</version>
    </dependency>
    <dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
    </dependency>
    <dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
    </dependency>
    </dependencies>

    <build>
    <finalName>food</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
    <plugins>
    <plugin>
    <artifactId>maven-clean-plugin</artifactId>
    <version>3.1.0</version>
    </plugin>
    <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
    <plugin>
    <artifactId>maven-resources-plugin</artifactId>
    <version>3.0.2</version>
    </plugin>
    <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.0</version>
    </plugin>
    <plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.1</version>
    </plugin>
    <plugin>
    <artifactId>maven-war-plugin</artifactId>
    <version>3.2.2</version>
    </plugin>
    <plugin>
    <artifactId>maven-install-plugin</artifactId>
    <version>2.5.2</version>
    </plugin>
    <plugin>
    <artifactId>maven-deploy-plugin</artifactId>
    <version>2.8.2</version>
    </plugin>
    </plugins>
    </pluginManagement>
    </build>
    </project>
  1. 创建applicationContext.xml
  2. 创建接口
  3. 继承接口
  4. SpringDemo1
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    package ioc.demo1;


    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;

    public class SpringDemo1 {
    @Test
    public void demo1(){
    UserService userService=new UserServiceImpl();
    userService.sayHello();
    }
    @Test
    // spring的方式实现
    public void demo2(){
    //创建Spring的工厂
    ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
    //通过工厂获得类
    UserService userService=(UserService) applicationContext.getBean("userService");

    userService.sayHello();

    }
    }

IOC和DI的概念

  • IOC Inverse of Control 反转控制的概念,就是将原本在程序中手动创建UserService对象的控制权,交由

    Spring框架处理

  • 简单说,就是创建UserService对象控制权被反转到了Spring框架
  • DI Dependency Injection 依赖注入的概念,就是在Spring创建这个对象的过程中,

    将这个对象所依赖的属性注入进去

1
2
3
4
5
6
7
8
9
10
11
12

<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">
<!--UserService的创建权交给了Spring-->
<bean id="userService" class="ioc.demo1.UserServiceImpl">
<!--控制反转-->
<!--设置属性-->
<property name="name" value="李四"/>
<!--依赖注入-->
</bean>
</beans>

Spring Bean管理

三种实例化Bean的方式

  • 使用类构造器实例化(默认无参数)
    1. 创建java/demo2/Bean1
    1
    2
    3
    4
    5
    6
    7
    8
    package demo2;

    //实例化的三种方式:采用无参数的构造方法的参数
    public class Bean1 {
    public Bean1(){

    }
    }
    1. 配置spring config applicationContext.xml
    1
    <bean id="bean1" class="demo2.Bean1"/>
    1
    3. SpringDemo2中(测试)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    package demo2;

    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;

    public class SpringDemo2 {
    @Test
    public void demo1(){
    //创建工厂
    ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
    //通过工厂获得类的实例
    Bean1 bean1= (Bean1) applicationContext.getBean("bean1");
    }
    }
  • 使用静态工厂方法实例化(简单工厂模式)
    1. 创建java/demo2/Bean2
    1
    2
    3
    4
    5
    package demo2;
    //静态工厂实例化方式
    public class Bean2 {

    }
    1. 创建demo2/Bean2Factory
    1
    2
    3
    4
    5
    6
    7
    8
    9
    package demo2;

    public class Bean2Factory {
    //第二种:Bean2的静态工厂
    public static Bean2 createBean2(){
    System.out.println("Bean2Factory的方法已经执行了");
    return new Bean2();
    }
    }
  1. applicationContext.xml
    1
    <bean id="bean2" class="demo2.Bean2Factory" factory-method="createBean2"/>
  1. SpringDemo2中(包含bean3)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    package demo2;

    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;

    public class SpringDemo2 {
    @Test
    public void demo1(){
    //创建工厂
    ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
    //通过工厂获得类的实例
    Bean1 bean1= (Bean1) applicationContext.getBean("bean1");
    }
    public void demo2(){
    //创建工厂
    ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
    //通过工厂获得类的实例
    Bean2 bean2= (Bean2) applicationContext.getBean("bean2");
    }
    public void demo3(){
    //创建工厂
    ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
    //通过工厂获得类的实例
    Bean3 bean3= (Bean3) applicationContext.getBean("bean3");
    }
    }
  • 使用实例工厂方法实例化(工厂方法模式)
  1. java/demo2/Bean3
1
2
3
4
5
package demo2;
//第三种:实例工厂实例化的方式
public class Bean3 {

}
  1. demo2/Bean3Factory
1
2
3
4
5
6
7
8
package demo2;

public class Bean3Factory {
public Bean3 createBean3(){
System.out.println("Bean3Factory被执行了");
return new Bean3();
}
}
  1. applicationContext.xml
1
2
<bean id="bean3Factory" class="demo2.Bean3Factory"/>
<bean id="bean3" factory-bean="bean3Factory" factory-method="createBean3"/>
  1. SpringDemo2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package demo2;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringDemo2 {
@Test
public void demo1(){
//创建工厂
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
//通过工厂获得类的实例
Bean1 bean1= (Bean1) applicationContext.getBean("bean1");
}
public void demo2(){
//创建工厂
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
//通过工厂获得类的实例
Bean2 bean2= (Bean2) applicationContext.getBean("bean2");
}
public void demo3(){
//创建工厂
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
//通过工厂获得类的实例
Bean3 bean3= (Bean3) applicationContext.getBean("bean3");
}
}

Bean的配置

  • id和name
    • 一般情况下,装配一个Bean时,通过指定一个id属性作为Bean的名称
    • id 属性在IOC容器中必须是唯一的
    • 如果Bean的名称中含有特殊字符,就需要使用name属性
  • class
    • class用于设置一个类的完全路径名称,主要作用是IOC容器生成类的实例

Bean的作用域

类别 说明
singleton 在SpringIOC容器中仅存在一个Bean实例,Bean以单实例的方式存在
prototype 每次调用getBean()时都会返回一个新的实例
request 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境
session 同一个HTTP Session共享一个Bean,不同的HTTP Session使用不同的Bean,该作用域仅适用于WebApplicationContext环境

applicationContext.xml

1
2
3
4
5
6
7

<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的作用范围-->
<bean id="person" class="com.majiajun.demo3.Person" scope="prototype"/>
</beans>

demo3/Person

1
2
3
4
5
package com.majiajun.demo3;

public class Person {

}

demo3/SpringDemo3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.majiajun.demo3;

import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/*Bean作用范围的测试*/
public class SpringDemo3 {
@Test
public void demo1(){
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
Person person= (Person) applicationContext.getBean("person");
Person person1=(Person) applicationContext.getBean("person");
System.out.println(person);
System.out.println(person1);
}
}

Bean的生命周期

1
<bean id="man" class="demo3.Man" init-method="setup" destroy-method="teardown"></bean>

Bean的生命周期的完整过程

  1. instantiate bean对象实例化
    1
    2
    3
    4
    5
    public class Man(){
    public Man(){
    System.out.println("第一步:对象的实例化");
    }
    }
  2. poprlate properties封装属性
    1
    2
    3
    4
    5
    6
    7
    public class Man{
    private String name;

    public void setName(String name) {
    System.out.println("第二步:设置属性");
    this.name = name;
    }
  3. 如果Bean实现BeanNameAware执行setBeanName
  4. 如果Bean实现BeanFactoryAware或者ApplicationContextAware设置工厂 setBeanFactory或者上下文对象setApplicationContext
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    public class Man implements BeanNameAware, ApplicationContextAware {
    private String name;

    public void setName(String name) {
    System.out.println("设置属性");
    this.name = name;
    }

    public Man(){
    System.out.println("Man被实例化");
    }
    public void setup(){
    System.out.println("Man被初始化");
    }
    public void teardown(){
    System.out.println("Man被销毁了");
    }

    @Override
    public void setBeanName(String s) {
    System.out.println("第三步:设置Bean的");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    System.out.println("第四步:了解工厂的信息");
    }
    }
  5. 如果存在类实现BeanPostProcessor(后处理Bean),执行postProcessBeforeInitialization
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    package com.majiajun.demo3;

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

    public class MyBeanProcessor 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;
    }
    }
  6. 如果Bean实现InitializingBean执行afterPropertiesSet
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    package com.majiajun.demo3;

    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.BeanNameAware;
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;

    public class Man implements BeanNameAware, ApplicationContextAware, InitializingBean {
    private String name;

    public void setName(String name) {
    System.out.println("设置属性");
    this.name = name;
    }

    public Man(){
    System.out.println("Man被实例化");
    }
    public void setup(){
    System.out.println("Man被初始化");
    }
    public void teardown(){
    System.out.println("Man被销毁了");
    }

    @Override
    public void setBeanName(String s) {
    System.out.println("第三步:设置Bean的");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    System.out.println("第四步:了解工厂的信息");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
    System.out.println("第六步:属性设置后");
    }
    }
  7. 调用指定初始化方法init
  8. 如果存在类实现BeanPostProcessor(后处理Bean),执行postProcessAfterInitialization
  9. 执行业务处理(自己定义的方法),如下
    1
    2
    3
    4
    5
    public class Man{
    public void run(){
    System.out.println("第九步:执行业务方法");
    }
    }
  10. 如果Bean实现DisposableBean执行destory
    1
    2
    3
    4
    5
    public class Man implements DisposableBean{
    public void destory()throws Exception{
    System.out.println("第十步:执行Spring的销毁方法");
    }
    }
  11. 调用指定销毁方法customerDestory

Spring容器中Bean的生命周期

  • 演示如何增强一个类中的方法

Spring的属性注入

  • 对于类成员变量,注入方式有三种
    • 构造函数注入
      • 通过构造方法注入Bean的属性值或依赖的对象,它保证了Bean实例在实例化后就可以使用
    • 属性settrt方法注入
    • 接口注入
  • Spring支持前两种