目录:
SpringBoot基础(1)SpringBoot基础(2)SpringBoot基础(3)

11.SpringBoot事务

spring Boot 使用事务非常简单,首先使用注解 @EnableTransactionManagement(启注解事务管理,等同于xml配置方式的 <tx:annotation-driven />)开启事务支持后,然后在访问数据库的Service方法上添加注解 @Transactional 便可。

在Service中,被 @Transactional 注解的方法,将支持事务。如果注解在类上,则整个类的所有方法都默认支持事务。

关于事务管理器,不管是JPA还是JDBC等都实现自接口 PlatformTransactionManager 。

如果添加的是 spring-boot-starter-jdbc 依赖,框架会默认注入 DataSourceTransactionManager 实例。如果你添加的是 spring-boot-starter-data-jpa 依赖,框架会默认注入 JpaTransactionManager 实例。

同时添加两者依赖时采用的是JpaTransactionManager

SpringBoot自动选择事务管理器固然方便,但是当存在多个事务管理器时,则需要指定使用哪个事务管理器。

@EnableTransactionManagement // 开启注解事务管理,等同于xml配置文件中的 <tx:annotation-driven />
@SpringBootApplication
public class ProfiledemoApplication implements TransactionManagementConfigurer {

    @Resource(name="txManager2")
    private PlatformTransactionManager txManager2;

    // 创建事务管理器1
    @Bean(name="txManager1")
    public PlatformTransactionManager txManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    // 创建事务管理器2
    @Bean(name="txManager2")
    public PlatformTransactionManager txManager2(EntityManagerFactory factory) {
        return new JpaTransactionManager(factory);
    }

    // 覆写TransactionManagementConfigurer的annotationDrivenTransactionManager方法,其返回值代表在拥有多个事务管理器的情况下默认使用的事务管理器
    @Override
    public PlatformTransactionManager annotationDrivenTransactionManager() {
        return txManager2;
    }

    public static void main(String[] args) {
        SpringApplication.run(ProfiledemoApplication.class, args);
    }

}
@Component
public class DevSendMessage {

    // 使用value具体指定使用哪个事务管理器
    @Transactional(value="txManager1")
    @Override
    public void send() {
        System.out.println(">>>>>>>>Dev Send()<<<<<<<<");
        send2();
    }

    // 在存在多个事务管理器的情况下,如果不使用value具体指定,
    // 则默认使用方法 annotationDrivenTransactionManager() 返回的事务管理器
    @Transactional
    public void send2() {
        System.out.println(">>>>>>>>Dev Send2()<<<<<<<<");
    }
}

如果Spring容器中存在多个 PlatformTransactionManager 实例,并且没有实现接口 TransactionManagementConfigurer 指定默认值,在我们在方法上使用注解 @Transactional的时候,就必须要用value指定,如果不指定,则会抛出异常。

对于系统需要提供默认事务管理的情况下,通过实现接口TransactionManagementConfigurer 指定,如上文示例。

对有的系统,为了避免不必要的问题,在业务中必须要明确指定 @Transactional 的 value 值的情况下,不建议实现接口 TransactionManagementConfigurer,这样控制台会明确抛出异常,开发人员就不会忘记主动指定。

12.SpringBoot环境变量的读取

直接注入

直接通过@Value注入即可, 如 @Value{a.b}

通过Environment获取

@Inject
private Environment env;

然后通过env获取,如env.getProperty(“a.b”);

实现EnvironmentAware 接口

凡是被spring管理的类,实现接口 EnvironmentAware 并重写方法 setEnvironment ,可以在工程启动时,获取到系统环境变量和application配置文件中的变量:

@Configuration
public class MyWebAppConfigurer implements EnvironmentAware
        {
    private static final Logger logger = LoggerFactory.getLogger(MyWebAppConfigurer.class);

    private RelaxedPropertyResolver propertyResolver;

    @Value("${spring.datasource.url}")
    private String myUrl;

    /**
     * 这个方法只是测试实现EnvironmentAware接口,读取环境变量的方法。
     */
    @Override
    public void setEnvironment(Environment env) {
        logger.info(env.getProperty("JAVA_HOME"));
        logger.info(myUrl);
        String str = env.getProperty("spring.datasource.url");
        logger.info(str);
        propertyResolver = new RelaxedPropertyResolver(env, "spring.datasource.");
        String url = propertyResolver.getProperty("url");
        logger.info(url);
    }
}

@Controller @Service 等被Spring管理的类都支持,注意重写的方法 setEnvironment是在系统启动的时候被执行。

@Controller
public class PageController implements EnvironmentAware{

    @Override
    public void setEnvironment(Environment environment) {
        String s = environment.getProperty("JAVA_HOME");
        System.out.println(s);
    }
}

还可以通过@ConfigurationProperties 读取application属性配置文件中的属性。

@Configuration
@ConditionalOnClass(Mongo.class)
@EnableConfigurationProperties(MongoProperties.class)
public class MongoAutoConfiguration {

    @Autowired
    private MongoProperties properties; 

}

@ConditionOnClass表明该@Configuration仅仅在一定条件下才会被加载,这里的条件是Mongo.class位于类路径上

@EnableConfigurationProperties将Spring Boot的配置文件(application.properties)中的spring.data.mongodb.*属性映射为MongoProperties并注入到MongoAutoConfiguration中。

@ConditionalOnMissingBean说明Spring Boot仅仅在当前上下文中不存在Mongo对象时,才会实例化一个Bean。这个逻辑也体现了Spring Boot的另外一个特性——自定义的Bean优先于框架的默认配置,我们如果显式的在业务代码中定义了一个Mongo对象,那么Spring Boot就不再创建。

@ConfigurationProperties(prefix = "spring.data.mongodb")
public class MongoProperties {

    private String host;
    private int port = DBPort.PORT;
    private String uri = "mongodb://localhost/test";
    private String database;

    // ... getters/ setters omitted
}

它就是以spring.data.MongoDB作为前缀的属性,然后通过名字直接映射为对象的属性,同时还包含了一些默认值。如果不配置,那么mongo.uri就是mongodb://localhost/test。

13.SpingBoot服务配置

spring Boot 其默认是集成web容器的,启动方式由像普通Java程序一样,main函数入口启动。其内置Tomcat容器或Jetty容器,具体由配置来决定(默认Tomcat)。当然你也可以将项目打包成war包,放到独立的web容器中(Tomcat、weblogic等等),当然在此之前你要对程序入口做简单调整。

修改启动类,继承 SpringBootServletInitializer 并重写 configure 方法:

public class SpringBootSampleApplication extends SpringBootServletInitializer{

    private static final Logger logger = LoggerFactory.getLogger(SpringBootSampleApplication.class);

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(this.getClass());
    }

}

修改打包文件为war

修改pom,排除tomcat插件

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>
     <exclusions>
        <exclusion>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
     </exclusions>
</dependency>

其他同一般J2EE项目一样部署到web容器。