3.5运行时值注入

讨论依赖注入的时候,我们通常所讨论的是将一个Bean的引用注入到另一个Bean的属性或构造器参数中。它通常来讲指的是将一个对象与另一个对象关联。

另一个方面,将一个值注入到Bean的属性或者构造器参数中!

public class SgtPeppers implements CompactDisc, BeanNameAware
{

    private String title = "Sgt. Pepper's Lonely Hearts Club Band";
    private String artist = "The Beatles";

    public void play() {
        System.out.println("Playing" + title + "by" + artist);
    }

    public void setBeanName(String s) {
        System.out.println(s);
    }
}

之前我们是使用硬编码的模式,把string写死。

我们有的时候想要在运行的时候再确定到底想要什么值注入进去。

Spring有两种在运行的时候求值的方式:

  1. 属性占位符
  2. spring表达式

3.5.1 注入外部的值

需要注入的值可以放在一个外部的properties文件当中,这些属性文件会加载到Spring的Environment中

disc.title=Sgt. Pepper's Lonely Hearts Club Band
disc.artist=The Beatles

运行是注入:

@Configuration
@PropertySource("classpath:app.properties")
public class ExpressiveConfig {

    @Autowired
    Environment environment;

    @Bean
    public BlankDisc disc (){
        return new BlankDisc(environment.getProperty("disc.title"), environment.getProperty("disc.artist"));
    }
}

深入学习Spring的environment

getProperty()并不是唯一一个获取属性的方法:

String getProperty(String key)

String getProperty(String key, String defalutValue) //在获取不到的时候返回默认值

T getProperty(String key, Class<T> type) //可以进行类型转换,传入Integer.class就可以返回Int

T getProperty(String key, Class<T> type, T defaultValue)

 

除了属性相关功能之外,

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ExpressiveConfig.class)
@ActiveProfiles("dev") //我们开启dev
//@ComponentScan
public class TestAdv {

    @Autowired
    @Qualifier("disc")
    CompactDisc compactDisc;

    @Test
    public void testFun() {
        System.out.println(compactDisc);
        compactDisc.play();
    }

}

@Configuration
@PropertySource("classpath:app.properties")
public class ExpressiveConfig {

    @Autowired
    Environment environment;

    @Bean
    public BlankDisc disc (){
        System.out.println(Arrays.deepToString(environment.getActiveProfiles()));
        System.out.println(environment.acceptsProfiles("dev"));
        return new BlankDisc(environment.getProperty("disc.title"), environment.getProperty("disc.artist"));
    }
}

运行结果

[dev]
true
SPEL.BlankDisc@6c80d78a
Playing Sgt. Pepper's Lonely Hearts Club Band by The Beatles
--------track------

我们开启了dev这个环境后,在env里面就可以获得profile [dev], acceptProfiles 这个方法则是用来判断你传入的字符串数组,这里是【dev】是不是被激活的。

之前那个conditional的例子里面用到过,

class ProfileCondition implements Condition {

	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
		if (attrs != null) {
			for (Object value : attrs.get("value")) {
				if (context.getEnvironment().acceptsProfiles((String[]) value)) {
					return true;
				}
			}
			return false;
		}
		return true;
	}

}

从context中可以拿到env,就像我们上面看的那样,是环境。

从metaData,可以获取这个Bean上所有的注解,getAllAnnotationAttributes拿到所有profile相关的注解,然后再拿value,就可以拿到profile的数组

最后调用acceptProfile来判断@Profile上面标注的环境和context里面的环境是不是一样的,一样的才产生这个bean。

3.5.2解析属性占位符

Spring一直支持将属性定义到外部的属性文件中,并使用占位符值将其插入到SpringBean中。${...}是占位符的形式,以下是例子,

   自动扫描
 public BlankDisc(@Value("${disc.title}") String title, @Value("${disc.artist}") String artist) {
        this.title = title;
        this.artist = artist;
    }

    手动声明

    @Bean
    public BlankDisc disc (@Value("${disc.title}") String title, @Value("${disc.artist}") String artist){
        System.out.println(Arrays.deepToString(environment.getActiveProfiles()));
        System.out.println(environment.acceptsProfiles("dev"));
//        return new BlankDisc(environment.getProperty("disc.title"), environment.getProperty("disc.artist"));
        return new BlankDisc(title, artist);
    }

3.5.3 使用Spring表达式语言进行装配

SpEL拥有很多特性,包括:

使用bean的id来引用bean;

调用方法和访问对象的属性;

对值进行算数,关系和逻辑运算;

正则表达式匹配;

集合操作

和占位符不同的是,Spring表达式需要放在 #{....}中 

例子:这个systemProperties是自带的变量,似乎需要放在虚拟机参数里面。-Ddisc.artist=li 放在外部的文件中似乎不管用???

SPEL 基础

  1. 表示字面值 #{3.1415}
  2. 引用bean、属性和方法
  3. 在表达式中使用类型
  4. Spel运算符
  5. 计算正则表达式
  6. 计算集合

2,引用bean属性和方法

@Component
public class CDPlayer {

    public CompactDisc compactDisc;

    public CDPlayer(@Value("#{blankDisc}") CompactDisc compactDisc) {
        this.compactDisc=compactDisc;
    }
}

    public CDPlayer(@Value("#{blankDisc}") CompactDisc compactDisc, @Value("#{blankDisc.getArtist()?.toUpperCase()}") String artist) {
        this.compactDisc=compactDisc;
        this.artist=artist;
    }

3,在表达式中使用类型

    public CDPlayer(@Value("#{blankDisc}") CompactDisc compactDisc, @Value("#{T(java.lang.Math).PI}") String artist) {
        this.compactDisc=compactDisc;
        this.artist=artist;
    }

4,SpEL运算符

   public CDPlayer(@Value("#{blankDisc ?: 'Rattle and Hum'}") CompactDisc compactDisc, @Value("#{T(java.lang.Math).PI}") String artist) {
        this.compactDisc=compactDisc;
        this.artist=artist;
    }

这个好像没有什么特别的,就只有上面的那个可以判断 ?:是不是空 如果是空的话就会返回'Rattle and Hum'

5,正则表达式

太复杂了,不赘述

6, 计算集合 

    @Value("#{jukeBox.songs[2].title}")
    String value;

    @Value("#{jukeBox.songs.$[artist == 'qu']}")
    Song list;

    @Value("#{jukeBox.songs.^[artist == 'qu']}")
    Song list;

    @Value("#{jukeBox.songs.![artist]}")
    List<String> names;

    @Value("#{jukeBox.songs.?[artist == 'qu']}")
    List<Song> names;

SPEL可以通过【】来获取集合中的元素,第二个是可以获取艺术家是qu的最后一个元素,第三个是第一个元素,第四是投影,可以用song.artist新建一个list,第五个是过滤一个艺术家是qu的list。

Spring 表达式很强大,但是也不要整的太复杂,毕竟不要debug。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值