Spring基础(上)

简介: Spring基础(上)

Spring基础


Spring是为了简化开发而生,它是轻量级的IoCAOP的容器框架,主要是针对Bean的生命周期进行管理的轻量级容器,并且它的生态已经发展得极为庞大。


IoC容器基础

IoC理论

之前的Web应用各层角色分工都明确,流水线上的一套操作必须环环相扣,这是一种高度耦合的体系。目前App更新频繁,对于高耦合代码出现问题,无法高效进行维护和更新。

IOC是Inversion of Control的缩写,翻译为:“控制反转”,把复杂系统分解成相互合作的对象,这些对象类通过封装以后,内部实现对外部是透明的,从而降低了解决问题的复杂度,而且可以灵活地被重用和扩展。

将对象交给IoC容器进行管理,不用再关心我们要去使用哪一个实现类了,我们只需要关心,给到我的一定是一个可以正常使用的实现类,能用就完事了。

public static void main(String[] args) {
    A a = new A();
    a.test(IoC.getBean(Service.class));   //容器类
    //比如现在在IoC容器中管理的Service的实现是B,那么我们从里面拿到的Service实现就是B
}
class A{
    private List<Service> list;   //一律使用Service,具体实现由IoC容器提供
    public Service test(Service b){
        return null;
    }
}
interface Service{ }   //使用Service做一个顶层抽象
class B implements Service{}  //B依然是具体实现类,并交给IoC容器管理


当具体实现类发生修改时,我们同样只需要将新的实现类交给IoC容器管理,这样我们无需修改之前的任何代码。

高内聚,低耦合,是现代软件的开发的设计目标,而Spring框架就给我们提供了这样的一个IoC容器进行对象的的管理,一个由Spring IoC容器实例化、组装和管理的对象,我们称其为Bean。


第一个Spring程序

创建实体类:

@ToString
public class Student {
}


注册Bean:

<?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 name="student" class="com.test.bean.Student"/>
</beans>


获取Bean对象:

public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
        Student student = context.getBean(Student.class);
        System.out.println(student);
    }
}


这个对象不需要我们再去创建了,而是由IoC容器自动进行创建并提供,我们可以直接从上下文中获取到它为我们创建的对象,这里得到的Student对象是由Spring通过反射机制帮助我们创建的


Bean注册与配置

配置一个Bean,并指定对应的类:

<bean class="com.test.bean.Student"/>


据类型向容器索要Bean实例对象:

ApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
//getBean有多种形式,其中第一种就是根据类型获取对应的Bean
//容器中只要注册了对应类的Bean或是对应类型子类的Bean,都可以获取到
Student student = context.getBean(Student.class);


为Bean指定一个名称用于区分:

<bean name="a" class="com.test.bean.Student"/>
<bean name="b" class="com.test.bean.Student"/>


<bean name="a" class="com.test.bean.Student"/>
<alias name="a" alias="test"/>#为Bean创建别名

默认情况下,通过IoC容器进行管理的Bean都是单例模式的,这个对象只会被创建一次。

对象作用域配置:

singleton,默认单例,全局唯一实例; prototype,原型模式,每次获取新的对象

当Bean的作用域为单例模式时,那么容器加载配置时就被创建,之后拿到的都是这个对象,容器没有被销毁,对象将一直存在;而原型模式下,只有在获取时才会被创建

单例模式下的Bean懒加载(获取时再加载):

<bean class="com.test.bean.Student" lazy-init="true"/>


维护Bean的加载顺序:

<bean name="teacher" class="com.test.bean.Teacher"/>
<bean name="student" class="com.test.bean.Student" depends-on="teacher"/>


xml配置文件是可以相互导入的:

<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
    <import resource="test.xml"/>
</beans>


依赖注入

依赖注入(Dependency Injection, DI)是一种设计模式,也是Spring框架的核心概念之一。

实体类需要其他实体类,创建时保证其他实体类也能进行动态加载。

public class Student {
    private Teacher teacher;
    //要使用依赖注入,我们必须提供一个set方法(无论成员变量的访问权限是什么)命名规则依然是驼峰命名法
    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }
    ...


public interface Teacher {
    void teach();
}
public class ArtTeacher implements Teacher{
    @Override
    public void teach() {
        System.out.println("我是美术老师,我教你画画!");
    }
}
public class ProgramTeacher implements Teacher{
    @Override
    public void teach() {
        System.out.println("我是编程老师,我教你学Golang!");
    }
}

有了依赖注入之后,Student中的Teacher成员变量,可以由IoC容器来选择一个合适的Teacher对象进行赋值,也就是说,IoC容器在创建对象时,需要将我们预先给定的属性注入到对象中

使用property标签:

<bean name="teacher" class="com.test.bean.ProgramTeacher"/>
<bean name="student" class="com.test.bean.Student">
    <property name="teacher" ref="teacher"/>
</bean>


name指定成员对象名,ref指定依赖的Bean名称

1b2d4172705b76fdb296a50e59b08cfb.png

依赖注入并不一定要注入其他的Bean,也可以是一个简单的值:

<bean name="student" class="com.test.bean.Student">
    <property name="name" value="卢本伟"/>
</bean>


在构造方法中去完成初始化:

public class Student {
    private final Teacher teacher;   //构造方法中完成,所以说是一个final变量
    public Student(Teacher teacher){   //Teacher属性是在构造方法中完成的初始化
        this.teacher = teacher;
    }
    ...


IoC容器默认只会调用无参构造,需要指明一个可以用的构造方法

constructor-arg标签:

<bean name="teacher" class="com.test.bean.ArtTeacher"/>
<bean name="student" class="com.test.bean.Student">
    <constructor-arg name="teacher" ref="teacher"/>
</bean>


constructor-arg就是构造方法的一个参数,这个参数可以写很多个,会自动匹配符合里面参数数量的构造方法

type指定参数的类型

<constructor-arg value="1" type="int"/>


其他特殊类型:

<bean name="student" class="com.test.bean.Student">
    <!--  对于集合类型,我们可以直接使用标签编辑集合的默认值  -->
    <property name="list">
        <list>
            <value>AAA</value>
            <value>BBB</value>
            <value>CCC</value>
        </list>
    </property>
</bean>


<bean name="student" class="com.test.bean.Student">
    <property name="map">
        <map>
            <entry key="语文" value="100.0"/>
            <entry key="数学" value="80.0"/>
            <entry key="英语" value="92.5"/>
        </map>
    </property>
</bean>

自动装配

自动装配就是让IoC容器自己去寻找需要填入的值,只需要将set方法提供好就可以了

autowire属性有两个值普通,一个是byName,还有一个是byType,顾名思义,一个是根据类型去寻找合适的Bean自动装配,还有一个是根据名字去找,就不需要显式指定property

<bean name="student" class="com.test.bean.Student" autowire="byType"/>


byName自动装配,依据的Name是setter方法的后缀和bean的name属性进行匹配:

public class Student {
    Teacher teacher;
    public void setArt(Teacher teacher) {
        this.teacher = teacher;
    }
}


<?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 name="art" class="com.test.bean.ArtTeacher"/>
    <bean name="student" class="com.test.bean.Student" autowire="byName"/>
</beans>

使用构造方法完成的依赖注入,也支持自动装配:

<bean name="student" class="com.test.bean.Student" autowire="constructor"/>


当自动装配发生歧义时:

Bean属性autowire-candidate设定false时,这个Bean将不再作为自动装配的候选Bean

Bean设定primary属性,当出现歧义时,也会优先选择

<bean name="teacher" class="com.test.bean.ArtTeacher" primary="true"/>
<bean name="teacher2" class="com.test.bean.ProgramTeacher" autowire-candidate="false"/>
<bean name="student" class="com.test.bean.Student" autowire="byType"/>


生命周期与继承

除了修改构造方法,我们也可以为Bean指定初始化方法和销毁方法,以便在对象创建和被销毁时执行一些其他的任务:

public void init(){
    System.out.println("我是对象初始化时要做的事情!");    
}
public void destroy(){
    System.out.println("我是对象销毁时要做的事情!");
}


通过init-methoddestroy-method来指定:

<bean name="student" class="com.test.bean.Student" init-method="init" destroy-method="destroy"/>


如果Bean不是单例模式,而是采用的原型模式,那么就只会在获取时才创建,并调用init-method,而对应的销毁方法不会被调用(因此,对于原型模式下的Bean,Spring无法顾及其完整生命周期,而在单例模式下,Spring能够从Bean对象的创建一直管理到对象的销毁)

Bean之间也是继承属性的:

public class SportStudent {
    private String name;
    public void setName(String name) {
        this.name = name;
    }
}
public class ArtStudent {
    private String name;
    public void setName(String name) {
        this.name = name;
    }
}


配置Bean之间的继承关系了,我们可以让SportStudent这个Bean直接继承ArtStudent这个Bean配置的属性:

<bean name="artStudent" class="com.test.bean.ArtStudent">
    <property name="name" value="小明"/>
</bean>
<bean class="com.test.bean.SportStudent" parent="artStudent"/>


在ArtStudent Bean中配置的属性,会直接继承给SportStudent Bean(注意,所有配置的属性,在子Bean中必须也要存在,并且可以进行注入,否则会出现错误)

如果子类中某些属性比较特殊,也可以在继承的基础上单独配置:

<bean name="artStudent" class="com.test.bean.ArtStudent" abstract="true">
    <property name="name" value="小明"/>
    <property name="id" value="1"/>
</bean>
<bean class="com.test.bean.SportStudent" parent="artStudent">
    <property name="id" value="2"/>
</bean>


只是希望某一个Bean仅作为一个配置模版供其他Bean继承使用,那么我们可以将其配置为abstract:

<bean name="artStudent" class="com.test.bean.ArtStudent" abstract="true">
    <property name="name" value="小明"/>
</bean>
<bean class="com.test.bean.SportStudent" parent="artStudent"/>


一旦声明为抽象Bean,那么就无法通过容器获取到其实例化对象了

全文Bean属性配置:

整个上下文中所有的Bean都采用某种配置,我们可以在最外层的beans标签中进行默认配置

即使Bean没有配置某项属性,但是只要在最外层编写了默认配置,那么同样会生效,除非Bean自己进行配置覆盖掉默认配置。


工厂模式和工厂Bean

正常情况下需要使用工厂才可以得到Student对象,现在我们希望Spring也这样做,不要直接去反射搞构造方法创建

public class Student {
    Student() {
        System.out.println("我被构造了");
    }
}
public class StudentFactory {
    public static Student getStudent(){
        System.out.println("欢迎光临电子厂");
        return new Student();
    }
}


通过factory-method进行指定:

<bean class="com.test.bean.StudentFactory" factory-method="getStudent"/>


public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
        Student student = context.getBean(Student.class);
        System.out.println(student);
    }
}

Bean类型需要填写为Student类的工厂类,并且添加factory-method指定对应的工厂方法

某些工厂类需要构造出对象之后才能使用:

public class StudentFactory {
    public Student getStudent(){
        System.out.println("欢迎光临电子厂");
        return new Student();
    }
}


将某个工厂类直接注册为工厂Bean,再使用factory-bean来指定Bean的工厂Bean

<bean name="studentFactory" class="com.test.bean.StudentFactory"/>
<bean factory-bean="studentFactory" factory-method="getStudent"/>


Student bean = (Student) context.getBean("studentFactory");
StudentFactory bean = (StudentFactory) context.getBean("&studentFactory");


相关文章
|
7月前
|
前端开发 Java 数据库连接
【Spring-01】Spring简介
【Spring-01】Spring简介
|
7月前
|
前端开发 Java 数据库连接
|
XML Java 数据格式
Spring基础(下)
Spring基础(下)
|
Java 数据库连接 API
01Spring - Spring简介
01Spring - Spring简介
38 0
|
安全 Java 程序员
【Spring】Spring 框架的概述
【Spring】Spring 框架的概述
|
前端开发 Java 数据库连接
Spring-Spring4.X 概述
Spring-Spring4.X 概述
109 0
|
缓存 监控 安全
Spring Boot框架基础介绍
Spring Boot 是一款基于 Spring 框架的开源应用程序开发工具,它旨在简化 Spring 应用程序的配置和开发过程。Spring Boot 提供了一种简单的方式来创建可独立运行的、生产级别的应用程序,并在需要时进行部署。Spring Boot 在微服务架构和云计算环境下得到了广泛应用,本文将介绍 Spring Boot 的特性、优势以及使用方法。
2418 0
|
Java Spring
spring学习5-spring简介
spring学习5-spring简介
89 0
spring学习5-spring简介
|
XML 缓存 Java
Spring系列二:基础篇(2)
​ 目录 IOC IOC 5.说一说什么是IOC?什么是DI? Java 是面向对象的编程语言,一个个实例对象相互合作组成了业务逻辑,原来,我们都是在代码里创建对象和对象的依赖。 所谓的IOC(控制反转):就是由容器来负责控制对象的生命周期和对象间的关系。以前是我们想要什么,就自己创建什么,现在是我们需要什么,容器就给我们送来什么。 引入IOC之前和引入IOC之后 也就是说,控制对象生命周期的不再是引用它的对象,而是容器。对具体对象,以前是它控制其它对象,现在所有对象都被容器控制,所以这就叫控制反转。 控制反转示意图 DI(依赖注入):指的是容器在实例化对象的时候把
106 0
Spring系列二:基础篇(2)
|
设计模式 前端开发 Java
Spring系列一:Spring基础篇
有人说,“Java程序员都是Spring程序员”,小叶秋不太赞成这个观点,但是这也可以看出Spring在Java世界里举足轻重的作用。今天叶秋学长带领小伙伴们一起进入Spring学习体系,还等什么快跟着叶秋学长一起内卷起来~~ 基础 1.Spring是什么?特性?有哪些模块? 2.Spring有哪些模块呢? 3.Spring有哪些常用注解呢? 4.Spring 中应用了哪些设计模式呢?
177 0
Spring系列一:Spring基础篇