Spring Framework学习笔记

Posted *^O^*—*^O^*

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Framework学习笔记相关的知识,希望对你有一定的参考价值。

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


Spring Framework

背景及简介

对于 Java 编程来说,使用 Spring 能完成的更加快速,更容易并更安全。Spring 专注于速度,便捷与开发效率,也正是如此,让Spring成为了全世界最流行的 Java 框架。
Spring Framework是简化开发的框架。但是配置比较多(口头说Spring,都是它)Spring Boot框架是进一步简化开发的

子模块简介

Core Container(核心容器)

简介

我们学习spring-core 和 spring-beans 模块,这两个模块提供了整个Spring框架最基础的设施:IoC(Inversion of Control,控制反转) 和 DI (Dependency Injection,依赖注入)。
这部分功能相当于所有Spring 框架运行的基础,以前我们操作对象都需要手动的 new 对象,由对象的作用域决定对象的生命周期。使用Spring后,由框架提供了统一的容器来实例化、管理这些对象,并自动组织对象与对象间的关系。这种容器称为IoC容器,有些地方也叫Spring Bean容器、Spring容器。对象之间的复杂关系(体现在代码中就是对象中成员变量,引用了另一个对象),也交给了容器来进行设置。

IoC

IoC (Inversion of Control,控制反转) ,是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。
系统中通过引入实现了IoC模式的IoC容器,即可由IoC容器来管理对象的生命周期、依赖关系等,从而使得应用程序的配置和依赖性规范与实际的应用程序代码分离。
从使用上看,以前手动new对象,并设置对象中属性的方式,控制权是掌握在应用程序自身。现在则全部转移到了容器,由容器来统一进行管理对象。因为控制权发生了扭转,所以叫控制反转。(可以把IoC容器看做IoC设计思想上的一种实现)

DI

DI (Dependency Injection,依赖注入) 是实现IoC的方法之一。所谓依赖注入,就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中。(把对象注入容器,将对象中的属性注入)
所以,依赖注入(DI)和控制反转(IoC)是从不同的角度的描述的同一件事情,就是指通过引入 IoC 容器,利用依赖关系注入的方式,实现对象之间的解耦。
有时候,也可以将DI看做IoC的一种实现方式

Spring容器使用流程开发步骤

  1. 启动一个容器,加载类加载根路径下的xml配置
  2. 根据xml配置,执行包扫描,扫描指定包和子包下,带
    @Controller.@Service,@Repository,@Component 注解的类
  3. 把以上扫描到的类注册到容器中(每个类都有一个实例对象创建并保存在容器中)
  4. 装配/注入 对象间的依赖关系:对象成员变量引用另一个对象
    使用@Autowired,@Resource注解的成员变量
package org.example;
import org.example.controller.LoginController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App 
    public static void main(String[] args) 
        //根据Spring配置文件路径创建容器:应用上下文对象
        //启动容器,加载xml配置文件,扫描org.example包
        //该包及下面子包中的待Spring注解的类都会注册到容器中,称为Bean对象
        //容器可以理解为一个Map结构,key为bean的id或名称,value为bean对象
        ApplicationContext context = new
                ClassPathXmlApplicationContext("beans.xml");
        //1.获取Bean对象的方式一,通过类型获取,容器只能存在该类型的一个bean
        LoginController loginController = context.getBean(LoginController.class);
        System.out.println(loginController);

        //2.获取方式二,通过名称或者id获取
        LoginController loginController1 = (LoginController) context.getBean("loginController");
        System.out.println(loginController1);
        
        //关闭容器
        ((ClassPathXmlApplicationContext) context).close();
    


初始化/注册Bean

  1. 类注解,就是上述的四个@,默认是单例模式注解,需要保证该类会被Spring扫描到,这种定义方式默认会注册一个名称为类名首字母小写的Bean对象到容器中。
  2. 方法注解:@Bean
    注意:方法所在的类要能被Spring扫描到才行,默认方法名为bean的名称/id,注册到容器中的bean对象为方法返回值
  3. 类注解:@Configuration 注册一个配置类到容器中 在类被Spring扫描到时,使用 @Configuration 注解,可以注册一个配置类到容器中。配置类一般用来自定义配置某些资源。之后会在SpringMVC中用到。
package org.example.controller;

import org.example.service.LoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;

@Controller
//@Scope("singleton")//单例模式
//@Scope("prototype")//原型模式,每次获取都是新的不同对象
public class LoginController 
    /**
     *当前类能被Spring扫描到的情况下
     * 方法加上@Bean注解可以注册Bean
     * 方法名作为Bean的名称/id,Bean对象为返回值
     */
    @Bean
    public Tmp tmp()
        return new Tmp();
    

    public static class Tmp

    

补充:实现了FactoryBean接口的类,被 Spring扫描到,注册到容器中的bean对象,是getBean方法的返回值
(建议使用方式,将带bean注解的方法,定义在@Configuration的类中)

package org.example.controller;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;

@Component
public class TmpFactory implements FactoryBean<LoginController.Tmp> 
    @Override
    public LoginController.Tmp getObject() throws Exception 

        return new LoginController.Tmp();
    

    @Override
    public Class<?> getObjectType() 
        return LoginController.Tmp.class;
    


可见这两个是同一个对象

获取Bean的方式

  1. 通过类型获取:如果该类型的对象,在容器中有多个,通过类型获取就会报错
  2. 通过Bean的名称/id获取
        //一个类型,可以注册多个bean对象到容器中,
        //通过名称/id获取,就是没有关系的
        //
//        LoginController.Tmp tmp = context.getBean(LoginController.Tmp.class);
//        System.out.println(tmp);报错,因为有多个Bean对象
        LoginController.Tmp tmp2 = (LoginController.Tmp) context.getBean("tmpFactory");
        System.out.println(tmp2);

        LoginController.Tmp tmp1 = (LoginController.Tmp) context.getBean("tmp");
        System.out.println(tmp1);

依赖注入

  1. 属性注入
    属性或属性的setter方法上,加上@Autowired,@Resource注解
    默认是变量名为注入bean的名称/id
    注意:注入bean对象时,如果该类型的bean只有一个,变量名叫啥都行,如果有多个,变量名一定要和bean的id/名称一致
  2. 构造方法注入
    构造方法上,加上@Autowired,@Resource注解
    方法参数会注入容器中的bean对象,方法参数变量名为注入的bean名称/id

补充:
 @Bean注解的方法上,方法参数会自动的注入容器中的bean对象,默认方法参数名bean的名称/id
 一个类型有多个bean对象时,可以使用@Qualifier注解,指定要注入的bean名称/id
可以使用在:
 属性注入时,属性上
 构造方法注入时,方法参数上
 @Bean的方法,要注入bean对象时,方法参数上
简单的说,要注入的变量上,加Qualifier注解即可

    @Autowired
    public  LoginService2(@Qualifier("tmp") LoginController.Tmp tmp2)
        this.tmp = tmp2;
    

和前面使用id来获取bean对象是一样的

Bean的作用域

类注解@Controller,@Service,@Component,@Repository默认是单例模式
但是可以通过类上加@Scope注解,表示作用域
@Scope(“singletion”)
	不加,默认就是singleton,表示单例模式注册,每次获取到的都是同一个对象
@Scope(“prototype”)
	原型模式注册,每次获取都是新的不同对象
@Scope("prototype")//原型模式,每次获取都是新的不同对象


就不是同一个bean了

Bean的生命周期(面试题)

  1. 实现了Aware接口的Bean,执行接口方法:如顺序执行BeanNameAware、BeanFactoryAware、ApplicationContextAware的接口方法。
  2. Bean对象初始化前,循环调用实现了BeanPostProcessor接口的预初始化方法(postProcessBeforeInitialization)
  3. Bean对象初始化:顺序执行@PostConstruct注解方法、InitializingBean接口方法、init-method方法
  4. Bean对象初始化后,循环调用实现了BeanPostProcessor接口的后初始化方法(postProcessAfterInitialization)
  5. 容器关闭时,执行Bean对象的销毁方法,顺序是:@PreDestroy注解方法、DisposableBean接口方法、destroy-method

以上是关于Spring Framework学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

Spring Framework学习笔记

慕课-《Spring入门篇》学习笔记 专题一 IOC

Web框架—Spring Framework学习笔记(IoC DI Bean)

Spring MVC框架 学习笔记总结

Spring.Net学习笔记-依赖注入

Spring MVC学习笔记——注解式控制器