高级装配

一、环境与Profile

一)配置profile bean

环境的改变导致配置改变(需求:通过环境决定使用哪个bean),可以通过Spring的Profile解决。

Profile可以在程序运行时根据环境的改变决定使用哪个bean。所以一个部署单元能适应所有环境。

1.在Java文件中配置 

@Configuration
public class UserConfig {
@Bean
@Profile("dev") //dev激活时才创建使用该bean
public User devUser() {
return new User("devUser", 110);
}
@Bean
@Profile("pro")
public User proUser(){
return new User("proUser", 110);
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = UserConfig.class)
@ActiveProfiles("dev") //指定测试时使用的bean
public class TestAll {
@Autowired
private User user;
@Test
public void doSth() {
System.out.println(user.getName() + " : " + user.getPhone()); //devUser : 110
}
}

2.在xml中配置

<?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" profile="dev">
<bean class="entity.User">
<constructor-arg name="name" value="devUserXml"/>
<constructor-arg name="phone" value="111"/>
</bean>
</beans>

方式二:

<?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">
<beans profile="dev">
<bean class="entity.User">
<constructor-arg name="name" value="devUserXml2"/>
<constructor-arg name="phone" value="11111"/>
</bean>
</beans>
<beans profile="pro">
<bean class="entity.User">
<constructor-arg name="name" value="proUserXml2"/>
<constructor-arg name="phone" value="222"/>
</bean>
</beans>
</beans>

二)激活Profile

首先要配置两个独立的属性:

1.spring.profiles.active

2.Spring.profiles.default

有多种方式设置这两种属性,具体设置方式请查阅相关文档,注意:

如果设置成了spring.profiles.active后,spring.profiles.default设置成什么值都无所谓,系统优先使用前者的设置。

二、条件化的bean

如果我们要求:一个或者多个bean

1.在类路径下包含特定的的库时

2.在某个特定的bean声明之后

3.特定的环境变量设置之后

才创建。显然profile不能满足要求。

我们可以使用@Condtional注解。

@Configuration
public class UserConfigWithCondition {
@Bean
//如果给定类中的matches方法返回true就创建此bean
@Conditional(MyCondition.class)
public User conditionUser() {
return new User("conditionUser", 22);
}
}
/*
* 必须实现Condition接口
* */
public class MyCondition implements Condition{
public boolean matches(ConditionContext conditionContext,
AnnotatedTypeMetadata annotatedTypeMetadata) {
return true;
}
}
public interface ConditionContext {
//返回的类可检查bean的定义
BeanDefinitionRegistry getRegistry();
//返回类可检查bean是否存在,甚至探测其属性
@Nullable
ConfigurableListableBeanFactory getBeanFactory();
//检查环境变量
Environment getEnvironment();
//探查ResourceLoader所加载的资源
ResourceLoader getResourceLoader();
@Nullable
ClassLoader getClassLoader();
}
public interface AnnotatedTypeMetadata {
//是否有给定名字的注解
boolean isAnnotated(String var1);
@Nullable
Map<String, Object> getAnnotationAttributes(String var1);
@Nullable
Map<String, Object> getAnnotationAttributes(String var1, boolean var2);
@Nullable
MultiValueMap<String, Object> getAllAnnotationAttributes(String var1);
@Nullable
MultiValueMap<String, Object> getAllAnnotationAttributes(String var1, boolean var2);
}

三)处理自动装配的歧义性

如果有多个bean能够匹配结果的话,这种歧义性会阻碍Springle的自动装配。

解决方案:

1.指定首选的bean:

多个bean情况

@Configuration
public class UserConfig {
@Bean
public User user() {
return new User("firstUser", 1);
}
@Bean
@Primary
public User user2() {
return new User("secondUser", 2);
}
@Bean
public User user3() {
return new User("thirdUser", 3);
}
}
@Autowired
private User user;
@Test
public void doSth() {
System.out.println(user.getName() + " : " + user.getPhone()); //secondUser : 2
}

多个实现类的情况:

public interface Schooler {
void introduce();
} @Component
@Primary
public class Teacher implements Schooler{
public void introduce() {
System.out.println("I'm a teacher.");
}
} @Component
public class Student implements Schooler{
public void introduce() {
System.out.println("I'm a student.");
}
} @Component
public class Worker implements Schooler{
public void introduce() {
System.out.println("I'm a worker." );
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AutoConfig.class)
public class TestAll {
@Autowired
private Schooler schooler;
@Test
public void t() {
schooler.introduce(); //I'm a teacher.
}
}

2.限定自动装配的Bean 

1)根据bean的id

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AutoConfig.class)
public class TestAll {
@Autowired
@Qualifier("student") //根据bean的id来注入,这里使用的是默认id
private Schooler schooler;
@Test
public void t() {
schooler.introduce(); //I'm a student.
}
}

创建自定义限定符:

@Configuration
public class UserConfig {
@Bean
@Qualifier("First")
public User user() {
return new User("firstUser", 1);
}
@Bean
@Qualifier("Second")
public User user2() {
return new User("secondUser", 2);
}
@Bean
@Qualifier("Third")
public User user3() {
return new User("thirdUser", 3);
}
}
@Autowired
@Qualifier("First")
private User user;
@Test
public void test() {
System.out.println(user.getName()); //firstUser
}

三)Bean的作用域

默认情况下,Spring应用中所有bean都是作为单例形式创建的。

Spring创建了多种作用域,可以基于这些作用域创建bean。

单例(Singleton):

原型(Prototype):每次注入或者通过上下文获取的时候,都会创建一个新的实例。

会话(Session):在Web应用中,为每个会话创建一个bean实例。

请求(request):在Web应用中,为每个请求创建一个bean实例。

其他略

四)运行时注入

为了注入字面量,且要避免硬编码(让这些值在运行时确定),Spring提供了两种运行时求值得方法:

1)属性占位符

2)Spring表达式语言(SpEl)

1.处理外部值

处理外部值最简单的方式是声明属性源并通过Spring的Environment来检索属性。

app.properties:

name = tang
@Configuration
@PropertySource("classpath:/app.properties")
public class UserConfig {
@Autowired
private Environment e;
@Bean
public User user() {
return new User(e.getProperty("name"), 22);
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = UserConfig.class)
public class TestAll {
@Autowired
User user;
@Test
public void t() {
System.out.println(user.getName()); //tang
}
}

xml中配置:

<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>app.properties</value>
</list>
</property>
</bean>
<bean class="entity.User" c:name="${aName}" c:phone="22"/>

如果我们使用组件扫描和和自动装配的话,可以使用@Value来实现:

@Component
@PropertySource("classpath:/app.properties")
public class Worker implements Schooler{
private String name;
private int phone;
public Worker(@Value("${name}") String name, @Value("${phone}") int phone) {
this.name = name;
this.phone = phone;
}
public void introduce() {
System.out.println("I'm a worker. And my name is " + name);
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AutoConfig.class)
public class TestAll {
@Autowired
Worker worker;
@Test
public void t() {
worker.introduce(); //I'm a worker. And my name is tang
}
}

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

Spring Expression Language(SqEl)能将值装配到bean属性和构造器参数中,表达式会在运行时得到值。

在装配bean的时候如何使用这些表达式:

1)通过XML使用:

<bean id="aUser" class="entity.User">
<constructor-arg name="name" value="Peter"/>
<constructor-arg name="id" value="222"/>
</bean>
<bean id="sys" class="entity.System">
<property name="name" value="aSystem"/>
<property name="user" value="#{aUser}"/>
</bean>

2)通过自动扫描:

@Component("userBean")
public class User {
@Value("tom")
private String name;
@Value("111")
private int id; public User(String name, int id) {
this.name = name;
this.id = id;
}
}
@Component("sys")
public class System {
@Value("#{userBean}")
private User user;
@Value("TarSys")
private String name; @Override
public String toString() {
return "System " + name + " have a user named " + user.getName();
}
}

基础表达式:

1)表示字面量

#{3.14159}

#{9.18E4}

#{‘Hello’}

#{true}

2)引用bean的属性方法

#{user.name}

#{user.getName()}

#{user.getName().toUpperCase()}

#{user.getName().?toUpperCase()}   //保证左边的值不为null,如果为null不调用右边的方法,直接返回null

3)表达式中使用类型

#{T(java.lang.Math).random()}

4)spEl运算符

Spring使用笔记(三) 高级装配的更多相关文章

  1. Spring学习笔记(三)之装配Bean

    除了组件扫描与自动装配之外还有基于Java代码的装配与基于XML的装配. 有一些场景是我们不能用自动装配的,比如我们要给第三方库中的组件装配到我们的应用中,这时自动装配无效,因为自动装配只能扫描本应用 ...

  2. Spring学习(三)--高级装配

    一.Spring profile 在开发软件的时候,有一个很大的挑战就是将应用程序从一个环境迁 移到另外一个环境.开发阶段中,某些环境相关做法可能并不适合迁 移到生产环境中,甚至即便迁移过去也无法正常 ...

  3. spring对bean的高级装配之profile机制

    最近在读spring实战一书,个人感觉内容通俗易懂,学到了一些之前并不知道的知识,于是打算在博客里记录一下这些知识点便于后期记忆: 今天要记录的就是spring的条件化创建bean,针对条件化创建be ...

  4. Spring学习笔记(二)之装配Bean

    一,介绍Bean的装配机制 在Spring中,容器负责对象的创建并通过DI来协调对象之间的关系.但是我们要告诉Spring创建哪些Bean并且如何将其装配在一起.,装配wiring就是DI依赖注入的本 ...

  5. Spring Boot笔记三:配置文件

    配置文件这里需要讲的东西很多,所以我写在了这里,但是这个是和上篇文章衔接的,所以看这篇文章,先看上篇文章笔记二 一.单独的配置文件 配置文件里面不能都写我们的类的配置吧,这样那么多类太杂了,所以我们写 ...

  6. Spring学习笔记三:Bean管理

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6775827.html  一:如何使用Spring获取对象 1:定义bean类:要按照注入方式来定义对应的bea ...

  7. Spring学习笔记--使用注解装配

    使用@Autowired注解 从Spring2.5开始,最有趣的一种装配Spring Bean的方式是使用注解自动装配Bean的属性.Spring默认禁用注解装配,最简单的启用方式是使用Spring的 ...

  8. Spring学习笔记(三):面向切面的Spring

    Spring之面向切面编程 一.理解何为面向切面编程 对于这个的理解,我觉得Spring实战中的例子讲得很明白: 假设我现在是一个小区用户,每个月小区都要收电费,这时候就会来人查看电表,算出来这个月电 ...

  9. Spring实战笔记2---Bean的装配

    创建应用对象之间协作关系的行为通常成为装配,该篇的主要内容有两个,一个Spring装配Bean的几种方式以及Spring表达式,事实上这两者是分不开的,在Spring中,对象无需自己负责查找或者创建与 ...

  10. Spring学习总结之高级装配

    1.  profile profile可以决定bean在什么环境下才被装配(开发环境.测试环境.线上环境等) @Profile(“dev”)可以用在class之前,也可以用在类之前(Spring3.2 ...

随机推荐

  1. Jumpserver里常用的sudo权限控制模板

    ALL,!/bin/bash,!/bin/tcsh,!/bin/su,!/usr/bin/passwd,!/usr/bin/passwd root,!/bin/vim /etc/sudoers,!/u ...

  2. .tar.xz文件的解压方法

    废话不多说: 直接看 方法一: tar -xvJf ***.tar.gz 方法二: 先减压成 .tar 格式的文件, 再解压 .tar #xz是一个工具, 系统中没有安装,需要下载 xz -d *** ...

  3. Fisher–Yates shuffle 算法

    费希尔 - 耶茨洗牌 维基百科,自由的百科全书     所述费-耶茨洗牌是一种算法,用于产生随机排列的有限的序列 -in平原而言,算法打乱的序列.该算法有效地将所有元素放在帽子里; 它通过随机从帽子中 ...

  4. PyCharm之python书写规范--消去提示波浪线

    强迫症患者面对PyCharm的波浪线是很难受的,针对如下代码去除PyCharm中的波浪线: # _*_coding:utf-8_*_ # /usr/bin/env python3 A_user = & ...

  5. Leetcode刷题第004天

    class Solution { public: int findKthLargest(vector<int>& nums, int k) { , nums.size()-, k) ...

  6. Html列表分页算法

    public class PageHelper { /// <summary> /// 标签 /// </summary> public string Tag { get; s ...

  7. SQL Server Profiler的简单使用

    SQL Server Profiler可以检测在数据上执行的语句,特别是有的项目不直接使用sql语句,直接使用ORM框架的系统处理数据库的项目,在调试sql语句时,给了很大的帮助. 之前写了使用SQL ...

  8. 【SpringBoot】常用注解

    @EnableAutoConfiguration 启动自动装载:使用了这个注解之后,所有引入的jar的starters都会被自动注入.这个类的设计就是为starter工作的. @RestControl ...

  9. Centos6.5下通过shell脚本快速安装samba服务器

    使用方法如下: 上传脚本到linux服务器授权

  10. 排查Linux机器是否已被入侵

    来自--马哥Linux运维 1.入侵者可能会删除机器的日志信息 ,可以查看日志信息是否存在后者被清除 [root@zklf-server02 ~]# ll -h /var/log/ total 3.4 ...