Java
Spring

Spring

第一个 Spring 项目

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>6.1.0</version>
</dependency>

spring-config.xml中定义一个Java 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 http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean name="student" class="com.test.bean.Student"/>
</beans>

Main中获取Spring上下文,并申请对象

public static void main(String[] args) {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
    Student student = context.getBean(Student.class);
    student.hello();
}

Bean 注册与配置

Bean在定义与获取时不能出现歧义,不同的Beanname不能够相同

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

可以使用alias标签为Bean定义别名

<alias name="student" alias="stu"/>

Spring中,对象默认是以单例模式被创建的,可指定scopeprototype使其变更为原型模式(多例)

<bean name="student" class="com.test.bean.Student" scope="prototype"/>

也可以通过lazy-init属性,使得Bean在被需要时再创建

或使用depends-on来指定加载顺序

依赖注入

属性注入

使用属性注入时,需要对应属性拥有其Setter方法

<bean name="student" class="com.test.bean.Student">
    <property name="stuName" value="Cherry"/>
    <property name="stuAge" value="10"/>
    <property name="stuId" value="10"/>
</bean>

构造器注入

可以使用constructor-arg进行构造器注入,但是参数顺序需要和带参构造函数保持一致

Spring将会自动匹配指定参数类型,指定参数数量的构造方法

<bean name="student" class="com.test.bean.Student">
    <constructor-arg name="stuId" value="10"/>
    <constructor-arg name="stuName" value="Cherry"/>
    <constructor-arg name="stuAge" value="10" type="int"/>
</bean>

注入集合类型

Spring对集合类型拥有特别的支持

<!-- List类型 -->
<bean name="student" class="com.test.bean.Student">
    <property name="studentTeachers">
        <list>
            <value>A</value>
            <value>B</value>
            <value>C</value>
        </list>
    </property>
</bean>
<!-- Map类型 -->
<bean name="student" class="com.test.bean.Student">
    <property name="studentTeachers">
        <map>
            <entry key="A" value="a"/>
            <entry key="B" value="b"/>
            <entry key="C" value="c"/>
        </map>
    </property>
</bean>

自动装配

可以开启自动装配,属性值将会由IoC容器自动装配,同时也可以按属性名注入或者按构造器注入

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

Bean发生歧义时,可以使用autowire-candidate使得一个Bean不参与自动注入,或者使用primary使得Bean被优先选择

生命周期与继承

可以使用init-methoddestory-method方法指定初始化方法和销毁方法,能够在对象被初始化和销毁时调用指定的方法

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

需要注意的是,这种生命周期只对单例模式生效,而原型模式Spring无法顾及其所有生命周期

继承

Spring中同样拥有继承,但这种继承是属性的继承,而不是类的继承

<bean name="student" class="com.test.bean.Student">
    <property name="stuId" value="10"/>
    <property name="stuName" value="Cherry"/>
    <property name="stuAge" value="10"/>
</bean>
<bean name="student2" class="com.test.bean.Student" parent="student"/>

对于特殊的属性,可以使用属性注入的方式(property)特别指定

可以使用abstract将一个Bean定义为抽象Bean,此时容器将不再为这个Bean创建对象,而是将其作为Bean的模板

如果希望给所有的Bean应用默认配置,可以在最外层的beans标签中定义

工厂模式和 Bean

Spring中,可以定义工厂,使得在创建Bean时透过工厂来创建

若创建Bean不需要实例化工厂类

<bean name="student" class="com.test.factory.StudentFactory" factory-method="getStudent"/>
System.out.println(context.getBean("student")); //直接获取Bean

若创建Bean需要实例化工厂类

<bean name="studentFactory" class="com.test.factory.StudentFactory"/>
<bean factory-bean="studentFactory" factory-method="getStudent"/>
System.out.println(context.getBean("studentFactory"));

或者可以让其实现FactoryBean接口

public class StudentFactory implements FactoryBean<Student> {
    @Override
    public Student getObject() {
        return null;
    }
 
    @Override
    public Class<?> getObjectType() {
        return null;
    }
}

值得注意的是,此时通过名称直接获取Bean对象返回的将会是FactoryBean所生产出的对象,若需要获取FactoryBean本身可以加上&

StudentFactory studentFactory = (StudentFactory) context.getBean("&student");

使用注解开发

Spring中,可以使用配置类 + 注解 的方式代替配置文件

@Configuration
public class MainConfiguration {
    @Bean("student")
    public Student student() {
        return new Student();
    }
}
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfiguration.class);

同时也可以通过@Import注解来导入其它的配置类

可以在@Bean注解中直接指定autowireCandidateinitMethoddestroyMethod

也能够使用@Lazy@DependsOn@Scope等注解来修饰

对于需要使用到其他类的属性注入或者构造函数注入,可以直接将其作为参数放入构造方法中

自动装配

也可以使用@Autowired来自动装配,它不仅仅能够用于字段,同时也能用于构造方法或Setter

@Autowired默认使用byType的方式装配,若出现了多个同类型的Bean可以使用@Qualifier按名称匹配

@Autowired
private Teacher stuTeacher;

Jakarta 中的注解

使用jakarta.annotation中的注解需要额外导入依赖坐标

<dependency>
    <groupId>jakarta.annotation</groupId>
    <artifactId>jakarta.annotation-api</artifactId>
    <version>2.1.1</version>
</dependency>

@Resource@Autowired的用法相同,但:

@Resouce默认ByName,找不到则ByType,可以添加到Setter、字段上

@Autowired默认是ByType,只会根据类型查找,可以添加到构造方法、Setter、字段、方法参数上

@Resource
private Teacher stuTeacher;

此外还有@PostConstruct@PreDestroy,它们的作用和init-methoddestroy-method一致

@Compoent

@Compent不同于@Bean,将通过反射的方式来创建对象,但是需要配置包扫描

使用@Compoent时,若构造函数不是默认无参构造,则默认会给每一个参数都进行自动注入

name属性没有被指定,则默认将会遵循驼峰命名法赋予默认值