0


Spring高手之路3——揭秘Spring依赖注入和SpEL表达式

本篇会给大家举出各种

Spring

属性依赖注入的例子,方便大家理解。

文章目录

1. setter属性注入

1.1 使用XML进行setter方法注入

我们在前面的文章中已经使用过

XML

进行

setter

方法的属性注入了,下面让我们再来回顾一下:

<beanid="userSetter"class="com.example.demo.bean.User"><propertyname="username"value="example-username-setter"/><propertyname="age"value="25"/></bean>

1.2 使用@Bean注解进行setter方法注入

我们在前面的文章中也学习过如何在

bean

创建时通过编程方式设置属性:

@BeanpublicUseruser(){User user =newUser();
    user.setUsername("example-username-anno-setter");
    user.setAge(25);return user;}

1.3 setter方法注入完整代码示例

  • 使用XML进行setter方法注入

首先,我们需要创建一个

User

类,并在其中包含

username

age

两个属性,以及相应的

getter

setter

方法和构造器。

publicclassUser{privateString username;privateInteger age;publicUser(){}// 为了节省篇幅,getter和setter方法省略......@OverridepublicStringtoString(){return"User{username='"+ username +"', age="+ age +"}";}}

对于

XML

方式的

setter

注入和构造器注入,我们需要创建一个配置文件,比如叫

applicationContext.xml

<beansxmlns="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"><!-- setter方法注入 --><beanid="userSetter"class="com.example.demo.bean.User"><propertyname="username"value="example-username-setter"/><propertyname="age"value="25"/></bean></beans>

然后,我们需要创建一个

DemoApplication

类,使用

ApplicationContext

来加载配置文件并获取

Bean

importcom.example.demo.bean.User;importorg.springframework.context.ApplicationContext;importorg.springframework.context.support.ClassPathXmlApplicationContext;publicclassDemoApplication{publicstaticvoidmain(String[] args){ApplicationContext context =newClassPathXmlApplicationContext("applicationContext.xml");User userSetter =(User) context.getBean("userSetter");System.out.println(userSetter);}}

运行结果如下:

在这里插入图片描述

  • 使用@Bean注解进行setter方法注入

我们需要创建一个配置类,例如叫

AppConfig.java

importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;@ConfigurationpublicclassAppConfig{@BeanpublicUseruserSetter(){User user =newUser();
        user.setUsername("example-username-anno-setter");
        user.setAge(25);return user;}}

使用

@Bean

注解来定义

Bean

。每个

@Bean

方法对应于

XML

配置中的一个

<bean>

元素。这个方法的名称就是

Bean

id

,方法的返回值就是

Bean

的类型

然后修改主程序,这里使用

AnnotationConfigApplicationContext

来创建

Spring

的应用上下文,并加载配置类。

Spring

会自动从配置类中获取所有的

Bean

定义,并创建相应的

Bean

实例。

packagecom.example.demo;importcom.example.demo.bean.User;importcom.example.demo.configuration.AppConfig;importorg.springframework.context.ApplicationContext;importorg.springframework.context.annotation.AnnotationConfigApplicationContext;publicclassDemoApplication{publicstaticvoidmain(String[] args){ApplicationContext context =newAnnotationConfigApplicationContext(AppConfig.class);User userSetter =(User) context.getBean("userSetter");System.out.println(userSetter);}}

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

  注意:

XML

配置方式已经相对陈旧,而且在

Spring Boot

项目中,主流的做法是使用注解和

Java

配置方式。对于

setter

注入,有时会引发循环依赖的问题。在

Spring

中,可以使用构造器注入来避免这种情况,这里了解即可。


2. 构造器注入

setter

注入是一种在对象被实例化之后(通过调用无参构造器创建实例)再通过

setter

方法注入依赖的方式。构造器注入则是在创建对象实例的时候就通过构造器参数来注入依赖。

为了演示构造器注入,我们需要给

User

添加一个全参数构造器:

publicUser(String username,Integer age){this.username = username;this.age = age;}

添加这个构造器后,

Java

不再提供默认的无参构造器,这会导致我们之前的

<bean>

标签创建时失败,因为它找不到默认的构造器。

2.1 使用XML进行构造器注入

我们可以在

<bean>

标签内部声明一个子标签:

constructor-arg

。它用于指定构造器的参数,来进行属性注入。

constructor-arg

标签的编写规则如下:

<beanid="userConstructor"class="com.example.demo.bean.User"><constructor-argindex="0"value="example-username-constructor"/><constructor-argindex="1"value="25"/></bean>
index

属性表示构造函数参数的位置,它的值是一个非负整数,其中

0

表示第一个参数,

1

表示第二个参数,以此类推。虽然

value

属性的值总是一个字符串,但是

Spring

会尝试将它转换为构造函数参数所需的类型。例如构造函数的第二个参数是

int

类型,那么

Spring

会尝试将字符串

"25"

转换为整数

25

  使用

index

属性来指定构造函数参数的位置在大多数情况下是可以的,但是如果构造函数的参数数量或者顺序发生了改变,就可能会出错。另外一种更为可靠的方式是使用

name

属性来指定参数的名称,如:

<beanid="userConstructor"class="com.example.demo.bean.User"><constructor-argname="username"value="example-username-constructor"/><constructor-argname="age"value="25"/></bean>

这样无论参数的顺序如何,只要参数名称不变,就不会出错。

2.2 使用@Bean注解进行构造器属性注入

在注解驱动的

bean

注册中,我们也可以直接使用编程方式赋值:

@BeanpublicUseruser(){returnnewUser("example-username-anno-constructor",25);}

2.3 构造器注入的完整代码示例

  • 使用XML进行构造器注入

首先,我们需要创建一个

User

类,并在其中包含

username

age

两个属性,以及相应的

getter

setter

方法和构造器。

publicclassUser{privateString username;privateInteger age;publicUser(){}publicUser(String username,Integer age){this.username = username;this.age = age;}// 为了节省篇幅,getter和setter方法省略......@OverridepublicStringtoString(){return"User{username='"+ username +"', age="+ age +"}";}}

对于

XML

方式的构造器注入,我们需要创建一个配置文件,比如叫

applicationContext.xml

,这里保留

setter

注入方便大家对比

<beansxmlns="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"><!-- setter方法注入 --><!-- setter方法注入 --><!--    <bean id="userSetter" class="com.example.demo.bean.User">--><!--        <property name="username" value="example-username-setter"/>--><!--        <property name="age" value="25"/>--><!--    </bean>--><!-- 构造器注入 --><beanid="userConstructor"class="com.example.demo.bean.User"><constructor-argname="username"value="example-username-constructor"/><constructor-argname="age"value="25"/></bean></beans>

然后,我们需要创建一个

DemoApplication

类,使用

ApplicationContext

来加载配置文件并获取

Bean

packagecom.example.demo;importcom.example.demo.bean.User;importorg.springframework.context.ApplicationContext;importorg.springframework.context.support.ClassPathXmlApplicationContext;publicclassDemoApplication{publicstaticvoidmain(String[] args){ApplicationContext context =newClassPathXmlApplicationContext("applicationContext.xml");//        User userSetter = (User) context.getBean("userSetter");//        System.out.println(userSetter);User userConstructor =(User) context.getBean("userConstructor");System.out.println(userConstructor);}}

运行结果如下:

在这里插入图片描述

  • 使用@Bean注解进行构造器属性注入

我们需要创建一个配置类,例如叫

AppConfig.java

importcom.example.demo.bean.User;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;@ConfigurationpublicclassAppConfig{//    @Bean//    public User userSetter() {//        User user = new User();//        user.setUsername("example-username-anno-setter");//        user.setAge(25);//        return user;//    }@BeanpublicUseruserConstructor(){returnnewUser("example-username-anno-constructor",25);}}

同样,我们需要创建一个

DemoApplication

类,使用

AnnotationConfigApplicationContext

来加载配置类并获取

Bean

importcom.example.demo.bean.User;importcom.example.demo.configuration.AppConfig;importorg.springframework.context.ApplicationContext;importorg.springframework.context.annotation.AnnotationConfigApplicationContext;publicclassDemoApplication{publicstaticvoidmain(String[] args){ApplicationContext context =newAnnotationConfigApplicationContext(AppConfig.class);//        User userSetter = (User) context.getBean("userSetter");//        System.out.println(userSetter);User userConstructor =(User) context.getBean("userConstructor");System.out.println(userConstructor);}}

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

注意:如果在类中同时使用构造器注入和

setter

注入,需要注意它们注入的顺序:先进行构造器注入,然后是

setter

注入。


3. 注解式属性注入

  上面我们已经说过注解式的

setter

和构造器注入。我们又是如何处理那些通过

@Component

扫描而注册的

bean

的属性的呢?我们来仔细说说这个问题,同时展示如何在

xml

中进行相同的操作。

3.1 @Value注解式属性注入的应用

  首先,让我们从最简单的属性注入方法:

@Value

开始。创建一个新的

White

类,并声明一些字段,但是这次我们不会设置

setter

方法:

@ComponentpublicclassWhite{@Value("white-value-annotation")privateString title;@Value("1")privateInteger rank;@OverridepublicStringtoString(){return"White{"+"title='"+ title +'\''+", rank="+ rank +'}';}}

要实现注解式属性注入,我们可以直接在需要注入的字段上添加

@Value

注解:

@Value("white-value-annotation")privateString title;@Value("1")privateInteger rank;

要注意的是,如果使用

@Value

注解来注入一个不存在的属性,那么应用程序会在启动时抛出异常。

然后,我们将通过组件扫描方式将这个

White

类扫描到

IOC

容器中,并将其取出并打印:

publicclassDemoApplication{publicstaticvoidmain(String[] args)throwsException{ApplicationContext ctx =newAnnotationConfigApplicationContext(White.class);White white = ctx.getBean(White.class);System.out.println("Injected value : "+ white);}}

运行

main

方法会看到

White

的字段已经成功注入:

Injected value :White{title='white-value-annotation', rank=1}

3.2 引入外部配置文件@PropertySource

  如果我们需要在

Spring

中使用

properties

文件,我们应该怎么办呢?

Spring

考虑到了这一点,并扩展了一个用于导入外部配置文件的注解:

@PropertySource

  1. 创建Bean和配置文件

创建一个新的

Blue

类,其结构与

White

类完全相同。然后在项目的

resources

目录下创建一个新的

blue.properties

文件,用于存储

Blue

类的属性配置:

blue.title=blue-value-properties
blue.rank=2
  1. 引入配置文件

使用

@PropertySource

注解将

properties

文件导入到配置类:

@Configuration@ComponentScan("com.example")@PropertySource("classpath:blue.properties")publicclassInjectValueConfiguration{}

  这个

blue.properties

文件是一个键值对的列表,

Spring

将这些键值对加载到

Environment

中,我们可以通过

@Value

注解或者

Environment

类的方法来获取这些属性值。

@Value

注解和

Environment

类都可以用于读取

Spring

上下文中的属性值。这些属性值可能来自于多个不同的源,包括但不限于:

  • Spring Boot 的默认配置文件(application.propertiesapplication.yml)。
  • 通过 @PropertySource 注解加载的属性文件。
  • 系统环境变量。
  • Java 系统属性(可以通过 -D 命令行参数设置)。

如果你想通过

@Value

注解来获取属性值,如下:

@ComponentpublicclassBlueConfig{@Value("${blue.title}")privateString title;@Value("${blue.rank}")privateint rank;// getters and setters...}

  在

Spring

应用中使用

@PropertySource

注解来加载一个

.properties

文件时,这个文件中的所有配置项都会被读取,并存储在一个内部的

Map

结构中。这个

Map

的键是配置项的名称,值是配置项的值。

Spring

中的一些内置配置项也会被添加到这个

Map

中。

  当我们使用

${...}

占位符语法来引用一个配置项时,

Spring

会查找这个

Map

,取出与占位符名称相应的配置项的值。例如有一个配置项

blue.title=blue-value-properties

,我们可以在代码中使用

${blue.title}

占位符来引用这个配置项的值。

如果想通过

Environment

类的方法来获取属性值,可以像下面这样做:

@ComponentpublicclassSomeComponent{@AutowiredprivateEnvironment env;publicvoidsomeMethod(){String title = env.getProperty("blue.title");int rank =Integer.parseInt(env.getProperty("blue.rank"));// ...}}

  在上述代码中,

Environment

类的

getProperty

方法用于获取属性值。注意,

getProperty

方法返回的是

String

,所以如果属性是非字符串类型(如

int

),则需要将获取的属性值转换为适当的类型。

  注意:**

@PropertySource

无法加载

YAML

格式的文件**,只能加载

properties

格式的文件。如果需要加载

YAML

格式的文件,而且使用的是

Spring Boot

框架,那么可以使用

@ConfigurationProperties

@Value

注解。例如以下的

YAML

文件:

application.yml

appTest:name: MyApp
  version: 1.0.0

可以使用

@ConfigurationProperties

来加载这些属性:

@Configuration@ConfigurationProperties(prefix ="appTest")publicclassAppConfig{privateString name;privateString version;// getters and setters...}
@ConfigurationProperties

注解主要用于指定配置属性的前缀,

@ConfigurationProperties

注解本身并不直接指定配置文件的位置, 而是由

Spring Boot

的自动配置机制处理的。

  这样,

name

字段就会被自动绑定到

appTest.name

配置属性,

version

字段就会被自动绑定到

appTest.version

配置属性。

  默认情况下,

Spring Boot

会在启动时自动加载

src/main/resources

目录下的

application.properties

application.yml

文件。我们可以通过设置

spring.config.name

spring.config.location

属性来改变默认的配置文件名或位置。

  注意:

@ConfigurationProperties

注解需要配合

@EnableConfigurationProperties

注解或

@Configuration

注解使用,以确保

Spring

能够发现并处理这些注解。

或者,你也可以使用

@Value

注解来加载这些属性:

@ComponentpublicclassAppConfig{@Value("${appTest.name}")privateString name;@Value("${appTest.version}")privateString version;// getters and setters...}
  1. Blue类的属性注入

对于

properties

类型的属性,我们这里选择

@Value

注解和占位符来注入属性:

@Value("${blue.title}")privateString title;@Value("${blue.rank}")privateInteger rank;

如果你熟悉

jsp

el

表达式,会发现这和它非常相似!

  1. 测试启动类

修改启动类,将配置类引入,然后取出并打印

Blue

publicstaticvoidmain(String[] args)throwsException{ApplicationContext ctx =newAnnotationConfigApplicationContext(InjectValueConfiguration.class);Blue blue = ctx.getBean(Blue.class);System.out.println("Properties value : "+ blue);}

运行

main

方法会看到控制台已经成功打印出了配置文件的属性:

Properties value :Blue{title='blue-value-properties', rank=2}

3.3 在XML中引入外部配置文件

xml

中,我们可以和

@Value

相同的方式使用占位符:

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd"xmlns:context="http://www.springframework.org/schema/context"><!-- 相当于注解中的 @PropertySource("classpath:blue.properties") --><context:property-placeholderlocation="classpath:blue.properties"/><beanclass="com.example.demo.bean.Blue"><propertyname="title"value="${blue.title}"/><propertyname="rank"value="${blue.rank}"/></bean></beans>

3.4 注解式属性注入完整代码示例

  • @Value注解式属性注入的应用

创建

White

类:

packagecom.example.demo.bean;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.stereotype.Component;@ComponentpublicclassWhite{@Value("white-value-annotation")privateString title;@Value("1")privateInteger rank;@OverridepublicStringtoString(){return"White{"+"title='"+ title +'\''+", rank="+ rank +'}';}}

创建启动类

InjectValueAnnotationApplication

packagecom.example.demo;importcom.example.demo.bean.White;importorg.springframework.context.ApplicationContext;importorg.springframework.context.annotation.AnnotationConfigApplicationContext;publicclassDemoApplication{publicstaticvoidmain(String[] args)throwsException{ApplicationContext ctx =newAnnotationConfigApplicationContext(White.class);White white = ctx.getBean(White.class);System.out.println("Injected value : "+ white);}}

运行结果如下:

在这里插入图片描述

  • 引入外部配置文件@PropertySource

创建

Blue

类和配置文件,没有

setter

getter

方法:

packagecom.example.demo.bean;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.stereotype.Component;@ComponentpublicclassBlue{@Value("${blue.title}")privateString title;@Value("${blue.rank}")privateInteger rank;@OverridepublicStringtoString(){return"Blue{"+"title='"+ title +'\''+", rank="+ rank +'}';}}
resources

目录下的

blue.properties

文件:

blue.title=blue-value-properties
blue.rank=2

创建配置类

InjectValueConfiguration

packagecom.example.demo.configuration;importorg.springframework.context.annotation.ComponentScan;importorg.springframework.context.annotation.Configuration;importorg.springframework.context.annotation.PropertySource;@Configuration@ComponentScan("com.example")@PropertySource("classpath:blue.properties")publicclassInjectValueConfiguration{}

修改启动类,引入配置类:

packagecom.example.demo;importcom.example.demo.bean.Blue;importcom.example.demo.configuration.InjectValueConfiguration;importorg.springframework.context.ApplicationContext;importorg.springframework.context.annotation.AnnotationConfigApplicationContext;publicclassDemoApplication{publicstaticvoidmain(String[] args)throwsException{ApplicationContext ctx =newAnnotationConfigApplicationContext(InjectValueConfiguration.class);Blue blue = ctx.getBean(Blue.class);System.out.println("Properties value : "+ blue);}}

运行结果如下:

在这里插入图片描述

  • 在xml中引入外部配置文件

  在使用

XML

配置的情况下,我们需要创建一个

XML

文件来替代

InjectValueConfiguration

类,我们可以先注释掉

InjectValueConfiguration

类的所有内容

下面是相应的

XML

文件内容:

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd"xmlns:context="http://www.springframework.org/schema/context"><!-- 相当于注解中的 @PropertySource("classpath:blue.properties") --><context:property-placeholderlocation="classpath:blue.properties"/><beanclass="com.example.demo.bean.Blue"><propertyname="title"value="${blue.title}"/><propertyname="rank"value="${blue.rank}"/></bean></beans>

  在这里我们使用了

context:property-placeholder

标签来导入外部的

properties

文件,然后使用

${...}

占位符语法来引用配置文件中的属性值。这样无论是选择用注解方式还是

XML

方式,都可以方便地在

Spring

中使用外部配置文件。

这里还需要修改下

Blue

类,因为通过

XML

方法注入属性需要提供相应的

setter

方法,修改后的

Blue

类如下:

packagecom.example.demo.bean;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.stereotype.Component;@ComponentpublicclassBlue{@Value("${blue.title}")privateString title;@Value("${blue.rank}")privateInteger rank;publicStringgetTitle(){return title;}publicvoidsetTitle(String title){this.title = title;}publicIntegergetRank(){return rank;}publicvoidsetRank(Integer rank){this.rank = rank;}@OverridepublicStringtoString(){return"Blue{"+"title='"+ title +'\''+", rank="+ rank +'}';}}

然后,我们需要修改启动类,使用

XmlApplicationContext

代替

AnnotationConfigApplicationContext

packagecom.example.demo;importcom.example.demo.bean.Blue;importorg.springframework.context.ApplicationContext;importorg.springframework.context.annotation.ComponentScan;importorg.springframework.context.support.ClassPathXmlApplicationContext;@ComponentScan("com.example")publicclassDemoApplication{publicstaticvoidmain(String[] args)throwsException{ApplicationContext ctx =newClassPathXmlApplicationContext("classpath:injectValueContext.xml");Blue blue = ctx.getBean(Blue.class);System.out.println("Properties value : "+ blue);}}

运行结果如下:

在这里插入图片描述

4. SpEL表达式

  当我们谈到属性注入的时候,我们可能会遇到一些复杂的需求,例如我们需要引用另一个

Bean

的属性,或者我们需要动态处理某个属性值。这种需求无法通过使用

${}

的占位符方式实现,我们需要一个更强大的工具:

SpEL

表达式。

Spring Expression Language

SpEL

)是从

Spring

框架

3.0

开始支持的强大工具。

SpEL

不仅是

Spring

框架的重要组成部分,也可以独立使用。它的功能丰富,包括调用属性值、属性参数、方法调用、数组存储以及逻辑计算等。它与开源项目

OGNL

Object-Graph Navigation Language

)相似,但

SpEL

Spring

框架推出的,并默认内嵌在

Spring

框架中。

4.1 使用@Value注解和SpEL表达式实现属性注入

SpEL

的表达式用

#{}

表示,花括号中就是我们要编写的表达式。

  我们创建一个

Bean

,命名为

Azure

,同样地,我们声明属性

name

priority

,并提供

getter

setter

方法以及

toString()

方法。然后我们使用

@Component

注解标注它。

使用

@Value

配合

SpEL

完成属性注入,如下:

@ComponentpublicclassAzure{@Value("#{'spel-for-azure'}")privateString name;@Value("#{10}")privateInteger priority;}

我们修改启动类,从

IOC

容器中获取

Azure

并打印,可以看到属性被成功注入:

Azure{name='spel-for-azure', priority=10}
SpEL

的功能远不止这些,它还可以获取

IOC

容器中其他

Bean

的属性,让我们来展示一下。

  我们已经注册了

Azure Bean

,现在我们再创建一个

Bean

,命名为

Emerald

。我们按照上述方法对字段和方法进行声明,然后使用

@Component

注解标注。

  我们希望

name

属性直接复制

Azure

name

属性,而

priority

属性则希望比

Azure

priority

属性大

1

,我们可以这样编写:

@ComponentpublicclassEmerald{@Value("#{'copy of ' + azure.name}")privateString name;@Value("#{azure.priority + 1}")privateInteger priority;}

  在

Spring

SpEL

中可以通过

bean

的名称访问到对应的

bean

,并通过

.

操作符访问

bean

的属性。在这个例子中,

azure

就是一个

bean

的名称,它对应的

bean

就是

Azure

类的实例。所以,

azure.name

就是访问

Azure

类实例的

name

属性。

如果你在一个不涉及

Spring

的环境中使用

SpEL

,这个特性是不会生效的。这是因为这个特性依赖于

Spring

IoC

容器。

我们修改启动类,测试运行,可以看到

Azure

的属性已经成功被复制:

use spel bean property :Emerald{name='copy of spel-for-azure', priority=11}
SpEL

表达式不仅可以引用对象的属性,还可以直接引用类的常量,以及调用对象的方法。下面我们通过示例进行演示。

  我们新建一个

Bean

,命名为

Ivory

。我们按照上述方法初始化属性、

toString()

方法、注解。

  假设我们有一个需求,让

name

azure

属性的前

3

个字符,

priority

Integer

的最大值。那么我们可以使用

SpEL

这样写:

@ComponentpublicclassIvory{@Value("#{azure.name.substring(0, 3)}")privateString name;@Value("#{T(java.lang.Integer).MAX_VALUE}")privateInteger priority;}

注意,直接引用类的属性,需要在类的全限定名外面使用

T()

包围。

我们修改启动类,测试运行,可以看到

Ivory

的属性已经是处理之后的值:

use spel methods :Ivory{name='spe', priority=2147483647}

4.2 在XML中使用SpEL表达式实现属性注入:

<beanid="ivory"class="com.example.demo.bean.Ivory"><propertyname="name"value="#{azure.name.substring(0, 3)}"/><propertyname="priority"value="#{T(java.lang.Integer).MAX_VALUE}"/></bean>

学习

SpEL

表达式不需要花费大量的精力,掌握基础的使用方法即可。

4.3 SpEL表达式属性注入完整代码示例

  • 使用@Value注解和SpEL表达式实现属性注入

创建三个

SpEL

表达式属性注入的

Bean

Azure.java

Emerald.java

Ivory.java

Azure.java:

packagecom.example.demo.bean;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.stereotype.Component;@ComponentpublicclassAzure{@Value("#{'spel-for-azure'}")privateString name;@Value("#{10}")privateInteger priority;publicStringgetName(){return name;}publicvoidsetName(String name){this.name = name;}publicIntegergetPriority(){return priority;}publicvoidsetPriority(Integer priority){this.priority = priority;}@OverridepublicStringtoString(){return"Azure{"+"name='"+ name +'\''+", priority="+ priority +'}';}}

Emerald.java:

packagecom.example.demo.bean;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.stereotype.Component;@ComponentpublicclassEmerald{@Value("#{'copy of ' + azure.name}")privateString name;@Value("#{azure.priority + 1}")privateInteger priority;publicStringgetName(){return name;}publicvoidsetName(String name){this.name = name;}publicIntegergetPriority(){return priority;}publicvoidsetPriority(Integer priority){this.priority = priority;}@OverridepublicStringtoString(){return"Emerald{"+"name='"+ name +'\''+", priority="+ priority +'}';}}

Ivory.java:

packagecom.example.demo.bean;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.stereotype.Component;@ComponentpublicclassIvory{@Value("#{azure.name.substring(0, 3)}")privateString name;@Value("#{T(java.lang.Integer).MAX_VALUE}")privateInteger priority;publicStringgetName(){return name;}publicvoidsetName(String name){this.name = name;}publicIntegergetPriority(){return priority;}publicvoidsetPriority(Integer priority){this.priority = priority;}@OverridepublicStringtoString(){return"Ivory{"+"name='"+ name +'\''+", priority="+ priority +'}';}}

MyBean.java

@ComponentpublicclassMyBean{@AutowiredprivateAzure azure;@AutowiredprivateEmerald emerald;@AutowiredprivateIvory ivory;publicvoidinit(){System.out.println(azure);System.out.println(emerald);System.out.println(ivory);}}
MyBean

是一个用于展示如何在

Spring

中通过

SpEL

表达式来注入属性的类,它聚合了三个对象

Azure

,

Emerald

Ivory

,并通过

Spring

的依赖注入机制将这三个对象注入到了

MyBean

类的实例中

主程序

DemoApplication
@SpringBootApplicationpublicclassDemoApplication{publicstaticvoidmain(String[] args){ApplicationContext applicationContext =SpringApplication.run(DemoApplication.class, args);MyBean myBean = applicationContext.getBean(MyBean.class);
        myBean.init();}}

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

  • 在XML中使用SpEL表达式实现属性注入

  对于

XML

配置,

Spring

还支持在

bean

定义中使用

SpEL

首先,需要创建一个

Spring XML

配置文件,我们将其命名为

app-config.xml

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd"><context:component-scanbase-package="com.example"/><beanid="azure"class="com.example.demo.bean.Azure"><propertyname="name"value="#{'spel-for-azure'}"/><propertyname="priority"value="#{10}"/></bean><beanid="emerald"class="com.example.demo.bean.Emerald"><propertyname="name"value="#{'copy of ' + azure.name}"/><propertyname="priority"value="#{azure.priority + 1}"/></bean><beanid="ivory"class="com.example.demo.bean.Ivory"><propertyname="name"value="#{azure.name.substring(0, 3)}"/><propertyname="priority"value="#{T(java.lang.Integer).MAX_VALUE}"/></bean></beans>

注意:在

XML

中使用

SpEL

需要使用

#{}

,而不是

${}

  然后修改这

3

Bean

,如果是使用

XML

来配置

Spring

Bean

的话,那么在

Java

类中就不需要使用

@Component

注解了。因为

XML

配置文件已经明确地告诉

Spring

这些类是

Spring Bean

  同样的,如果在

XML

文件中定义了

Bean

的属性值,那么在

Java

类中就不需要使用

@Value

注解来注入这些值了。因为

XML

配置文件已经明确地为这些属性赋了值。

Azure.java

packagecom.example.demo.bean;publicclassAzure{privateString name;privateInteger priority;publicStringgetName(){return name;}publicvoidsetName(String name){this.name = name;}publicIntegergetPriority(){return priority;}publicvoidsetPriority(Integer priority){this.priority = priority;}@OverridepublicStringtoString(){return"Azure{"+"name='"+ name +'\''+", priority="+ priority +'}';}}

Emerald.java

packagecom.example.demo.bean;publicclassEmerald{privateString name;privateInteger priority;publicStringgetName(){return name;}publicvoidsetName(String name){this.name = name;}publicIntegergetPriority(){return priority;}publicvoidsetPriority(Integer priority){this.priority = priority;}@OverridepublicStringtoString(){return"Emerald{"+"name='"+ name +'\''+", priority="+ priority +'}';}}

Ivory.java

packagecom.example.demo.bean;publicclassIvory{privateString name;privateInteger priority;publicStringgetName(){return name;}publicvoidsetName(String name){this.name = name;}publicIntegergetPriority(){return priority;}publicvoidsetPriority(Integer priority){this.priority = priority;}@OverridepublicStringtoString(){return"Ivory{"+"name='"+ name +'\''+", priority="+ priority +'}';}}

然后需要在主程序中导入这个

XML

配置文件,这可以通过在主程序中添加

@ImportResource

注解实现:

packagecom.example.demo;importcom.example.demo.bean.MyBean;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.context.ApplicationContext;importorg.springframework.context.annotation.ImportResource;@SpringBootApplication@ImportResource("classpath:app-config.xml")publicclassDemoApplication{publicstaticvoidmain(String[] args){ApplicationContext applicationContext =SpringApplication.run(DemoApplication.class, args);MyBean myBean = applicationContext.getBean(MyBean.class);
        myBean.init();}}

这样就可以在

Spring

XML

配置文件中使用

SpEL

了。

运行结果如下:

在这里插入图片描述


欢迎一键三连~

有问题请留言,大家一起探讨学习

----------------------Talk is cheap, show me the code-----------------------


本文转载自: https://blog.csdn.net/qq_34115899/article/details/131032009
版权归原作者 砖业洋__ 所有, 如有侵权,请联系我们删除。

“Spring高手之路3——揭秘Spring依赖注入和SpEL表达式”的评论:

还没有评论