当前位置:   article > 正文

『JavaEE』Spring FrameWork简介_org.springframework是什么

org.springframework是什么

本篇博客简单介绍一下Spring FrameWork的相关概念。

什么是Spring?


  • Spring是一个主流的Java Web开发框架,该框架是一个轻量级的应用框架,具有很高的凝聚力和吸引力。Spring框架因其强大的功能以及卓越的性能而受到众多开发人员的喜爱。
  • Spring是分层的Java SE/EE full-stack轻量级开源框架,以IoC(Inverse of Control,控制反转)AOP(Aspect of Programming,面向切面编程)为内核,使用基本的JavaBean完成以前只可能由EJB完成的工作,取代了EJB臃肿和低效的开发模式。
  • 实际开发中,通常服务端采用三层体系架构,分别为表现层(web)业务逻辑层(service)持久层(dao)
  • Spring对每一层都提供了技术支持,在表现层提供了与Structs框架的整合,在业务逻辑层可以管理事务和记录日志等,在持久层可以整合Hibernate和jdbc Template等技术。
  • 从设计上看,Spring框架给予了Java程序员更高的自由度,对业界的常见问题也提供了良好的解决方案,因此,在开源社区受到了广泛的欢迎,并且被大部分公司作为Java项目开发的首选框架。
  • Spring具有简单、可测试和松耦合等特点,不仅可以用于服务器端的开发,也可以应用于任何Java应用的开发中。

使用maven创建一个Spring项目


  • 点击File -> New -> Module,选择Maven,点击Next。
    在这里插入图片描述
  • 输入GroupId和ArtifactId,点击Next
    在这里插入图片描述
  • 创建完成后,修改pom.xml如下
<?xml version="1.0" encoding="UTF-8"?>
<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>com.sss</groupId>
    <artifactId>test_spring</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <encoding>UTF-8</encoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
            <scope>provided</scope>
        </dependency>

        <!-- Spring需要的依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>

        <!-- 日志需要的依赖 -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

    </dependencies>

    <build>
        <finalName>test_spring</finalName>

        <!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
        <pluginManagement>
            <plugins>
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>3.1.0</version>
                </plugin>
                <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
  • 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
  • org.springframework.context.ApplicationContext接口是我们常用的Spring IoC容器负责实例化、配置、及装配bean的,它是org.springframework.beans.factory.BeanFactory的子接口,也是我们通常所说的bean工厂
  • 这个接口有需要的实现类,我们使用org.springframework.context.support.ClassPathXmlApplicationContext进行我们的练习。
  • 我们新建一个Main.java
package com.sss;

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

public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applications.xml");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • resources目录下新建applications.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

</beans>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在这里插入图片描述

  • 我们来修改一个applications.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 创建一个字符串对象,对象名为myName,通过new String("sss")生成对象 -->
    <bean id="myName" class="java.lang.String">
        <constructor-arg value="sss" />
    </bean>

</beans>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 我们再来修改一个Main.java,如下:
package com.sss;

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

public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applications.xml");

        // 通过名字来获取bean对象
        Object o = context.getBean("myName");
        System.out.println(o.getClass());
        System.out.println(o);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 运行结果如下
    在这里插入图片描述

上述过程的原理如下图所示
在这里插入图片描述

  • context就是我们的IoC容器
  • myName是我们配置的bean,其中myName表示bean的唯一id,类是java.lang.String,构造方法的参数时"sss";
  • 通过context.getBean("myName")可以拿到我们需要的对象,对象的初始化过程我们再也不用参与了。

Spring Bean容器


Spring Bean容器:存放对象的一种技术实现,对象的生命周期由容器进行统一的管理
Spring IoC容器可以管理一个或者多个bean,这些bean都是通过xml进行配置,这些Bean在Spring内部是通过BeanDefinition进行管理,每个bean对象都有一个BeanDefinition对象管理,管理包括但不限于如下的信息

  • 对象的类型全名(package-qualified class name);
  • bean的行为,例如scope、生命周期等;
  • 依赖其他bean信息。

Spring Bean的配置


我们新建一个Book类,如下:

package com.sss;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Setter
@Getter
@ToString
public class Book {
    private String name;
    private String author;

    public Book() {}

    public Book(String name) {
        this.name = name;
    }

    public Book(String name, String author) {
        this.name = name;
        this.author = author;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

然后,我们再来新建一个BookStore类,如下:

package com.sss;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.util.List;

@Setter
@Getter
@ToString
public class BookStore {
    private String name;
    private List<Book> books;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

基于XML的方式配置Bean


然后我么来修改applications.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="book1" class="com.sss.Book">
        <property name="name" value="三国演义" />
        <property name="author" value="罗贯中" />
    </bean>

    <bean id="book2" class="com.sss.Book">
        <constructor-arg name="name" value="西游记" />
        <property name="author" value="吴承恩" />
    </bean>

    <bean id="book3" class="com.sss.Book">
        <constructor-arg name="name" value="水浒传" />
        <constructor-arg name="author" value="施耐庵" />
    </bean>

    <bean id="book4" class="com.sss.Book">
        <constructor-arg index="0" value="红楼梦" />
        <constructor-arg index="1" value="曹雪芹" />
    </bean>

    <bean id="bookStore" class="com.sss.BookStore">
        <property name="name" value="三味书屋" />
        <property name="books">
            <list>
                <ref bean="book1" />
                <ref bean="book2" />
                <ref bean="book3" />
                <ref bean="book4" />
            </list>
        </property>
    </bean>

</beans>
  • 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

最后,我们来修改一下Main.java,如下:

package com.sss;

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

public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applications.xml");

        // 通过名字来获取bean对象
        Object book1 = context.getBean("book1");
        System.out.println(book1);
        System.out.println(book1.getClass() + "\n");

        Object book2 = context.getBean("book2");
        System.out.println(book2);
        System.out.println(book2.getClass() + "\n");

        Object book3 = context.getBean("book3");
        System.out.println(book3);
        System.out.println(book3.getClass() + "\n");

        Object book4 = context.getBean("book4");
        System.out.println(book4);
        System.out.println(book4.getClass() + "\n");

        // 通过类型获取对象:容器中只能有一个该类型的对象
        Object bookStore = context.getBean(BookStore.class);
        System.out.println(bookStore);
        System.out.println(bookStore.getClass());
    }
}
  • 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

在这里插入图片描述
注意事项

  • 通过类型获取对象,必须保证容器中只有一个该类型的对象,否则会报错,我们来看一下如果容器中有多个同类型对象,然后我们通过类型来获取对象:
package com.sss;

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

public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applications.xml");

        // 通过类型获取对象:容器中只能有一个该类型的对象
        Object book = context.getBean(Book.class);
        System.out.println(book);
        System.out.println(book.getClass());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

在这里插入图片描述

  • 使用constructor-arg的方式注入对象,必须有对应的构造方法。我们来调整一下Book类和applications.xml中的内容来看一下:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

基于Annotation的方式配置Bean


我们来修改一下applications.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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

	<!--
		扫描base-package的包,所有子包都会进行扫描包含Spring注解的类
	-->
    <context:component-scan base-package="com.sss.scan" />

</beans>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

主要用到的注解如下

  • @Controller:做前端请求处理的类;
  • @Service:业务处理的类;
  • @Component:宽泛的概念,一般指组件;
  • @Repository:数据操作的类;
  • @Configuration:配置类,使用@Configuration+@Bean。

我们先来使用一下@Controller注解

package com.sss.scan;

import org.springframework.stereotype.Controller;

// @Controller和@Controller("Bean名称")
// @Controller使用类名首字母小写作为Bean名称
@Controller
public class LoginController {

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
package com.sss;

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

public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applications.xml");

        Object o = context.getBean("loginController");
        System.out.println(o);
        System.out.println(o.getClass());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

运行结果如下
在这里插入图片描述
我们再来看一下@Service注解

package com.sss.scan;

import org.springframework.stereotype.Service;

@Service
public class LoginService {

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
package com.sss;

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

public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applications.xml");

        Object o = context.getBean("loginService");
        System.out.println(o);
        System.out.println(o.getClass());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在这里插入图片描述
我们来看一下@Configuration注解的使用

package com.sss.scan;

import com.sss.Book;
import com.sss.BookStore;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;

@Configuration
public class Conf {

    @Bean
    public Book book1() {
        return new Book("三国演义", "罗贯中");
    }

    @Bean("book2")
    public Book testBook1() {
        return new Book("水浒传", "施耐庵");
    }

    @Bean
    public Book book3() {
        return new Book("西游记", "吴承恩");
    }

    @Bean("book4")
    public Book testBook2() {
        return new Book("红楼梦", "曹雪芹");
    }

    @Bean
    public BookStore bookStore1(Book book1, Book book2) {
        BookStore bookStore = new BookStore();

        List<Book> books = new ArrayList<>();
        books.add(book1);
        books.add(book2);

        bookStore.setName("三味书屋");
        bookStore.setBooks(books);

        return bookStore;
    }

    @Bean("bookStore2")
    public BookStore testBookStore(@Qualifier("book3") Book book3, @Qualifier("book4") Book book4) {
        BookStore bookStore = new BookStore();

        List<Book> books = new ArrayList<>();
        books.add(book3);
        books.add(book4);

        bookStore.setName("新华书店");
        bookStore.setBooks(books);

        return bookStore;
    }
}
  • 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
package com.sss;

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

public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applications.xml");

        Object book1 = context.getBean("book1");
        System.out.println(book1);
        System.out.println(book1.getClass());

        Object book2 = context.getBean("book2");
        System.out.println(book2);
        System.out.println(book2.getClass());

        Object book3 = context.getBean("book3");
        System.out.println(book3);
        System.out.println(book3.getClass());

        Object book4 = context.getBean("book4");
        System.out.println(book4);
        System.out.println(book4.getClass());

        Object bookStore1 = context.getBean("bookStore1");
        System.out.println(bookStore1);
        System.out.println(bookStore1.getClass());

        Object bookStore2 = context.getBean("bookStore2");
        System.out.println(bookStore2);
        System.out.println(bookStore2.getClass());
    }
}
  • 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

在这里插入图片描述

Spring Bean的装配


Spring Bean的装配就是要使用Bean了。通常我们使用两个注解来实现Bean的装配:@Autowired@Resource,二者的区别如下:

  • @AutowiredSpring的注解,只能Spring框架使用
  • @ResourceJDK的注解,是一种装配资源类的规范,Spring实现了这个规范,所以也可以使用该注解

我们先来看一下@Autowired注解的使用

package com.sss.scan;

import com.sss.Book;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

// @Controller和@Controller("Bean名称")
// @Controller使用类名首字母小写作为Bean名称
@Controller
@Getter
@Setter
@ToString
public class LoginController {

    @Autowired
    private LoginService loginService;

    @Autowired
    private Book book1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
package com.sss;

import com.sss.scan.LoginController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applications.xml");

        LoginController loginController = (LoginController) context.getBean("loginController");
        System.out.println(loginController.getClass());
        System.out.println(loginController);
        System.out.println(loginController.getLoginService());
        System.out.println(loginController.getBook1());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

在这里插入图片描述
@Resource注解的使用方式和@Autowired一样,我们来看一下:

package com.sss.scan;

import com.sss.Book;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.stereotype.Controller;

import javax.annotation.Resource;

// @Controller和@Controller("Bean名称")
// @Controller使用类名首字母小写作为Bean名称
@Controller
@Getter
@Setter
@ToString
public class LoginController {

    @Resource
    private LoginService loginService;

    @Resource
    private Book book1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
package com.sss;

import com.sss.scan.LoginController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applications.xml");

        LoginController loginController = (LoginController) context.getBean("loginController");
        System.out.println(loginController.getClass());
        System.out.println(loginController);
        System.out.println(loginController.getLoginService());
        System.out.println(loginController.getBook1());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

在这里插入图片描述
除了上述两种装配方式,Spring中@Bean注解修饰的方法参数会被自动装配

Spring Bean对象的作用域


Spring容器在初始化一个Bean的实例时,同时会指定该实例的作用域。Spring3为Bean定义了五种作用域,具体如下:

  • singleton
    单例模式,使用singleton定义的Spring容器中只有一个实例,这也是Bean默认的作用域
  • prototype
    原型模式,每次通过Spring容器获取prototype定义的Bean时,容器都将创建一个新的Bean实例
  • request
    在一次HTTP请求中,容器会返回该Bean的同一个实例。而对不同的HTTP请求,会返回不同的实例,该作用域仅在当前HTTP Request内有效。
  • session
    在一次HTTP Session中,容器会返回该Bean的同一个实例。而对不同的HTTP请求,会返回不同的实例,该作用域仅在当前HTTP Session内有效。
  • global Session
    在一个全局的HTTP Session中,容器会返回该Bean的同一个实例。该作用域仅在使用portlet context时有效。

这里我们主要来看一下singleton和prototype
我们修改一下applications.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="book" class="com.sss.Book" scope="singleton">
        <property name="name" value="三国演义" />
        <property name="author" value="罗贯中" />
    </bean>

</beans>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

我们修改一下Main.java,如下:

package com.sss;

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

public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applications.xml");

        Object book1 = context.getBean("book");
        Object book2 = context.getBean("book");
        System.out.println(book1 == book2);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在这里插入图片描述
可以看到,得到的两个Bean对象是同一个,我们修改一下Bean的作用域为prototype,如下:

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="book" class="com.sss.Book" scope="prototype">
        <property name="name" value="三国演义" />
        <property name="author" value="罗贯中" />
    </bean>

</beans>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在这里插入图片描述
可以看到返回的两个Bean对象不是同一个

Spring Bean的生命周期


Spring容器可以管理singleton作用域Bean的生命周期,在此作用域下,Spring能够精确地知道该Bean何时被创建,何时初始化完成,以及何时被销毁。
而对于prototype作用域的Bean,Spring只负责创建,当容器创建了Bean的实例后,Bean的实例就交给客户端代码管理,Spring容器将不再跟踪其生命周期。每次客户端请求prototype作用域的Bean时,Spring容器都会创建一个新的实例,并且不会管那些被配置成prototype作用域的Bean的生命周期。

了解Spring生命周期的意义就在于,可以利用Bean在其存活期间的指定时刻完成一些相关操作。这种时刻可能有很多,但一般情况下,会在Bean被初始化后和被销毁前执行一些相关操作。
在Spring中,Bean的生命周期是一个很复杂的执行过程我们可以利用Spring提供的方法定制Bean的创建过程
当一个Bean被加载到Spring容器时,它就具有了生命,而Spring容器在保证一个Bean能够使用之前,会进行很多工作。Spring容器中Bean的生命周期流程如下图所示
在这里插入图片描述
我们通过一个代码来看一下Bean的生命周期

package com.sss;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class Lifecycle implements BeanNameAware, BeanFactoryAware,
        ApplicationContextAware, BeanPostProcessor, InitializingBean,
        DisposableBean {
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("BeanFactoryAware");
    }

    @Override
    public void setBeanName(String s) {
        System.out.println("BeanNameAware");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("ApplicationContextAware");
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor before");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor after");
        return bean;
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean");
    }
}
  • 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

我们来修改一下applications.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="book1" class="com.sss.Book">
        <property name="name" value="三国演义" />
        <property name="author" value="罗贯中" />
    </bean>

    <bean id="book2" class="com.sss.Book">
        <property name="name" value="西游记" />
        <property name="author" value="吴承恩" />
    </bean>

    <bean id="book3" class="com.sss.Book">
        <property name="name" value="水浒传" />
        <property name="author" value="施耐庵" />
    </bean>

    <bean id="book4" class="com.sss.Book">
        <property name="name" value="红楼梦" />
        <property name="author" value="曹雪芹" />
    </bean>

    <bean id="bookStore" class="com.sss.BookStore">
        <property name="name" value="三味书屋" />
        <property name="books">
            <list>
                <ref bean="book1" />
                <ref bean="book2" />
                <ref bean="book3" />
                <ref bean="book4" />
            </list>
        </property>
    </bean>

    <bean id="lifeCycle" class="com.sss.Lifecycle" />

</beans>
  • 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

最后我们来修改一下Main.java,如下:

package com.sss;

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

public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applications.xml");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

运行结果如下
在这里插入图片描述

控制反转IoC和依赖注入DI


什么是IoC


IoC即Inversion of Control,即控制反转,不是什么技术,而是一种设计思想。在Java开发中,IoC意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。如何理解IoC呢?理解好IoC的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就有正转),哪些方面反转了”。

  • 谁控制谁,控制什么:传统的Java SE程序设计,我们直接在程序内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由IoC容器来控制对象的创建;谁控制谁?当然是IoC容器控制对象控制什么?主要控制外部资源获取(不只是对象包括比如文件等)
  • 为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了
  • 传统的程序设计都是主动去创建相关对象然后再结合起来,如下图:
    在这里插入图片描述
  • 有了IoC/DI的容器后,在客户端类中不再主动去创建这些对象,如下图:
    在这里插入图片描述

IoC能做什么?


  • IoC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。
  • 其实IoC对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在IoC/DI思想中,应用程序就变成被动的了,被动的等待IoC容器来创建并注入它所需要的资源了
  • IoC很好的体现了面向对象设计法则之一,好莱坞法则:“别找我们,我们找你”;即由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找

什么是DI?


DI,Dependency Injection,即“依赖注入”组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来的更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下:

  • 谁依赖于谁:当然是应用程序依赖于IoC容器
  • 为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源
  • 谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象
  • 注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常亮数据)

IoC和DI有什么关系?


其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以2004年大师级人物Martin Fowler又给出了一个新的名字:“依赖注入”,相对IoC而言,“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”

IoC(控制反转)

  • 所谓IoC,对于Spring框架而言,就是由Spring来负责控制对象的生命周期和对象间的关系
  • 举个例子,通常我们找女朋友,常见的情况是,我们到处去看哪里有长得漂亮身材又好的小姐姐,然后打听她们的兴趣爱好、微信等,想办法认识她们,投其所好。这个过程我们必须自己设计和面对每个环节。传统的程序开发也是如此,在一个对象中,如果要使用另外的对象,就必须得到它(自己new一个),使用完之后还要将对象销毁,对象始终会和其他的接口或类耦合起来。
  • IoC是如何做到的呢?有点像婚介所找女朋友,在我们和小姐姐之间引入了一个第三者:婚姻介绍所。婚介所管理了很多男男女女的资料,我们可以向婚介所提出一个列表,告诉它我想找个什么样的女朋友。然后婚介所就会按照我们的要求,提供一个小姐姐,我们只需要去和她恋爱就可以了。简单明了,如果婚介所给我们的人选不符合要求,们就会抛出异常。整个过程不再;由我自己控制,而是由婚介所这样一个容器来控制。
  • Spring倡导的开发方式就是如此,所有的类都会在Spring容器中登记,告诉Spring你是个什么东西,你需要什么东西,然后Spring会在系统运行到适当的时候,把你需要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由Spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是Spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被Spring控制,所以这叫控制反转

DI(依赖注入)

  • IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的
  • 比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了Spring我们就只需要告诉Spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。
  • 在系统运行中,Spring会在适当的时候制造一个Connection,然后像打针一样,注射到A中,这样就完成了对各个对象之间关系的控制。A需要依赖Connection才能正常运行,这个Connection是由Spring注入到A中的,依赖注入的名字就是这么来的。
  • 那么DI是如何实现的呢?Java 1.3之后一个重要特征是反射(reflection),它允许程序在运行的时候动态生成对象、执行对象的方法、改变对象的属性,Spring就是通过反射来实现注入的

IoC(控制反转)和DI(依赖注入)的理解

  • 在平时的Java应用开发中,我们要实现某一个功能或者说是完成某个业务逻辑至少需要两个或以上的对象来写作完成。
  • 没有使用Spring的时候,每个对象再需要使用它的合作对象时,自己均要使用像new Object()这样的语法来将合作对象创建出来,这个合作对象是由自己主动创建出来的,创建合作对象的主动权在自己手上,自己需要哪个合作对象,就主动去创建,创建合作对象的主动权和创建时机都是由自己把握的,而这样就会使得对象间的耦合度高了,A对象需要使用合作对象B来共同完成一件事,A要使用B,那么A就对B产生了依赖,也就是A和B之间存在一种耦合关系,并且是紧密耦合在一起。
  • 使用了Spring之后就不一样了,创建合作对象B的工作是由Spring来做的,Spring创建好B对象,然后存储到一个容器里面,当A对象需要使用B对象时,Spring就从存放对象的那个容器里面取出A要使用的那个B对象,然后交给A对象使用,至于Spring是如何创建那个对象,以及什么时候创建好对象的,A对象不需要关心这些细节问题,A得到Spring给我们的对象之后,两个人一起协作完成要完成的工作即可。
  • 所以控制反转IoC是说创建对象的控制权进行转移,以前创建对象的主动权和创建时机是由自己把握的,而现在这种权力转移到第三方,比如转移交给了IoC容器,它就是一个专门用来创建对象的工厂,你要什么对象,它就给你什么对象,有了IoC容器,依赖关系就变了,原先的依赖关系就没了,他们都依赖IoC容器,通过IoC容器来建立它们之间的关系
  • DI(依赖注入)其实就是IoC的另外一种说法,DI是由Martin Fowler在2004年初的一篇论文中首次提出的。他总结:控制的什么被反转了?就是:获得依赖对象的方式反转了

Spring IoC的原理


Spring IoC的原理使用反射+ASM字节码技术
反射的缺点效率低,还有一些限制(无法获取方法传入参数名)

Spring注册Bean、装载Bean的流程

  • 加载并解析配置文件;
  • 通过反射+ASM字节码技术创建Bean对象并设置对象属性。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/84785
推荐阅读
相关标签
  

闽ICP备14008679号