如今你们都追赶新的技术潮流,我来逆行一下。java
其实Spring Boot 隐藏了大量的细节,有大量的默认配置,其实经过xml配置的方式也能够达到和Spring Boot同样的效果。spring
在Spring Boot项目中咱们经过application.properties
中的设置来配置使用哪一个配置文件application-dev.properties
,application-prod.properties
等等apache
spring.profiles.active=dev
Spring 3.0之后就包含了Profile功能,在xml中能够这么写,不过全部的bean须要显式的配置。须要弄清楚本身项目的依赖关系,在Spring中第三方包如何初始化。app
<beans profile="dev,test"> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:application-dev.properties" /> </bean> </beans> <beans profile="prod"> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:application-prod.properties" /> </bean> </beans>
在Spring Boot中大量的Jave Bean都包含了默认初始化的功能,只须要配置预先设置好的属性名称,可是在xml中须要显式的初始化Bean,而且能够在初始化的时候用Placeholder
来配置。maven
在 Spring Boot 项目中application.properties
和application-xxx.properties
中的变量会自动放到 Environment中,而且能够经过@Value
直接注入到变量中。ide
若是使用 ClassPathXmlApplicationContext 初始化项目,能够看到源代码里 Environment 是一个 StandardEnvironment 实例,仅仅包含系统变量和环境变量,为了把application-xxx.properties
放到 Environment 当中咱们须要扩展一下 ClassPathXmlApplicationContext,下面是CustomApplicationContext
和CustomEnvironment
spring-boot
import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; public class CustomApplicationContext extends ClassPathXmlApplicationContext { public CustomApplicationContext(){ super(); } public CustomApplicationContext(String configLocation) { super(new String[]{configLocation}, true, null); } @Override public ConfigurableEnvironment createEnvironment() { return new CustomEnvironment(); } }
import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.PropertySource; import org.springframework.core.env.StandardEnvironment; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; import org.springframework.core.io.support.ResourcePropertySource; import java.io.IOException; public class CustomEnvironment extends StandardEnvironment { private static final String APPCONFIG_PATH_PATTERN = "classpath:application-%s.properties"; @Override protected void customizePropertySources(MutablePropertySources propertySources) { super.customizePropertySources(propertySources); try { propertySources.addLast(initResourcePropertySourceLocator()); } catch (IOException e) { logger.warn("failed to initialize application config environment", e); } } private PropertySource<?> initResourcePropertySourceLocator() throws IOException { String profile = System.getProperty("spring.profiles.active", "dev"); String configPath = String.format(APPCONFIG_PATH_PATTERN, profile); System.out.println("Using application config: " + configPath); Resource resource = new DefaultResourceLoader(this.getClass().getClassLoader()). getResource(configPath); PropertySource resourcePropertySource = new ResourcePropertySource(resource); return resourcePropertySource; } }
Spring Boot 默认使用的是logback,在logback-spring.xml 的配置文件中可使用Spring Profile,并且还有一个默认的CONSOLE Appender测试
<?xml version="1.0" encoding="UTF-8"?> <configuration> <include resource="org/springframework/boot/logging/logback/base.xml" /> <springProfile name="dev,test"> <logger name="org.springframework" level="DEBUG" additivity="false"> <appender-ref ref="CONSOLE"/> </logger> </springProfile> <springProfile name="prod"> <logger name="org.springframework" level="INFO" additivity="false"> <appender-ref ref="CONSOLE"/> </logger> </springProfile> </configuration>
在没有使用Spring Boot的状况下,不能在logback的config中使用Spring Profile,只能分拆成多个文件,而后根据环境变量读取不一样的配置文件,须要添加依赖org.logback-extensions
。ui
<dependency> <groupId>org.logback-extensions</groupId> <artifactId>logback-ext-spring</artifactId> <version>0.1.4</version> </dependency>
logback-dev.xmlthis
<?xml version="1.0" encoding="UTF-8"?> <configuration> <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%15.15t] %-40.40logger{39} : %m%n}"/> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>${CONSOLE_LOG_PATTERN}</pattern> <charset>utf8</charset> </encoder> </appender> <logger name="org.springframework" level="DEBUG" additivity="false"> <appender-ref ref="CONSOLE"/> </logger> </configuration>
logback-prod.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration> <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%15.15t] %-40.40logger{39} : %m%n}"/> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>${CONSOLE_LOG_PATTERN}</pattern> <charset>utf8</charset> </encoder> </appender> <logger name="org.springframework" level="INFO" additivity="false"> <appender-ref ref="CONSOLE"/> </logger> </configuration>
下面的代码根据环境变量读取不一样的配置文件
private static final String LOGCONFIG_PATH_PATTERN = "classpath:logback-%s.xml"; public static void main(String[] args) throws FileNotFoundException, JoranException { String profile = System.getProperty("spring.profiles.active", "dev"); System.setProperty("file.encoding", "utf-8"); // logback config String logConfigPath = String.format(LOGCONFIG_PATH_PATTERN, profile); System.out.println("Using logback config: " + logConfigPath); LogbackConfigurer.initLogging(logConfigPath); SLF4JBridgeHandler.removeHandlersForRootLogger(); SLF4JBridgeHandler.install(); ConfigurableApplicationContext context = new CustomApplicationContext("classpath:applicationContext.xml"); }
有Spring Boot 的时候TestCase写起来很方便,在类上添加两行注解便可,在src\test\resources
下的application.properties
中设置spring.profiles.active=test
便可指定Profile为test
@RunWith(SpringRunner.class) @SpringBootTest public class TestStockService { @Autowired StockService stockService; @Before public void setUp() { } @After public void tearDown() { } @Test public void testMissingBbTickerEN() { } }
不使用Spring Boot的状况下,须要指定好几个配置。
@RunWith(SpringRunner.class) @ContextConfiguration(locations = "classpath:applicationContext.xml") @ActiveProfiles(profiles = "test") @TestPropertySource("classpath:application-test.properties") public class TestStockService { @Autowired StockService stockService; @Before public void setUp() { } @After public void tearDown() { } @Test public void testMissingBbTickerEN() { } }
Spring Boot 会把项目和所依赖的 Jar 包打包成一个大 Jar 包,直接运行这个 Jar 包就能够。这个功能是经过spring-boot-maven-plugin
实现的。
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin>
不使用Spring Boot 以后,咱们须要配置maven-jar-plugin
,可是依赖包没法像Spring Boot同样打包成一个大的 Jar 包,须要咱们指定classpath。
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>2.6</version> <configuration> <archive> <manifest> <mainClass>com.exmaple.demo.DemoApplication</mainClass> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> </manifest> </archive> </configuration> </plugin>
注意:
当用java -jar yourJarExe.jar来运行一个通过打包的应用程序的时候,你会发现如何设置-classpath参数应用程序都找不到相应的第三方类,报ClassNotFound错误。实际上这是因为当使用-jar参数运行的时候,java VM会屏蔽全部的外部classpath,而只以自己yourJarExe.jar的内部class做为类的寻找范围。因此须要在jar包mainfest中添加classpath。
使用下面的maven配置帮你把全部的依赖包复制到targetlib目录下,方便咱们部署或者是测试时复制依赖包。
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>copy-dependencies</id> <phase>prepare-package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>target/lib</outputDirectory> <overWriteIfNewer>true</overWriteIfNewer> <excludeGroupIds> junit,org.hamcrest,org.mockito,org.powermock,${project.groupId} </excludeGroupIds> </configuration> </execution> </executions> <configuration> <verbose>true</verbose> <detail>true</detail> <outputDirectory>${project.build.directory}</outputDirectory> </configuration> </plugin>
运行时经过指定命令行参数 -Dspring.profiles.active=prod 来切换profile
java -jar -Dspring.profiles.active=prod demo.jar
Spring Boot很大程度上方便了咱们的开发,可是隐藏了大量的细节,咱们使用xml配置spring能够达到差很少一样的效果,可是在结构和配置上更加清晰。