KEMBAR78
Spring Boot | PPTX
Spring Boot
Claudia Zhou
2018.05.23
Spring
2002
2004
2005
Spring Modules
• Inversion of Control container
• Aspect-oriented programming
• Data access
• Transaction management
• Model-view-controller
• Remote Access framework
• Convention-over-configuration
• Batch processing
• Authentication and authorization
• Remote Management
• Messaging
• Testing
Inversion of Control
vs
Dependency Injection
IoC
Inversion of Control
IoC
Inversion of Control Flow
Martin Fowler
https://martinfowler.com/bliki/In
versionOfControl.html
https://www.martinfowler.com/a
rticles/injection.html
Command Line
#ruby
puts 'What is your name?'
name = gets
process_name(name)
puts 'What is your quest?'
quest = gets
process_quest(quest)
GUI
require 'tk'
root = TkRoot.new()
name_label = TkLabel.new() {text "What is Your Name?"}
name_label.pack
name = TkEntry.new(root).pack
name.bind("FocusOut") {process_name(name)}
quest_label = TkLabel.new() {text "What is Your Quest?"}
quest_label.pack
quest = TkEntry.new(root).pack
quest.bind("FocusOut") {process_quest(quest)}
Tk.mainloop()
Hollywood Principle
Don’t call us, we’ll call you.
Ex. HttpSessionListener
•sessionCreated()
•sessionDestroyed()
Ex. Template Method Pattern
Dependency Injection
One Form of IoC
Spring Stereotype
•@Component
•@Repository
•@Service
•@Controller
Spring @Autowired
Productivity of
Java Programmers
•50% Spring
•50% IDE
Boot
Boot Methods
1. Web https://start.spring.io/
2. IDE
3. CLI (command line)
claudia.zhou@claudiazhou:~/projects$ brew tap pivotal/tap
==> Tapping pivotal/tap
Cloning into '/usr/local/Homebrew/Library/Taps/pivotal/homebrew-tap'...
remote: Counting objects: 15, done.
remote: Compressing objects: 100% (14/14), done.
remote: Total 15 (delta 0), reused 5 (delta 0), pack-reused 0
Unpacking objects: 100% (15/15), done.
Tapped 10 formulae (50 files, 36.6KB)
claudia.zhou@claudiazhou:~/projects$ brew install springboot
Updating Homebrew...
==> Installing springboot from pivotal/tap
==> Downloading https://repo.spring.io/release/org/springframework/boot/spring-
######################################################################## 100.0%
==> Caveats
Bash completion has been installed to:
/usr/local/etc/bash_completion.d
zsh completions have been installed to:
/usr/local/share/zsh/site-functions
==> Summary
🍺 /usr/local/Cellar/springboot/2.0.2.RELEASE: 7 files, 9.8MB, built in 5 seconds
claudia.zhou@claudiazhou:~/projects$ spring init --dependencies=web,data-jpa my-
project
Using service at https://start.spring.io
Project extracted to '/Users/claudia.zhou/projects/my-project'
First Project
DemoApplication
package com.example.demo;
import org.springframework.boot.SpringApplication;
import
org.springframework.boot.autoconfigure.SpringBootApplicati
on;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
CommandLineRunner
@SpringBootApplication
public class DemoApplication implements CommandLineRunner {
private static final Logger logger =
LoggerFactory.getLogger(DemoApplication.class);
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
logger.info("Hello World!");
}
}
SQL Database
build.gradle
dependencies {
compile('org.springframework.boot:spring-boot-starter')
testCompile('org.springframework.boot:spring-boot-
starter-test')
}
build.gradle
dependencies {
compile('org.springframework.boot:spring-boot-starter-
jdbc')
runtime('mysql:mysql-connector-java')
testCompile('org.springframework.boot:spring-boot-
starter-test')
}
application.properties
spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=test
spring.datasource.password=test
spring.datasource.hikari.maximumPoolSize=1
DemoRepository
package com.example.demo.dao;
@Repository
public class DemoRepository {
private static final Logger logger =
LoggerFactory.getLogger(DemoRepository.class);
private final JdbcTemplate jdbcTemplate;
@Autowired
public DemoRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void demo() {
List<Map<String, Object>> list =
this.jdbcTemplate.queryForList("select
PARTITION_NAME, START, END from `partition`;");
logger.info("partitions: {}", list);
}
}
DemoApplication
@SpringBootApplication
public class DemoApplication implements CommandLineRunner
{
private final DemoRepository demoRepository;
@Autowired
public DemoApplication(DemoRepository demoRepository)
{
this.demoRepository = demoRepository;
}
@Override
public void run(String... args) throws Exception {
logger.info("Hello World!");
this.demoRepository.demo();
}
}
BeanPropertyRowMapper
Partition
package com.example.demo.domain;
public class Partition {
private String partitionName;
private Long start;
private Long end;
public String getPartitionName() {
return partitionName;
}
public void setPartitionName(String partitionName) {
this.partitionName = partitionName;
}
public Long getStart() {
return start;
}
public void setStart(Long start) {
this.start = start;
}
public Long getEnd() {
return end;
}
public void setEnd(Long end) {
this.end = end;
}
}
DemoRepository
@Repository
public class DemoRepository {
private RowMapper<Partition> rowMapper = new
BeanPropertyRowMapper<>(Partition.class);
public void demo2() {
List<Partition> list =
this.jdbcTemplate.query("select
PARTITION_NAME, START, END from `partition`;", rowMapper);
logger.info("partitions: {}", list);
}
}
Partition
public class Partition {
@Override
public String toString() {
return "Partition{" +
"partitionName='" + partitionName + ''' +
", start=" + start +
", end=" + end +
'}';
}
}
Partition
package com.example.demo.domain;
public class Partition {
private String name;
private Long start;
private Long end;
// 省略 getter, setter, toString
}
DemoRepository
@Repository
public class DemoRepository {
public void demo2() {
List<Partition> list =
this.jdbcTemplate.query("select
PARTITION_NAME as name, START, END from `partition`;",
rowMapper);
logger.info("partitions: {}", list);
}
}
Lombok
build.gradle
dependencies {
compile('org.springframework.boot:spring-boot-starter-
jdbc')
compile('org.projectlombok:lombok')
runtime('mysql:mysql-connector-java')
testCompile('org.springframework.boot:spring-boot-
starter-test')
}
Partition
package com.example.demo.domain;
import lombok.Data;
@Data
public class Partition {
private String name;
private Long start;
private Long end;
}
YAML
application.yaml
spring:
datasource:
url: jdbc:mysql://localhost/test
username: test
password: test
hikari:
maximumPoolSize: 1
Spring Profiles
application.yaml
spring:
profiles:
active: ${NODE_ENV:dev}
datasource:
url: jdbc:mysql://localhost/test
username: test
password: test
hikari:
maximumPoolSize: 1
application-staging.yaml
spring:
datasource:
hikari:
maximumPoolSize: 2
RabbitMQ
build.gradle
dependencies {
compile('org.springframework.boot:spring-boot-starter-
amqp')
compile('com.fasterxml.jackson.core:jackson-databind')
}
DemoRabbitSender
package com.example.demo.component;
@Component
public class DemoRabbitSender {
private static final String queueName = "demo";
private final AmqpTemplate amqpTemplate;
@Autowired
public DemoRabbitSender(AmqpTemplate amqpTemplate) {
this.amqpTemplate = amqpTemplate;
}
public void send() {
Partition p = new Partition();
p.setName("demo");
p.setStart(11111L);
p.setEnd(99999L);
this.amqpTemplate.convertAndSend(queueName, p);
}
}
DemoRabbitListener
package com.example.demo.component;
@Component
public class DemoRabbitListener {
private static final Logger logger =
LoggerFactory.getLogger(DemoRabbitListener.class);
@RabbitListener(queues = "demo")
public void processMessage(Partition partition) {
logger.info("received: {}", partition);
}
}
AppConfig
package com.example.demo;
@Configuration
public class AppConfig {
/*
@Bean
public SimpleRabbitListenerContainerFactory
rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
SimpleRabbitListenerContainerFactory factory = new
SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setMessageConverter(new Jackson2JsonMessageConverter());
return factory;
}
*/
@Bean
public MessageConverter messageConverter() {
return new Jackson2JsonMessageConverter();
}
}
DemoApplication
@SpringBootApplication
public class DemoApplication implements CommandLineRunner
{
private final DemoRabbitSender demoRabbitSender;
@Autowired
public DemoApplication(DemoRepository demoRepository,
DemoRabbitSender demoRabbitSender) {
this.demoRepository = demoRepository;
this.demoRabbitSender = demoRabbitSender;
}
@Override
public void run(String... args) throws Exception {
demoRabbitSender.send();
}
}
Scheduling
AppConfig
import
org.springframework.scheduling.annotation.EnableScheduling;
@Configuration
@EnableScheduling
public class AppConfig {
}
DemoApplication
@SpringBootApplication
public class DemoApplication implements CommandLineRunner
{
@Override
public void run(String... args) throws Exception {
}
@Scheduled(fixedRate = 1000)
public void sendToRabbit() {
this.demoRabbitSender.send();
}
}
Async
AppConfig
@Configuration
@EnableAsync
@EnableScheduling
public class AppConfig {
@Bean
public ThreadPoolTaskExecutor asyncExecutor() {
ThreadPoolTaskExecutor executor = new
ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setThreadNamePrefix("async-");
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
}
DemoRabbitSender
@Component
public class DemoRabbitSender {
@Async
public void asyncSend() {
logger.info("asyncSendToRabbit()");
send();
}
}
DemoApplication
@SpringBootApplication
public class DemoApplication implements CommandLineRunner
{
@Override
public void run(String... args) throws Exception {
this.demoRabbitSender.asyncSend();
this.demoRabbitSender.asyncSend();
this.demoRabbitSender.asyncSend();
}
}
Redis
build.gradle
dependencies {
compile('org.springframework.boot:spring-boot-starter-
data-redis')
}
DemoRedisRepository
@Repository
public class DemoRedisRepository {
private static final Logger logger =
LoggerFactory.getLogger(DemoRedisRepository.class);
private StringRedisTemplate template;
@Autowired
public DemoRedisRepository(StringRedisTemplate template) {
this.template = template;
}
public void demo() {
Long size = this.template.opsForList().size("demoList");
logger.info("demoList size: {}", size);
String value = this.template.opsForList().index("demoList",
0);
logger.info("demoList[0]: {}", value);
}
}
DemoApplication
@SpringBootApplication
public class DemoApplication implements CommandLineRunner
{
@Override
public void run(String... args) throws Exception {
this.demoRedisRepository.demo();
}
}
MongoDB
build.gradle
dependencies {
compile('org.springframework.boot:spring-boot-starter-
data-mongodb')
}
application.yaml
spring:
data:
mongodb:
uri: mongodb://localhost/test
DemoMongoRepository
@Repository
public class DemoMongoRepository {
private static final Logger logger =
LoggerFactory.getLogger(DemoMongoRepository.class);
private static final String COLLECTION = "demo";
private final MongoTemplate mongoTemplate;
@Autowired
public DemoMongoRepository(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}
public void demo() {
List<HashMap> data = this.mongoTemplate.find(new Query(),
HashMap.class, COLLECTION);
logger.info("mongo data: {}", data);
}
}
Multiple Datasources
application.yaml
demo2:
datasource:
url: jdbc:mysql://localhost/test
username: test
password: test
hikari:
maximumPoolSize: 1
DbConfig
@Configuration
public class DbConfig {
@Bean
@Primary
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "demo2DataSource")
@ConfigurationProperties(prefix = "demo2.datasource")
public DataSource demo2DataSource() {
return DataSourceBuilder.create().build();
}
}
Demo2MongoRepository
@Repository
public class Demo2Repository {
private JdbcTemplate jdbcTemplate;
private NamedParameterJdbcTemplate
namedParameterJdbcTemplate;
@Autowired
public void setDataSource(@Qualifier("demo2DataSource")
DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.namedParameterJdbcTemplate = new
NamedParameterJdbcTemplate(dataSource);
}
}
ORM - Hibernate-JPA
• Generate entity from table
• Generate table from entity
• Auto-implemented CRUD
Unit Test
RESTful API &
Microservice
WebSocket
AWS
Actuator
Sample & References
• https://github.com/jiayun/spring-boot-
sample
• https://docs.spring.io/spring-
boot/docs/current/reference/
• https://docs.spring.io/spring/docs/current/s
pring-framework-reference/
Thanks

Spring Boot

Editor's Notes

  • #11 http://martinfowler.com/
  • #13 http://martinfowler.com/bliki/InversionOfControl.html
  • #18 http://martinfowler.com/articles/injection.html
  • #19 http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/stereotype/package-summary.html
  • #42 可以不用設  driver-class-name,Spring Boot 會自動從 URL 判斷
  • #63 可以不用設  driver-class-name,Spring Boot 會自動從 URL 判斷
  • #65 可以不用設  driver-class-name,Spring Boot 會自動從 URL 判斷
  • #69 可以不用設  driver-class-name,Spring Boot 會自動從 URL 判斷
  • #97 可以不用設  driver-class-name,Spring Boot 會自動從 URL 判斷
  • #101 可以不用設  driver-class-name,Spring Boot 會自動從 URL 判斷