Spring--bean装配(二)
多环境测试
使用H2内嵌数据库+Pure Spring测试
数据准备
# schema.sql
create table bean_test(
id int identity,
name varchar(255)
);
# data.sql
insert into bean_test (id,name) values (1,'user-1');
insert into bean_test (id,name) values (2,'user-2');
实体
package com.spring.study.profile.condition.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String name;
}
package com.spring.study.profile.condition.bean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import javax.sql.DataSource;
@Configuration
public class DataSourceConfig {
@Bean(destroyMethod = "shutdown")
@Profile("dev")
public DataSource embeddedDataSource(){
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("classpath:schema.sql")
.addScript("classpath:data.sql")
.build();
}
}
JDBC测试
package com.spring.study.bean.profile.condition.bean;
import com.spring.study.profile.condition.bean.DataSourceConfig;
import com.spring.study.profile.condition.bean.User;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = DataSourceConfig.class)
@ActiveProfiles("dev")
@Slf4j
public class DatasourceTest {
@Autowired
private DataSource dataSource;
private static final String SELECT_SQL = "select * from bean_test";
@Test
public void getAll(){
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
conn = dataSource.getConnection();
stmt = conn.prepareStatement(SELECT_SQL);
rs = stmt.executeQuery();
User user = null;
while (rs.next()){
user = new User();
user.setId(rs.getInt(1));
user.setName(rs.getString(2));
log.info(user.toString());
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
if (rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
XML配置形式 + 引入JdbcTemplate简化查询操作
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
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
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd">
<!-- 激活相同id的bean @ActiveProfiles-->
<!-- spring.profiles.active/spring.proflies.default-->
<!-- DispatcherServlet; <context-param>-->
<context:component-scan base-package="com.spring.study.profile.condition.bean"/>
<beans profile="dev">
<jdbc:embedded-database id="dataSource" type="H2">
<jdbc:script location="schema.sql"/>
<jdbc:script location="data.sql"/>
</jdbc:embedded-database>
</beans>
</beans>
package com.spring.study.bean.profile.condition.bean;
import com.spring.study.profile.condition.bean.User;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.sql.DataSource;
import java.sql.ResultSet;
import java.sql.SQLException;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:profile-config.xml")
@ActiveProfiles("dev")
@Slf4j
public class DataSourceTestWithXml {
@Autowired
private DataSource dataSource;
private JdbcTemplate jdbcTemplate;
@Autowired
public void setJdbcTemplate() {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
private static final String SELECT_SQL = "select * from bean_test where id = ?";
@Test
public void testGetOne(){
User user = jdbcTemplate.queryForObject(SELECT_SQL,new UserRowMapper(),1);
log.info(user.toString());
}
private static final class UserRowMapper implements RowMapper<User>{
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
return new User(
rs.getInt(1),
rs.getString(2)
);
}
}
}
Condition条件化配置bean
package com.spring.study.profile.condition.bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
@Configuration
@PropertySource("classpath:params.properties")
public class ConditionBean {
@Autowired
Environment environment;
@Bean
@Conditional(CheackBean.class)
public MyBean myBean(){
MyBean myBean = new MyBean();
myBean.setName(environment.getProperty("user.name"));
return myBean;
}
}
package com.spring.study.profile.condition.bean;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class CheackBean implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
Environment environment = conditionContext.getEnvironment();
return environment.containsProperty("user.name");
}
}
package com.spring.study.bean.profile.condition.bean;
import com.spring.study.profile.condition.bean.ConditionBean;
import com.spring.study.profile.condition.bean.MyBean;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ConditionBean.class)
public class MyBeanTest {
@Autowired
private MyBean myBean;
@Test
public void testNotNull(){
Assert.assertNotNull(myBean);
}
}
ConditionContext接口简述

| getRegistry() |
检查bean的定义 |
| getBeanFactory() |
检查bean是否存在 |
| getEnvironment() |
检查环境变量是否存在 |
| getResourceLoader |
返回ResourceLoader加载的所有资源 |
| getClassLoader |
加载并检查类是否存在 |

profile原理
package org.springframework.context.annotation;
import java.util.Iterator;
import java.util.List;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.MultiValueMap;
class ProfileCondition implements Condition {
ProfileCondition() {
}
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//当前环境变量不为null则取出所有属性
if (context.getEnvironment() != null) {
MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
if (attrs != null) {
Iterator var4 = ((List)attrs.get("value")).iterator();
Object value;
do {
if (!var4.hasNext()) {
//不匹配
return false;
}
value = var4.next();
} while(!context.getEnvironment().acceptsProfiles((String[])((String[])value)));
return true;
}
}
//默认创建
return true;
}
}