示例代码地址:这里

1. 配置

1.1 基本配置

1.1.1 POM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>lx</groupId>
<artifactId>deep-into-spring-boot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>deep-into-spring-boot</name>
<description>深入实践spring boot</description>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
<relativePath/> <!-- 从仓库中查找parent -->
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

1.1.2 application.yml

将端口设置为8080(默认就是的,并且设置tomcat的字符集为UTF-8

1
2
3
4
server:
port: 8080
tomcat:
uri-encoding: UTF-8

spring boot更多预置参数请参考:

https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

Read more »

1. 环境变量

1.1 GOROOT

GOROOT就是go的安装路径
~/.bash_profile中添加下面语句:

1
2
3
4
5
GOROOT=/usr/local/go
export GOROOT

# 添加到PATH
export PATH=$PATH:$GOROOT/bin

1.2 GOPATH

go install/get/run会用到的目录。它的下面有3个文件夹:

  • bin: golang编译可执行文件存放路径,可自动生成。通常把它也假如到PATH中,用来执行安装的第三方工具
  • pkg: golang编译的.a中间文件存放路径,可自动生成
  • src: 源码路径。按照golang默认约定,go run,go install等命令的当前工作路径(即在此路径下执行上述命令)。

可以设置多个子目录到GOPATH中

1
export GOPATH=~/golib:~/goproject

1.3 GOBIN

Read more »

7.1 映射JPA实体

JPA: Java Persistence API 它是从EJB3中抽取出来的。

  • EntityManagerFactory
  • EntityManager
  • persistence.xml
  • @Entity
  • @Column
  • @Table

要使用JPA,我们需要添加依赖:

1
compile group: 'javax', name: 'javaee-api', version: '7.0'

我们来新建数据:

1
2
3
4
5
6
7
8
@Entity
public class Account {
@Id
private Long id;
private BigDecimal balance;

//...
}

然后配置数据源:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Configuration
@ComponentScan(basePackages = "lx.spring.core")
@PropertySource("classpath:prod.properties")
@EnableTransactionManagement
public class AppConfig {

@Autowired
private Environment env;

@Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(env.getProperty("db.driver"));
dataSource.setUrl(env.getProperty("db.url"));
dataSource.setUsername(env.getProperty("db.user"));
dataSource.setPassword(env.getProperty("db.pass"));
return dataSource;
}
}

7.2 Entity Manager和Vendor Adapter

Read more »

6.1 实例化和配置

没有Spring的情况下,JDBC非常难用;有了Spring,JDBC就变得比较靠谱可用了。

这里我们在Bean中使用DataSourceJdbcTemplate进行初始化。

1
2
3
4
5
6
7
8
9
10
11
12
13

@Repository
@Profile("test")
public class JdbcAccountRepository implements AccountRepository {

private JdbcTemplate template;
private static long nextId = 4;

@Autowired
public JdbcAccountRepository(DataSource dataSource) {
template = new JdbcTemplate(dataSource);
}
}

后面我们看如何配置多个DataSource

6.2 定义数据源Data Source

之前我们已经讲了@Component,但是在实际中我们更多的遇到的是@Service@Repository@Controller,这些其实也是@Component

首先我们来添加一些依赖:

1
2
3
4
5
6
7
8
9
10
dependencies {
compile group: 'org.apache.commons', name: 'commons-dbcp2', version: '2.1.1'

compile group: 'org.springframework', name: 'spring-test', version: '4.3.2.RELEASE'
compile group: 'org.hamcrest', name: 'hamcrest-library', version: '1.3'
//...

return'com.h2database:h2:1.4.192'

}

注意这里我们用了返回,这是因为需要对应的驱动

Read more »

5.1 声明事务管理

ACID 属性:

Atomic原子:All or Nothing

Consistent一致性: DB integrity constraints never violated

Isolated: How transactions see work done by others

Durable: Committed changes are permanent

我们一般是在Service层声明事务。

5.1.1 @Transactional注解

@Transactional注解允许我们管理一个事务管理器。Spring不直接提供事务管理器,它提供一个hook连接到已经存在的事务管理器,比如我们使用关系数据库,那Spring就是使用关系数据库的事务管理器。Spring的Bean和Entity允许我们请求事务管理器,设置属性(比如超时、只读等)。

应用Spring的事务需要两步:

Read more »

4.1 标准测试注解和injecting fixture

Spring的一个特点是测试Component非常方便。

现在我们为BaseballGame创建BaseballGameTest。然后做测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class BaseballGameTest {
private Game game;
private ApplicationContext ctx;

@Before
public void setUp() throws Exception {
ctx = new AnnotationConfigApplicationContext(AppConfig.class);
game = ctx.getBean("game", Game.class);
}

@Test
public void playGame() throws Exception {
String home = game.getHomeTeam().getName();
String away = game.getAwayTeam().getName();

String result = game.playGame();

assertTrue(result.contains(home) || result.contains(away));
}

@Test
public void testGetAndSetHomeTeam() throws Exception {
Team royals = ctx.getBean("royals", Team.class);
game.setHomeTeam(royals);
assertEquals(royals.getName(), game.getHomeTeam().getName());
}

}

这里每次测试的时候,都要调用一次setUp,也就是我们的ApplicationContext会被反复创建很多次,Spring提供了一些方法让ApplicationContext只执行一次。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@RunWith(SpringJUnit4ClassRunner.class) //
@ContextConfiguration(classes = AppConfig.class) //
public class BaseballGameTest {
@Autowired //
private Game game;

@Autowired //
private ApplicationContext ctx;

@Test
public void playGame() throws Exception {
String home = game.getHomeTeam().getName();
String away = game.getAwayTeam().getName();

String result = game.playGame();

assertTrue(result.contains(home) || result.contains(away));
}

@Test
public void testGetAndSetHomeTeam() throws Exception {
Team royals = ctx.getBean("royals", Team.class);
game.setHomeTeam(royals);
assertEquals(royals.getName(), game.getHomeTeam().getName());
}
}

这里我们用@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = AppConfig.class)让我们可以直接用Bean和ApplicationContext

4.2 事务测试

事务测试是当测试完成后,所有的测试操作都会回滚。我们用@Transactional来表示事务测试。

1
2
3
4
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
@Transactional
public class BaseballGameTest { ... }
Read more »

3.1 AOP的概念

AOP适用于以下场景:代码交织(code tangling)和代码分散(code scattering)

代码交织是指一个方法完成多个功能,这几个功能之间又没有必然联系,比如我们需要做日志、检查授权和执行业务逻辑,如果我们不用AOP的话那这三个就混在一起了。

代码分散式指比如我们有多处需要做日志,然后这些代码在多个地方重复。

AOP允许我们将这些动作封装成一个类,然后告诉Spring我们希望在多个地方调用这个类(成为Aspect),从而避免代码交织和分散。

AOP会设计到一下几个概念:

  • 连接点Join Point
  • 切入点Point Cut
  • Advice
  • Aspect
  • Weaving

3.1.1 连接点(Join Point)和切入点(Point Cut)

连接点,指的是我们能够应用我们Aspect的地方。这是告诉我们where to use the Aspects.
在一般概念的AOP上,我们可以在任何地方用Aspect,但是Spring对这一规则做了限制,我们只能用在Spring管理的Bean的公共方法中。

切入点一般来说可以认为和连接点类似。表示我们实际声明的连接点。

Read more »

2.1 构造函数和Setter注入

之前我们基于注解的配置是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Configuration
@ComponentScan(basePackages = "lx.spring.core")
public class AppConfig {

@Autowired
private DataSource dataSource;

@Autowired @Qualifier("redSox")
private Team home;

@Autowired @Qualifier("cubs")
private Team away;

@Bean
public Game game() {
BaseballGame game = new BaseballGame(home, away);
game.setDataSource(dataSource);
return game;
}
}

我们知道如果没有@Qualifier注解,就会报错。但是如果我们把homeaway去掉,然后添加一个集合,像下面这样:

1
2
3
4
5
6
7
8
9
10
11
12
...
public class AppConfig {
...
@Autowired
private List<Team> teams;

@Bean
public Game game() {
BaseballGame game = new BaseballGame(teams.get(0), teams.get(1));
...
}
}

如果我们有多个相同类型的Bean,但是是以单个变量声明的,如

1
2
@Autowired @Qualifier("redSox")
private Team home;

如果没有@Qualifier注解就会报错,但是想前面例子是用集合的形式:

1
2
@Autowired
private List<Team> teams;

就不会报错,他会扫描所有这个类型的Bean,然后放到集合中。

Read more »

1.1 一个Spring的简单Java应用

1.1.1 创建应用

这里,我们用Gradle创建Spring的应用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
group 'lx.spring.core'
version '1.0-SNAPSHOT'

apply plugin: 'java'

sourceCompatibility = 1.8

repositories {
mavenCentral()
}

dependencies {
compile group: 'org.springframework', name: 'spring-context', version: '4.3.2.RELEASE'
testCompile group: 'org.springframework', name: 'spring-test', version: '4.3.2.RELEASE'
testCompile group: 'junit', name: 'junit', version: '4.11'
}

1.1.2 定义entity

spring希望我们尽可能的使用接口,因此,我们声明,Team, Game接口,然后创建对应的实现:

1
2
3
4
5
6
7
8
9
10
11
public interface Team {
String getName();
}

public interface Game {
void setHomeTeam(Team team);
Team getHomeTeam();
void setAwayTeam(Team team);
Team getAwayTeam();
String playGame();
}

对应的实现类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public class Cubs implements Team {
@Override
public String getName() {
return "Chicago Cubs";
}
}

public class RedSox implements Team {
@Override
public String getName() {
return "Bostom Red Sox";
}
}

public class Royals implements Team {
@Override
public String getName() {
return "Kansas City Royals";
}
}

public class BaseballGame implements Game {
private Team homeTeam;
private Team awayTeam;

public BaseballGame() {
}

public BaseballGame(Team homeTeam, Team awayTeam) {
this.homeTeam = homeTeam;
this.awayTeam = awayTeam;
}

@Override
public Team getHomeTeam() {
return homeTeam;
}

@Override
public void setHomeTeam(Team homeTeam) {
this.homeTeam = homeTeam;
}

@Override
public Team getAwayTeam() {
return awayTeam;
}

@Override
public void setAwayTeam(Team awayTeam) {
this.awayTeam = awayTeam;
}

@Override
public String playGame() {
return Math.random() < 0.5 ? getHomeTeam().getName() :
getAwayTeam().getName();
}
}

1.1.3 使用Java注解来进行调用

Read more »

本章包含:

  • Netty的技术与架构
  • Channel, EventLoop, 和 ChannelFuture
  • ChannelHandlerChannelPipeline
  • Bootstrapping

3.1 Channel, EventLoop和ChannelFuture

Channel, EventLoopChannelFuture可以看成是Netty对网络的抽象:

  • Channel:Socket
  • EventLoop: 控制流、多线程和并发
  • ChannelFuture:异步通知

3.1.1 Channel接口

基本IO操作(bind(), connect(), read(), write())依赖于底层网络传输。在基于Java的网络中,基础组成是Socket类。Netty的Channel接口提供了的API能大幅度减少直接操作Socket的复杂度。此外,Channel是所有扩展类的根类。下面是一些继承的类:

  • EmbeddedChannel
  • LocalServerChannel
  • NioDatagramChannel
  • NioSctpChannel
  • NioSocketChannel

3.1.2 EventLoop接口

EventLoop定义了Netty对连接生命区间事件处理的核心抽象。在后面的章节里我们会讨论EventLoop的细节。下图展示了Channel, EventLoop, ThreadEventLoopGroup之间的关系。

Read more »
0%