-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch.xml
More file actions
84 lines (58 loc) · 62.1 KB
/
search.xml
File metadata and controls
84 lines (58 loc) · 62.1 KB
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title><![CDATA[Maven 学习笔记(六)]]></title>
<url>%2F2017%2F08%2F30%2FMaven-Note-6%2F</url>
<content type="text"><![CDATA[Maven 模块直接存在类似 Java 语言的聚合与继承关系. 通过依赖和插件管理的可以更好的简化 Maven 的配置.并且通过这两个特性编写出更新简洁完善的 Maven 测试案例. 聚合与继承聚合 通过创建一个新的聚合模块, 可用通过该模块构建整个项目的所有模块 123456789101112131415161718<project> <modelVersion>4.0.0</modelVersion> <groupId>com.dlc.maven</groupId> <artifactId>dlc-parent</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>pom</packaging> <name>DLC-PARENT</name> <!-- 父子结构 --> <modules> <module>dlc-module-1</module> <module>dlc-module-2</module> </modules> <!-- 平行结构 --> <modules> <module>../dlc-module-1</module> <module>../dlc-module-2</module> </modules></project> 继承 作为父模块的POM, 必须 packaging 必须定义为 pom 继承父模块的子模块POM 1234567891011121314151617181920212223242526<project> <!-- 声明父模块 --> <parent> <groupId>com.dlc.maven</groupId> <artifactId>dlc-parent</artifactId> <version>1.0.0-SNAPSHOT</version> <!-- 非必须 父模块 POM 的相对路径 relativePath 默认值是 ../pom.xml --> <relativePath></relativePath> </parent> <artifactId>dlc-subModule</artifactId> <name>SubModule</name> <dependencies> ... </dependencies> <build> <plugins> ... </plugins> </build> </project> 可继承的 POM 元素 groupId version description organization: 项目的组织信息 inceptionYear: 项目的创建年限 url: 项目 URL 地址 developers: 项目开发者信息 contributors: 项目贡献者信息 distributionManagement: 项目部署配置 issueManagement: 项目的缺陷跟踪系统信息 ciManagement: 项目持续集成系统信息 scm: 项目的版本控制系统信息 mailingLists: 项目邮件列表信息 properties: 自定义的 Maven 属性 dependencies dependencyManagement: 项目的依赖管理配置 repositories: 项目的仓库配置 build: 包括项目的源码目录配置, 输出目录配置, 插件配置, 插件管理配置等. reporting: 包括项目的报告的输出目录配置, 报告插件配置等. 依赖和插件管理 123456789<!-- 不会给当前模块引入依赖, 也不会跟子模块添加 但当前配置会被继承--><dependencyManagement> <dependency> ... </dependency></dependencyManagement> 子 POM 可以从父 POM 中继承 dependencyManagement, 子 POM 配置的依赖如果是属于父类的 dependencyManagement, 由于继承的关系, 在子 POM 中引用可以直接省略 version 和 scope. 插件管理 pluginManagement, 原理同上. 123456789<build> <pluginManagement> <plugins> <plugin> ... </plugin> </plugins> </pluginManagement></build> 反应堆 在一个多模块的Maven项目中, 反应堆 (Reactor) 是指所有模块的一个构建结构. 对于单模块的项目, Reactor就是该模块本身, 但对于多模块的项目, 反应堆包含了各个模块直接的继承与依赖关系, 从而 Maven 可以自动计算出合理的模块构建顺序. 一个 Reactor的构建顺序为: Maven 按顺序读取 POM, 如果该 POM 没有依赖模块, 那么就构建该模块, 否则就会先构建该模块的, 如果该模块还依赖其他模块,则先构建该模块. 如果值需要构建项目中的一个模块, 可以通过裁剪 Reactor 来实现 12345678# 同时构建所列模块的依赖模块: -am, --also-makemvn clean install -pl dlc-module-1 -am# 同时构建依赖于所列模块的模块: -amd, -also-make-dependentsmvn clean install -pl dlc-module-1 -amd# 构建指定的模块, 模块参数用逗号分隔: -pl, --projects <arg>mvn clean install -pl dlc-module-1,dlc-module-2# 从指定的模块回复 Reactor: -rf, -resume-from <arg>mvn clean install -rf dlc-module-1 Maven测试maven-surefire-plugin 此插件是与 default生命周期的 test阶段绑定的, 是Maven内置绑定. maven-surefire-plugin会自动执行 Maven 测试路径(默认 src/test/java/)下的所有符合以下一组命名模式的测试类. 模式为: **/Test*.java **/*Test.java **/*TestCase.java 跳过测试 1234# 跳过 default生命周期的 test 阶段, 但是仍会 test 编译, tetst 创建等阶段mvn clean install -DskipTests# 会跳过所有与 test 有关的阶段.mvn clean install -Dmaven.skip.test=true OR 1234567891011121314151617181920<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.1</version> <configuration> <!-- -Dmaven.skip.test=true ,此 skip 参数只针对 test --> <skip>true</skip> </configuration></plugin><plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.5</version> <configuration> <!-- -Dmaven.skip.test=true --> <skip>true</skip> <!-- -DskipTests --> <skipTests>true</skipTests> </configuration></plugin> 动态指定运行的测试用例 123456mvn test -Dtest=classNamemvn test -Dtest=className*Testmvn test -Dtest=className1,className2mvn test -Dtest=className*Test,className2# 默认 -Dtest 如果没有找到测试类, Maven 会默认报错, 添加参数 DfailIfNoTests 没有测试也不报错mvn test -Dtest -DfailIfNoTests=false 包含与排除测试用例 1234567891011<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.5</version> <configuration> <!-- 任意路径(**)以 Tests 结尾(*)的 Java 类包含在测试中 --> <include>**/*Tests.java</include> <!-- 任意路径(**)的 Test.java 类排除出测试--> <exclude>**/Test.java</exclude> </configuration></plugin> 测试报告 基本测试报告 默认情况下, maven-surefire-plugin 会在项目的 target/surefire-reports 目录下生成两种格式的错误报告: 简单文本格式 与JUnit 兼容的XML格式 测试覆盖率报告使用 Cobertura, Maven 通过 cobertura-maven-plugin 与之集成. 1mvn cobertura:cobertura 会在项目目录 target/site/cobertrua/生成HTML格式的报告.]]></content>
</entry>
<entry>
<title><![CDATA[Maven 学习笔记(五)]]></title>
<url>%2F2017%2F07%2F11%2FMaven-Note-5%2F</url>
<content type="text"><![CDATA[Maven 的核心仅仅定义了抽象的生命周期, 具体的任务是交给插件去完成的, 插件以独立构件形式存在, 因此, Maven 只会在使用时才会连接远程仓库下载需要使用的插件.Maven为了复用代码, 一个插件能完成多个任务. 一些功能组成 Maven 插件, 每个 Maven 插件的功能是插件的目标. 插件绑定生命周期的阶段与插件的目标相互绑定, 以完成某个具体的构建任务. eg: maven-compiler-plugin 对应 default 生命周期的 compile 阶段. clean 生命周期阶段 插件目标 pre-clean clean maven-clean-plugin:clean post-clean default 生命周期阶段 插件目标 process-resources maven-resources-plugin:resources compile maven-compiler-plugin:compile process-test-resources maven-resources-plugin:testResources test-compile maven-compiler-plugin:testCompile test maven-surefire-plugin:test package maven-jar-plugin:jar install maven-install-plugin:install deploy maven-deploy-plugin:deploy default 生命周期还有其他阶段, 默认它们没有绑定任何插件 site 生命周期阶段 插件目标 pre-site site maven-site-plugin:site post-site site-deploy maven-site-plugin:deploy 除了内置绑定, 可以通过自己选择某个插件目标绑定到某个生命周期的某个阶段. 自定义绑定eg: 生成项目的源码 jar 包, 可以利用 maven-source-plugin, 它其中的 jar-no-fork 目标可以将项目主代码打包成 jar 文件, 可以将 default 生命周期 verify 阶段, 在完成集成测试后和安装构件之前创建源码 jar 包. 1234567891011121314151617181920212223<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <version>2.1.1</version> <executions> <execution> <!-- 执行任务 --> <id>attach-sources</id> <!-- 绑定任务执行的生命周期阶段 --> <phase>verify</phase> <!-- 需要执行的插件目标 --> <goals> <goal>jar-no-fork</goal> </goals> <configuration> </configuration> </execution> </executions> </plugin> </plugins></build> 插件配置 命令行插件配置Maven中可以使用 -D 参数, 并伴随一个参数建 = 参数值eg: 编译时跳过项目里的测试代表 1mvn install -Dmaven.test.skip=true POM中插件全局配置如果一些参数从项目创建到项目发布都不会改变或者很少改变, 可以在POM中全局配置.eg: 生成支持Java 1.5 的字节码文件 12345678910111213<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.1</version> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> </plugins></build> POM中插件任务配置还可以为某个插件任务配置特定的参数, 比如上面生成项目源码的例子. 插件解析机制 插件仓库 1234567891011121314<pluginRepositories> <pluginRepository> <id>central</id> <name>Maven Plugin Repository</name> <url>http://repo1.maven.org/maven2</url> <layout>default</layout> <snapshots> <enabled>false</enabled> </snapshots> <releases> <updatePolicy>never</updatePolicy> </releases> </pluginRepository></pluginRepositories> 插件的默认groupIdPOM配置插件时, 如果该插件是 Maven 的官方插件, 可以省略 groupId 的配置. Maven 解析插件时, 如果是 Maven 官方插件会默认获取超级 POM 中设置的版本, 如果是自定义插件, Maven 会先检查所有仓库中可用的版本, Maven3 会直接提取 release进行使用(Maven2 中默认使用 latest 进行解析).]]></content>
</entry>
<entry>
<title><![CDATA[Spring Batch(一)]]></title>
<url>%2F2017%2F07%2F06%2FSpring-Batch-1%2F</url>
<content type="text"><![CDATA[面对现代企业应用当中的复杂业务以及海量的数据,除了页面复杂的人机交互处理,还有一类是不需要人工干预,只需要定期读入大批量数据,按对应的规则处理。这种处理被称为 “批处理 ”。特点: 数据量巨大 不需要的人工干预,根据系统的配置自动处理 按时间配置处理。一天或者一个月执行一次 批处理对应三个环节: 读取数据,数据可能来自文件、数据库或消息队列等 数据处理,如金融系统的对账的计费处理 写数据,将输出结果写入文件、数据库或消息队列等 Spring Batch 不仅提供了统一的读写接口、丰富的任务处理方式、灵活的事务管理以及并发处理,同时还支持日志、监控、任务重启与跳过等特性。Spring Batch 是一款批处理应用框架,不是调度框架。它只关注任务处理的相关问题,如事务、并发、监控、执行等,并不会提供相应的任务调度功能。如果需要批处理任务定期执行,可以结合 Quartz 等调度框架试下。 通过 Spring Batch 将 CSV 文件里的数据写入到数据库里,Spring Batch 会读取数据将数据映射为一个对象中,并在连接数据将生成的数据插入到数据中。 Maven 依赖1234567891011121314<dependencies> <!--批处理核心代码--> <dependency> <groupId>org.springframework.batch</groupId> <artifactId>spring-batch-core</artifactId> <version>3.0.7.RELEASE</version> </dependency> <!--批处理基础访问框架--> <dependency> <groupId>org.springframework.batch</groupId> <artifactId>spring-batch-core</artifactId> <version>3.0.7.RELEASE</version> </dependency></dependencies> Spring Batch 处理周期 输入文件(CSV)→ 读取工具 (Reader)Spring Batch 里的org.springframework.batch.item 中定义了许多内置的 Reader,如数据库(.database.*), 消息队列(.amqp.*),文件(.file.*),大数据(.data.*)等,读取 CSV 文件使用 org.springframework.batch.item.file.FlatFileItemReader 1234567891011121314151617181920212223242526<bean id="playerReader" class="org.springframework.batch.item.file.FlatFileItemReader" scope="step"> <!-- 需要处理的资源路径,下面是通过 jobParameters 指定文件,可以不同 Job 处理不同文件 --> <property name="resource" value="file:#{jobParameters['inputFile']}" /> <!-- 跳过行数 --> <property name="linesToSkip" value="1" /> <!-- 定义一行数据映射的对象--> <property name="lineMapper"> <bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper"> <!-- lineTokenizer 对象,根据某种分割符分割--> <property name="lineTokenizer"> <bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer"> <!--分割符,默认是 ","--> <property name="delimiter" value=","/> <!-- lineTokenizer 会把行数据转换对应格式的 FieldSet的对象--> <property name="names" value="id,name,team,goal" /> </bean> </property> <!-- fieldSetMapper 会将lineTokenizer.tokenize(line) 拆分的数据 --> <property name="fieldSetMapper"> <!--映射到对象方法,需要自己定义--> <bean class="com.dlc.springBatchDemo.reader.PlayerFieldSetMapper" /> </property> </bean> </property></bean> 定义需要映射的对象 123456789101112131415161718192021222324252627282930313233343536373839package com.dlc.springBatchDemo.model; public class Player { private int id; private String name; private String team; private int goal; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getTeam() { return team; } public void setTeam(String team) { this.team = team; } public int getGoal() { return goal; } public void setGoal(int goal) { this.goal = goal; }} 映射处理对象 123456789101112131415161718package com.dlc.springBatchDemo.reader;import com.dlc.springBatchDemo.model.Player;import org.springframework.batch.item.file.mapping.FieldSetMapper;import org.springframework.batch.item.file.transform.FieldSet;import org.springframework.validation.BindException;/** 根据 CSV 文件中的字段集合构建 Player 对象 */public class PlayerFieldSetMapper implements FieldSetMapper<Player> { public Player mapFieldSet(FieldSet fieldSet) throws BindException { Player player = new Player(); player.setId( fieldSet.readInt( "id" ) ); player.setName( fieldSet.readString( "name" ) ); player.setTeam( fieldSet.readString( "team" ) ); player.setGoal( fieldSet.readInt( "goal" ) ); return player; }} 或则直接使用org.springframework.batch.item.file.mappin.BeanWrapperFieldSetMapper , 需要 CSV 转换列和对应 Bean 对象的字段名对应。 application context 配置1234567891011121314151617181920212223242526272829303132333435363738394041424344<beans> <!-- Spring 注释 --> <context:annotation-config /> <!-- 扫包,导入包下 component --> <context:component-scan base-package="com.com.dlc.springBatchDemo" /> <!-- 配置 MySQL Data source --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost/bacth"/> <property name="username" value="dlc"/> <property name="password" value="dlc"/> </bean> <!-- Spring事务管理器, 用于管理MySQL事务 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- Spring 提供的与JDBC connections交互的模板设计模式实现,实际中一般使用Hibernate 等代替--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource" /> </bean> <!-- Job Repository: 保持着所有Job执行的相关元数据 这里使用的MapJobRepositoryFactoryBean用于测试和快速原型,不具备 Spring Batch 多线程和分割等,MapJobRepositoryFactoryBean是线程安全的 --> <bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean"> <property name="transactionManager" ref="transactionManager" /> </bean> <!-- Job Launcher: java程序来通过JobLauncher启动 Job --> <bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher"> <property name="jobRepository" ref="jobRepository" /> </bean> <!-- Reader bean:设置为scope 设置为 Step,当对应bean 使用 Spring Batch 的 JobParameters启动时是不存在,使用 step scope 使Spring Batch在创建ean 时能加载配置 JobParameters 参数 --> <bean id="productReader" class="org.springframework.batch.item.file.FlatFileItemReader" scope="step"> ... </bean></beans> 处理程序 (Processor)处理程序不是 Spring Batch 处理里必须 对 CSV 文件里的数据进行计数 1234567891011121314151617181920212223242526272829303132333435363738394041package com.dlc.springBatchDemo.processor;import com.dlc.springBatchDemo.model.Player;import org.springframework.batch.item.ItemProcessor;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.jdbc.core.RowMapper;import java.sql.ResultSet;import java.sql.SQLException;import java.util.List;/** * Processor that finds existing players and updates a player goal */public class PlayerGoalProcessor implements ItemProcessor<Player,Player> { private static final String GET_PLAYER = "select * from PLAYER where id = ?"; @Autowired private JdbcTemplate jdbcTemplate; public Player process(Player player) throws Exception { // Retrieve the player from the database List<Player> playerList = jdbcTemplate.query(GET_PLAYER, new Object[] {player.getId()}, new RowMapper<Player>() { public Player mapRow( ResultSet resultSet, int rowNum ) throws SQLException { Player p = new Player(); p.setId( resultSet.getInt( 1 ) ); p.setName( resultSet.getString( 2 ) ); p.setTeam( resultSet.getString( 3 ) ); p.setGoal( resultSet.getInt( 4 ) ); return p; } }); if( playerList.size() > 0 ) { Player existingPlayer = playerList.get( 0 ); player.setGoal( existingPlayer.getGoal() + player.getGoal()) ); } return player; }} PlayerGoalProcessor 只是对数据进行进球数据进行数据统计,此 processor 没有进行数据过滤,但如果 process() 方法返回的结果是 null, 则Spring Batch 将会忽略这个 item, 不将其发送给 Writer 配置 applicationContext.xml 引入 Bean 1<bean id="playerGoalProcessor" class="com.dlc.springBatchDemo.processor.PlayerGoalProcessor" /> 写工具 (Writer)→数据库 (DataBase)123456789101112131415161718192021222324252627282930313233343536373839404142434445package com.dlc.springBatchDemo.writer;import com.dlc.springBatchDemo.model.Player;import org.springframework.batch.item.ItemWriter;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.jdbc.core.RowMapper;import java.sql.ResultSet;import java.sql.SQLException;import java.util.List;/** * Writes players to a database */public class PlayerItemWriter implements ItemWriter<Player>{ private static final String GET_PLAYER = "select * from PLAYER where id = ?"; private static final String INSERT_PLAYER = "insert into PLAYER (id,name,team,goal) values (?,?,?,?)"; private static final String UPDATE_PLAYER = "update PLAYER set name = ?, team = ?,goal = ? where id = ?"; @Autowired private JdbcTemplate jdbcTemplate; public void write(List<? extends Player> players) throws Exception { for( Player player : players ){ List<Player> playerList = jdbcTemplate.query(GET_PLAYER, new Object[] {player.getId()}, new RowMapper<Player>() { public Player mapRow( ResultSet resultSet, int rowNum ) throws SQLException { Player p = new Player(); p.setId( resultSet.getInt( 1 ) ); p.setName( resultSet.getString( 2 ) ); p.setTeam( resultSet.getString( 3 ) ); p.setGoal( resultSet.getInt( 4 ) ); return p; } }); if( playerList.size() > 0 ){ jdbcTemplate.update( UPDATE_PLAYER, player.getName(), player.getTeam(), player.getGoal(), player.getId() ); }else{ jdbcTemplate.update( INSERT_PLAYER, player.getId(), player.getName(), player.getTeam(), player.getGoal() ); } } }} 通过实现ItemWriter继承并实现了其唯一的方法: write() 。write() 方法接受一个泛型 Player 的 list . Spring Batch 使用“chunking”策略实现其 writers , 读取时是一次执行一个item, 而写入时是将一组数据一块写。 可以通过 commit-interval 配置控制每次一起写入的item的数量。 applicationContext.xml 引入 Bean 1<bean id="playerWriter" class="com.dlc.springBatchDemo.writer.ProductItemWriter" /> 配置 Jobimport-csv-job.xml 1234567891011<beans> <!-- Import our beans --> <import resource="classpath:/applicationContext.xml" /> <job id="simpleFileImportJob" xmlns="http://www.springframework.org/schema/batch"> <step id="importFileStep"> <tasklet> <chunk reader="playerReader" processor="playerGoalProcessor" writer="playerWriter" commit-interval="5" /> </tasklet> </step> </job></beans> 一个 job 可以包含 0 到 多个 step; 一个 step 可以包含 0 到 多个 tasklet; 一个 tasklet 可以包含 0 到多个 chunk. 一个 job 可以包含 0到多个 step; 一个 step 可以有 0/1 个tasklet; 一个 tasklet 可以有 0/1 个 chunk。 多个 processors通过设计批处理的适当的粒度来创建多个 item processor,然后按顺序在同一个 chunk之 中执行。比如:需要processor 来正确地管理 item 数量,需要跳过某个八强被灌3个球力夺银靴的球员。 12345678910<bean id="playerGoalProcessor" class="com.dlc.springBatchDemo.processor.PlayerGoalProcessor" /><bean id="playerFilterProcessor" class="com.dlc.springBatchDemo.processor.playerFilterProcessor" /><bean id="playerCompositeProcessor" class="org.springframework.batch.item.support.CompositeItemProcessor"> <property name="delegates"> <list> <ref bean="playerFilterProcessor" /> <ref bean="playerGoalProcessor" /> </list> </property></bean> Tasklets(微线程)Spring Batch 会分块读取 CSV 文件,依次读取每一个 item,在经过 processor 处理,处理完成之后会将结果收集并分组为 chunks , 然后把这些记录发送给 writer ,在这里是插入到数据库中。而有时需要一个步骤的 tasklet 不进行读写操作,只进行如:下载文件,压缩解密规定文件,Spring Batch 支持 自定义定义一个tasklet。 ArchivePlayerDataTasklet.java 1234567891011121314151617181920212223242526272829303132333435package com.dlc.springBatchDemo.tasklet;import org.apache.commons.io.FileUtils;import org.springframework.batch.core.StepContribution;import org.springframework.batch.core.scope.context.ChunkContext;import org.springframework.batch.core.step.tasklet.Tasklet;import org.springframework.batch.repeat.RepeatStatus;import java.io.File;/** * Collect player goal data * 实现Tasklet 接口的 execute() 方法 */public class ArchivePlayerDataTasklet implements Tasklet{ private File inputFile; public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception { File archiveDir = new File( inputFile.getParent() + File.separator+"archive"); FileUtils.forceMkdir( archiveDir ); System.out.println(inputFile); FileUtils.copyFileToDirectory( inputFile , archiveDir ); return RepeatStatus.FINISHED; } public File getInputFile() { return inputFile; } public void setInputFile(File inputFile) { this.inputFile = inputFile; }} applicationContext.xml 123<bean id="archiveFileTasklet" class="com.dlc.springBatchDemo.tasklet.ArchivePlayerDataTasklet" scope="step"> <property name="inputFile" value="#{jobParameters['inputFile']}" /></bean> import-csv-job.xml 123456789<beans> <!-- Import our beans --> <import resource="classpath:/applicationContext.xml" /> <job id="simpleFileImportJob" xmlns="http://www.springframework.org/schema/batch"> <step id="archive"> <tasklet id="archiveFileTasklet"></tasklet> </step> </job></beans> Resiliency(弹性) Skipping Items(跳过某项) 跳过某些记录, 比如 reader 读取的无效记录,或者处理/写入过程中出现异常的对象。 要跳过记录有两种方式: 在 chunk 元素上定义 skip-limit 属性, 告诉Spring 最多允许跳过多少个 items,超过则 job 失败(如果无效记录很少那可以接受,但如果无效记录太多,那可能输入数据就有问题了)。 定义一个 skippable-exception-classes 列表, 用来判断当前记录是否可以跳过, 可以指定 include 元素来决定发生哪些异常时会跳过当前记录, 还可以指定 exclude 元素来决定哪些异常不会触发 skip( 比如你想跳过某个异常层次父类, 但排除一或多个子类异常时)。 示例如下: 1234567891011<job id="simpleFileImportJob" xmlns="http://www.springframework.org/schema/batch"> <step id="importFileStep"> <tasklet> <chunk reader="productReader" processor="productProcessor" writer="productWriter" commit-interval="5" skip-limit="10"> <skippable-exception-classes> <include class="org.springframework.batch.item.file.FlatFileParseException" /> </skippable-exception-classes> </chunk> </tasklet> </step></job> 这里在处理某条记录时如果抛出 FlatFileParseException 异常, 则这条记录将被跳过。 如果超过10次 skip, 那么直接让 job 失败。 重试(Retrying Items) 有时发生的异常是可以重试的, 如由于读入数据库锁导致的失败。 重试(Retry)的实现和跳过(Skip)非常相似: 在 chunk 元素上定义 retry-limit 属性, 告诉Spring 每个 item 最多允许重试多少次, 超过则认为该记录处理失败。 如果只用重试, 不指定跳过,则如果某条记录重试处理失败, 则 job将被标记为失败。 定义一个 retryable-exception-classes 列表, 用来判断当前记录是否可以重试; 可以指定 include 元素来决定哪些异常发生时当前记录可以重试, 还可以指定 exclude 元素来决定哪些异常不对当前记录重试执行.。 例如: 1234567891011<job id="simpleFileImportJob" xmlns="http://www.springframework.org/schema/batch"> <step id="importFileStep"> <tasklet> <chunk reader="productReader" processor="productProcessor" writer="productWriter" commit-interval="5" retry-limit="5"> <retryable-exception-classes> <include class="org.springframework.dao.OptimisticLockingFailureException" /> </retryable-exception-classes> </chunk> </tasklet> </step></job> 还可以将重试和可跳过的异常通过 skippable exception 与 retry exception 对应起来。 因此, 如果某个异常触发了5次重试, 5次重试之后还没搞定, 恰好该异常也在 skippable 列表中, 则这条记录将被跳过。 如果 exception 不在 skippable 列表则会让整个 job 失败。 重启 job 对于执行失败的 job作业, 我们可以重新启动,并让他们从上次断开的地方继续执行。 要做到这一点, 只需要使用和上次一模一样的参数来启动 job, 则 Spring Batch 会自动从数据库中找到这个实例然后继续执行。 配置数据库由于配置里使用的是 MapJobRepositoryFactoryBean ,Spring Batch 默认使用的内存数据,只需要创建 Player 对象的表 1234567CREATE TABLE PLAYER ( ID INT NOT NULL, NAME VARCHAR(128) NOT NULL, TEAM VARCHAR(128), GOAL INT, PRIMARY KEY(ID) ); 如果Spring Batch 需要使用 Mysql 将<bean id="jobRepository"> 改为 1<batch:job-repository id="jobRepository" data-source="dataSource" /> 同时需要手动导入 Spring Batch 的表 spring-batch-core.jar/org/springframework/batch/core/schema-mysql.sql 如果只是测试也可以在 applicationContext.xml 里添加 1234<jdbc:initialize-database data-source="dataSource"> <jdbc:script location="org/springframework/batch/core/schema-drop-mysql.sql" /> <jdbc:script location="org/springframework/batch/core/schema-mysql.sql" /></jdbc:initialize-database> 测试批量任务在测试资源目录resources\添加需要导入的文件 sample.csv 12345678id,name,team,goal1,Cristiano Ronaldo,Real Madrid, 122,Lionel Messi,Barcelona, 113,Lewandowski,Bayern München, 84,Cavani,Paris Saint-Germain, 85,Aubameyang,Dortmund, 76,Mbappé,Monaco, 67,Griezmann,Barcelona, 6 pom 里添加依赖 1234567891011121314151617181920212223242526<project> ... <dependencies> ... <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.batch</groupId> <artifactId>spring-batch-test</artifactId> <version>${spring.batch.version}</version> <scope>test</scope> </dependency> ... </dependencies> ...</project> 添加单元测试类 AppTest.java 123456789101112131415161718192021222324252627282930313233343536373839package com.dlc.springBatchDemo;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.batch.core.*;import org.springframework.batch.core.launch.JobLauncher;import org.springframework.batch.item.ExecutionContext;import org.springframework.batch.item.ItemReader;import org.springframework.batch.item.ItemStream;import org.springframework.batch.test.JobLauncherTestUtils;import org.springframework.batch.test.StepScopeTestExecutionListener;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.TestExecutionListeners;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;import java.util.Date;import static org.junit.Assert.assertEquals;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration({ "classpath:/applicationContext.xml","classpath:/jobs/csv-import-job.xml","classpath:test-contxt.xml"})public class BatchSpringContextTest { @Autowired private Job csvImportJob; @Autowired private JobLauncherTestUtils jobLauncherTestUtils; @Test public void launchJobWithJobLauncherTest() throws Exception { JobParameters jobParameters = new JobParametersBuilder().addString("inputFile","sample.csv").toJobParameters(); jobLauncherTestUtils.setJob(csvImportJob); JobExecution jobExecution = jobLauncherTestUtils.launchJob(jobParameters); assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus()); }} Spring Batch Demo 学习参考自 Reading and writing CVS files with Spring Batch and MySQL]]></content>
</entry>
<entry>
<title><![CDATA[Maven 学习笔记(四)]]></title>
<url>%2F2017%2F06%2F19%2FMaven-Note-4%2F</url>
<content type="text"><![CDATA[Maven 是通过设计的插件机制来实现 Maven 构件项目的的周期. 比如 :编译周期有 maven-compiler-plugin, 而针对测试插件有 maven-surefire-plugin 等.Maven 拥有3套相互独立的生命周期,clean, default 和 site. clean 生命周期的目的是为了清理项目, default生命周期的目的是为了构件项目, site生命周期的目的是为了建立项目站点. clean 阶段 pre-clean 执行一些清理前需要完成的工作 clean 清理上一次构件生成的文件 post-clean 执行一些清理后需要完成的工作 default 阶段 validate 验证项目是正确的, 所有重要的信息是可用 initialize 初始化构建状态, eg: 设置属性, 创建目录 generate-sources 编译原代码 process-sources 处理源代码, eg: 过滤一些值 genreate-resources 生成资源文件 process-resources 复制和处理资源到目标目录,准备进行打包 compile 编译项目的源代码 process-classes 处理编译生成文件, 比如JAVA文件的字节码 generate-test-sources 生成测试编译文件的 process-test-sources 处理测试源代码, eg: 过滤一些值 genreate-test-resources 创建测试配置文件 process-test-resources 复制和处理资源到测试目标目录 test-compile 编译项目测试的源代码到指定目录 process-test-classes 处理测试编译生成的文件 test 使用单元测试框架运行测试, 测试源代码不会被打包 prepare-package 准备打包版本 package 接收编译代码,打包成一个可发布格式,例如一个JAR pre-integration-test 集成到测试环境前需要采取的行动, eg: 配置测试环境 integration-test 处理,并部署包在中,集成到测试环境中(如果有必要) post-integration-test 进行集成测试执行后需要采取的行动 eg: 清理环境 verify 运行任何检查,以验证包是有效性,并符合标准 install 安装包到本地仓库,用作当地其他项目的依赖 deploy 将包部署到远程仓库, 与其他开发人员共享和项目 site 阶段 pre-site 执行一些生成项目站点之前需要完成的工作 site 生成项目站点文件 post-site 执行一些生成项目站点之后需要完成的工作 site-deploy 将项目站点发布到服务器上 ##命令对应的生命周期: $mvn clean 调用 clean 生命周期的clean阶段. 实际执行阶段为 clean 生命周期的 pre-clean 和 clean阶段 $mvn test 调用 default 生命周期的 test 阶段. 实际执行阶段为 default 生命周期的 validate , initialize等阶段, 直到 test 所有阶段 $mvn clean install 调用 clean 生命周期的 clean 阶段和 default 生命周期的 install 阶段. 实际执行阶段为 clean 生命周期的 pre-clean 和 clean 阶段, 和 default 生命周期的 validate , initialize等阶段, 直到 install 所有阶段 $mvn clean deploy site-deploy 调用 clean 生命周期的 clean 阶段和 default 生命周期的 deploy 阶段, 以及 site 生命周期的 deploy-site 阶段. 实际执行阶段为 clean 生命周期的 pre-clean 和 clean 阶段, 和 default 生命周期的所有阶段, site 生命周期所有阶段.]]></content>
</entry>
<entry>
<title><![CDATA[Maven 学习笔记(三)]]></title>
<url>%2F2017%2F05%2F15%2FMaven-Note-3%2F</url>
<content type="text"><![CDATA[Maven 中, 任何一个依赖,插件或者项目构建的输出, 被称为构件. 利用坐标机制, Maven 会使用一个统一位置来存储所有Maven项目共享的构建, 就是 Maven 仓库. 对应一个构建在Maven仓库的路径一般为 groupId/artifactId/version/artifactId-version[-classifier].packaging Maven 仓库的分类 本地仓库 本机用户目录下的.m2/repository 可以通过修改配置文件(~/.m2/settings.xml)自定义本地仓库目录, 也可以修改全局配置文件($MAVEN_HOME/conf/settings.xml) 123<settings> <localRepository>customer Path </localRepository></settings> 远程仓库 包括中央仓库和私服, 可以修改配文件或者POM文件添加远程仓库地址 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697 <settings> ... <profiles> <profile> <!-- profile配置的唯一标识符 --> <id></id> <activation> <!--profile默认是否激活的标识 --> <activeByDefault>false</activeByDefault> <!--检测jdk版本,与设置一样profile被激活。 --> <jdk>1.7</jdk> <!--匹配的操作系统属性被检测到,profile被激活 --> <os> <!--激活profile的操作系统的名字 --> <name>Windows XP</name> <!--激活profile的操作系统所属家族(如 'windows') --> <family>Windows</family> <!--激活profile的操作系统体系结构 --> <arch>x86</arch> <!--激活profile的操作系统版本 --> <version>5.1.2600</version> </os> <!--如果Maven检测到某一个属性(其值可以在POM中通过${名称}引用),其拥有对应的名称和值,Profile就会被激活。--> <!--如果值字段是空的,那么存在属性名称字段就会激活profile,否则按区分大小写方式匹配属性值字段 --> <property> <!--激活profile的属性的名称 --> <name>mavenVersion</name> <!--激活profile的属性的值 --> <value>2.0.3</value> </property> <!--提供一个文件名,通过检测该文件的存在或不存在来激活profile。--> <file> <!--如果指定的文件存在,则激活profile。 --> <exists>/usr/local/hudson/hudson-home/jobs/maven-guide-zh-to-production/workspace/</exists> <!--如果指定的文件不存在,则激活profile。 --> <missing>/usr/local/hudson/hudson-home/jobs/maven-guide-zh-to-production/workspace/</missing> </file> </activation> <!--对应profile的扩展属性列表。Maven属性和Ant中的属性一样,可以用来存放一些值。这些值可以在POM中的任何地方使用标记${X}来使用,这里X是指属性的名称。--> <!--属性有五种不同的形式,并且都能在settings.xml文件中访问。 --> <!--1. env.X: 在一个变量前加上"env."的前缀,会返回一个shell环境变量。例如,"env.PATH"指代了$path环境变量(在Windows上是%PATH%)。 --> <!--2. project.x:指代了POM中对应的元素值。 --> <!--3. settings.x: 指代了settings.xml中对应元素的值。 --> <!--4. Java System Properties: 所有可通过java.lang.System.getProperties()访问的属性都能在POM中使用该形式访问, --> <!-- 如/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre。 --> <!--5. x: 在<properties/>元素中,或者外部文件中设置,以${someVar}的形式使用。 --> <properties> <!-- 这个profile被激活,则属性${user.install}就可以被访问了 --> <user.install></user.install> </properties> <!-- POM文件修改在 project 标签内添加 --> <repositories> <repository> <!-- 仓库ID, 唯一的, Maven自带的中央仓库使用的ID是central, 如果添加的其它仓库也使用了该ID, 会覆盖 --> <id></id> <name></name> <url></url> <!-- 是否支持发布版本下载 --> <releases> <enabled>true</enabled> <!-- 配置更新频率, 默认daily, 每天检查一次. never 从不检查更新 always 每次构建时检查更新 interval: X 每隔X分钟检查更新 --> <updatePolicy></updatePolicy> <!-- 配置检查检验和文件策略, 构建时下载构件出现校验和验证的失败, 默认为warn, 会输出警告信息 fail Maven遇到校验和验证的失败, 让构建失败 ignore Maven完全忽略校验和验证的失败错误 --> <checksumPolicy></checksumPolicy> </releases> <!-- 是否支持快照版本下载 --> <snapshots> <enabled>false</enabled> </snapshots> <layout>default</layout> </repository> <!-- 可以添加多个地址 --> <repository> ... </repository> </repositories> </profile> </profiles> <servers> <server> <!-- 对应Repository的ID --> <id><id> <username></username> <password></password> </server> </servers> ...</settings> 部署至远程仓库私服可以部署第三方构件, 可以通过配置POM文件或者部署命令将项目生成的构件部署到仓库中. 12345678910111213141516<project> ... <distributionManagement> <repositroy> <id>Release Repository ID</id> <name>Release Repository Name</name> <url>deploy URL</url> </repositroy> <snapshotRepository> <id>Snapshot Repository ID</id> <name>Snapshot Repository Name</name> <url>deploy URL</url> </snapshotRepository> </distributionManagement> ...</project> 配置完后, 命令运行mvn clean deploy即可.如果不配置POM, 则使用: 1234mvn clean deploy -U -Dmaven.test.skip=true -DaltDeploymentRepository=id::layout::url # id: 对 应 setting 中<servers>标签里配置的 Repository ID# layout: Either default for the Maven2 layout or legacy for the Maven1 layout. Maven3 also uses the default layout.# url: The location of the repository 部署或者是下载构件到远程仓库, 当需要认证时, 配置方式都是一致的. 快照版本在快照发布到私服时, Maven 会自动为构件打上时间戳, 当构建最新项目时, Maven会从仓库中检查对应快照版本的默认的最新构件, 发现有更新时会下载. 默认情况下(未修改snapshots下的updatePolicy), Maven 会每天检查一次更新, 构建时可以使用 -U 强制检查更新. 1mvn clean install -e -U -Dmaven.skip=true 从仓库解析依赖的机制 当依赖范围是 system 的时候, Maven 直接从本地文件系统解析构件. 根据依赖坐标计算仓库路径, 尝试直接从本地仓库寻找构件, 如果发现相应构件, 则解析成功. 在本地仓库不存在相应构件的情况下, 如果依赖的版本是显示的发布版本构件, 如 1.1, 2.3 等, 则遍历所有远程仓库, 发现后, 下载并解析使用. 如果依赖的版本是 RELEASE 或者 LATEST, 则基于更新策略读取所有远程仓库的元数据 groupId/artifactId/version/maven-metadata.xml, 将其与本地仓库的对应元数据合并后, 计算出 RELEASE 的真实值, 然后基于这个真实值检查本地和远程仓库 如果依赖的版本是 SNAPSHOT, 则基于更新策略读取所有远程仓库的与则基于更新策略读取所有远程仓库的元数据 groupId/artifactId/version/maven-metadata.xml, 将其与本地仓库的对应元数据合并后, 计算出快照的最新版本, 然后基于这个真实值检查本地和远程仓库. 如果最后解析得到的构件是时间格式的快照, 会将其复制为非时间戳的格式, 并会使用该构件. △: 依赖和声明中不推荐使用 LATEST 和 RELEASE, 由于 Maven 构件的解析机制可能会不同时间的构件会解析到不同版本的构件. 镜像如果仓库 A 可以提供 仓库 B 的所有的内容, 则 A 是 B 仓库的镜像. 则任何从 B 仓库获取的构件, A 也可获取. 可以通过修改setting.xml使用镜像. 1234567891011121314151617181920212223<settings> ... <mirrors> <mirror> <!-- 该镜像的唯一标识 --> <id></id> <name></name> <url></url> <!-- 值对应一般仓库的Id,*(所有) --> <mirrorOf></mirrorOf> <!-- 通配例子 --> <!-- 匹配所有远程仓库 --> <mirrorOf>*</mirrorOf> <!-- 匹配所有不在本机上的远程仓库, 如localhost, file:// --> <mirrorOf>external: *</mirrorOf> <!-- 匹配仓库 repo1, repo2. 多个仓库用 , 分开 --> <mirrorOf>repo1, repo2</mirrorOf> <!-- 匹配所有仓库, 除了仓库 repo1 --> <mirrorOf>*, !repo1</mirrorOf> </mirror> </mirrors> ...</settings>]]></content>
</entry>
<entry>
<title><![CDATA[Java 项目部署(一)]]></title>
<url>%2F2017%2F04%2F11%2FSystem-Deploy-1%2F</url>
<content type="text"><![CDATA[上周六折腾了一天终于把快一年前的坑给填上了。阿里是越来越会玩了,ECS的价格从原来的40一个月慢慢的涨到了80。发现了腾讯服务器特惠,免费一个月加几张优惠劵,够半年了。把自己开发的一个轻博客部署上去了,这个博客整体样式仿照 Tumblr。注册的时候连接Outlook邮箱发注册邮件老是抽风,有时候邮件可以发成功有时候连接失败,下次有时间注册个邮件平台。 打算系统的记录下项目部署的过程和其中的遇到的的坑。 系统采用的是 Apache Https + Tomcat + MySql,采用的是企鹅家的云服务器,系统是 Centos,只开放了 80 端口供网页访问。 最后附上网站的链接。 Honks]]></content>
</entry>
<entry>
<title><![CDATA[Java Puzzler(5-6)]]></title>
<url>%2F2017%2F03%2F26%2FJavaPuzzler-2%2F</url>
<content type="text"><![CDATA[5. 十六进制和八进制12345678910111213System.out.println(0x80);//128//0x81看作是int型,最高位(第32位)为0,所以是正数System.out.println(0x81);//129System.out.println(0x8001);//32769System.out.println(0x70000001);//1879048193//字面量0x80000001为int型,最高位(第32位)为1,所以是负数System.out.println(0x80000001);//-2147483647//字面量0x80000001L强制转为long型,最高位(第64位)为0,所以是正数System.out.println(0x80000001L);//2147483649//最小int型System.out.println(0x80000000);//-2147483648//只要超过32位,就需要在字面常量后加L强转long,否则编译时出错System.out.println(0x8000000000000000L);//-9223372036854775808 △ 如果Hex和Octal转换为10进制时字面常量的最高位为1,这个数为负数 十六进制的字面常量表示的是int型,如果超过32位,则需要在后面加“L”,否则编译过不过。如果为32,则为负int正数,超过32位,则为long型,但需明确指定为long。 通常最好避免混合类型运算 6. 多重转型(二进制原理) Type Bit Length Int 32位 2^31-1 byte 8位 2^7-1 char 16位 2^16-1 数据类型都要保留最高位作为符号位 有符号的数据类型存储是先将其无符号数Binary,在将其到最高位都置1如: 1234System.out.println(Integer.toBinaryString(-1));//1111 1111 1111 1111 1111 1111 1111 1111System.out.println(Integer.toBinaryString(-100));//1111 1111 1111 1111 1111 1111 1001 1100 符号扩展进行符号扩展,即短数据类型的符号位填充到长数据类型的高字节位(即比短数据类型多出的那一部分),保证扩展后的数值大小不变 123byte x=-1; int y=x; //则x的二进制值为1111 1111,y的值应为1111 1111 1111 1111 1111 1111 1000 1001;byte =1; short y=x; //则y的值应为0000 0000 0000 0000 0000 0000 0000 0001; 零扩展进行零扩展,即用零来填充长数据类型的高字节位 12unsigned char x=1000 1001b; short y=x; //则y的值应为00000000 10001001b;unsigned char x=0000 1001b; short y=x; //则y的值应为00000000 00001001b; △ 从较窄整型转换成较宽整型规定:如果最初的数值类型是有符号的,就进行符号扩展;如果它是char,那么不管它转化成什么类型,都是进行零扩展 12345678char c = (char)(0xff & b);/* 0000 0000 0000 0000 0000 0000 1111 1111 (0Xff) & 1111 1111 1111 1111 1111 1111 1001 1100 (b=-100) ----------------------------------------- 0000 0000 0000 0000 0000 0000 1001 1100 (100)*///0xff是第八位全部置1;其他位全部置0;//上面是不进行符号扩展]]></content>
</entry>
<entry>
<title><![CDATA[Maven 学习笔记(二)]]></title>
<url>%2F2017%2F03%2F11%2FMaven-Note-2%2F</url>
<content type="text"><![CDATA[Maven Dependency,Maven 除了快速构建项目外,还有一大功能就是管理项目依赖。Maven 的依赖管理通过groupId、artifactId、version等标识确定一个依赖的坐标,从而通过 Maven 仓库或获取对应的项目依赖的 Jar,自动化的解析任何一个 Java 构件。 Maven 坐标 groupId: 定义当前Maven项目隶属的实际项目. artifactId: 定义实际项目中的一个Maven项目(模块). version: 定义maven项目当前所处的版本. packaging: 定义Maven项目的打包方式. classifier: 定义构建输出的一些附属构件. 例如:一个项目的主构件是xxx-xxx-7.0.0.jar, 可能还需要javadoc和source, 这时javadoc和source就是附属构件的classifier, classifier不能定义, 它不是默认生成的, 而是由附加插件帮助生成的. groupId, artifactId, version是必须的, packaging 是可选的(默认jar), 而classifier是不能自定义的. maven项目生成的文件名一般为 artifactId-version[-classifier].packaging 依赖 POM 定义123456789101112131415161718192021222324<project>... <!-- 项目所有的依赖--> <dependencies> <!-- 定义一个模块使用的一个依赖--> <dependency> <!-- 依赖的基本坐标--> <groupId></groupId> <artifactId><artifactId> <version></version> <!-- 依赖类型,对应项目目标定义中的packaging, 不声明默认为Jar --> <type></type> <!-- 依赖作用范围--> <scope></scope> <!-- 标记依赖是否可选--> <optional></optional> <!-- 需要排除的依赖 --> <exclusions> <exclusion></exclusion> </exclusions> </dependency> </dependencies>...</project> 依赖范围ScopeMaven会使用3种classpath来控制使用的依赖(编译classpath, 测试classpath, 运行测试classpath).Maven有以下几种依赖范围. compile 编译依赖范围. 默认依赖范围, 对应编译, 测试, 运行三种classpath都有效. eg: Spring-core test 测试依赖范围. 只对测试classpath有效, 在编译主代码或者运行项目中无法使用该依赖. eg: JUint provided 已提供的依赖范围. 对于编译和测试时有效, 运行时无效使用. eg: servlet-api runtime 运行时依赖范围. 对应测试和运行时有效, 但项目编译时无效. eg: JDBC ,编译时使用JDK提供的JDBC接口. system 系统依赖范围. 依赖范围和provided完全一致, 但是需要显示的指定依赖文件路径. 此类不是由Maven仓库解析处理,往往与本机系统绑定 1234567<dependency> <groupId></groupId> <artifactId><artifactId> <version></version> <scope>system</scope> <systemPath>${java.home}/lib/rt.jar</systemPath></dependency> import 导入依赖范围. 该依赖不会对classpath产生实际影响. Scope compile classpath test classpath runtime classpath compile Y Y Y test - Y - provided - Y Y runtime - Y Y system Y Y - 依赖传递依赖范围不但可以控制3种classpath的依赖,对传递性依赖也会产生影响. compile test provided runtime compile compile - - runtime test test - - test provided provided - provided provided runtime runtime - - runtime eg: Honks Test (Scope:Test, 对应表中行,第一依赖) 依赖Spring-email(Scope:compile, 对应表中列,第二依赖), Spring-email依赖java-mail. 则Honks Test通过传递依赖java-mail 依赖调解 依赖路径最近者优先 依赖路径相同, 先声明的优先 eg: A -> B -> C -> X(1.0), A -> B -> X(2.0), 优先使用 X(2.0) [路径更短] A -> B -> X(1.0), A -> B -> X(2.0), 优先使用 X(1.0) [先声明] 依赖定义优化 定义优化 12345678910111213141516171819202122232425262728293031<project> <modleVersion>4.0.0</modleVersion> <groupId>com.dlc.maven</groupId> <artifactId>maven</artifactId> <version>1.0.0</version> <!-- 依赖归类 --> <properties> <springframework.version>3.6</springframework.version> </properties> <dependencies> <dependency> <!-- 使用依赖归类 --> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${springframework.version}</version> <groupId>org.springframework</groupId> <artifactId>maven-dep</artifactId> <version>${springframework.version}</version> <groupId>com.dlc.maven</groupId> <artifactId>maven-dep</artifactId> <version>1.0.0</version> <!-- 依赖排除 --> <exclusions> <exclusion> <groupId>com.dlc.maven</groupId> <artifactId>maven-dep-dep</artifactId> </exclusion> </exclusions> </dependency> </dependencies> </project> 依赖优化 12345678# 查看当前项目的已解析依赖mvn dependency:list# 查看当前项目的依赖树mvn dependency:tree# 分析当前项目依赖mvn dependency:analyze# 输出 Used undeclared dependencies, 项目中使用的但没有显式声明的依赖(但当前项目依赖的传递性依赖中存在)# 输出 Unused declared dependencies, 项目未使用的, 当显式声明的依赖]]></content>
</entry>
<entry>
<title><![CDATA[Java Annotation]]></title>
<url>%2F2017%2F02%2F27%2FJava_Annotation%2F</url>
<content type="text"><![CDATA[Java Annotation是JDK5.0引入的一种注释机制。随着 Spring 引入了大量的注释类,相比 XML 配置,注释配置更受欢迎,有进一步流行的趋势。可以通过 自定义一些注释来很大程度上减少代码。深入学习注解,就必须能定义自己的注解,并使用注解,在定义自己的注解之前,就必须要了解Java提供的元注解和相关定义注解的语法。 定义 Annotaiion需要声明为@interface @Target规定注释一定要写在什么语句上面@Target(ElementType.对应类型) 12345678910111213TYPE: 类,接口或者Enum声明FIELD: 域(属性)声明METHOD: 方法声明PARAMETER: 参数申明CONSTRUCTOR: 构造方法声明LOCAL_VARIABLE: 局部变量声明ANNOTATION_TYPE: 注释类声明PACKAGE: 包声明Java 8 之前的版本中,只能允许在声明式前使用 Annotation(Annotaion可以在任何使用Type的地方)TYPE_PARAMETER: Type 的声明式前TYPE_USE: 所有使用 Type 的地方(如:泛型,类型转换等) @Retention 需要在什么级别保存该注释信息@Retention(RetentionPolicy.对应类型) SOURCE: 注释将被编译器丢弃,例如@Override,这种只起到标示的注释 CLASS: 注释在class中,但是会被VM丢弃 RUNTIME: 注释在class中,VM中也会存在 @Documented 将此注解包含在Javadoc中 使用注释12345678910@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface ValueBind { enum fieldType{ STRING,INT } fieldType type(); String value();} 使用的Bean对象123456789101112131415161718192021222324252627282930313233public class Student implements Serializable { private String studentId; private int age; private String name; public String getStudentId() { return studentId; } @ValueBind(type = ValueBind.fieldType.STRING,value = "7777") public void setStudentId(String studentId) { this.studentId = studentId; } public int getAge() { return age; } @ValueBind(type = ValueBind.fieldType.INT,value = "21") public void setAge(int age) { this.age = age; } public String getName() { return name; } @ValueBind(type = ValueBind.fieldType.STRING,value = "wuyu") public void setName(String name) { this.name = name; }} 测试12345678910111213141516171819202122232425262728 public static void main(String[] args) throws Exception { Object c = Class.forName("Student").newInstance(); /** * getMethod*() 获取的是类的public method * including those declared by the class(自己) or interface(接口) and those inherited from superclasses and superinterfaces(父类,父接口) * getDeclaredMethod*() 只得到自身申明的所有方法, * 包括public, protected, default (package) access, and private methods, but excluding inherited methods * * 对应没有method返回一个length=0 Array */ Method[] methodArray = c.getClass().getDeclaredMethods(); for (Method method: methodArray) { if(method.isAnnotationPresent(ValueBind.class)){ ValueBind annotation = method.getAnnotation(ValueBind.class); String type = String.valueOf(annotation.type()); String value = annotation.value(); if("INT".equals(type)){ method.invoke(c,new Integer(value)); }else{ method.invoke(c,value); } } } AnnotationDemo1 annotationStudent = (AnnotationDemo1) c; System.out.println("StudentId===="+annotationStudent.getStudentId()); System.out.println("StudentName===="+annotationStudent.getName()); System.out.println("StudentAge===="+annotationStudent.getAge());}]]></content>
</entry>
<entry>
<title><![CDATA[Java Puzzler(1-4)]]></title>
<url>%2F2017%2F02%2F11%2FJavaPuzzler-1%2F</url>
<content type="text"><![CDATA[1. 奇数性123public static boolen isOdd(int i){ return i %2 ==1;} 上面的method是错误的,会在1/4的时间里返回的是错误值 a % b = c中c的值取决于a;只要a为正,无论b取何值,若有余数,c一定为正,同理可知a为负,c一定为负值。correct method:123456public static boolen idOdd(int i){ rutrun i%2 != 0;}punlic static boolen idOdd(int i){ retrun (i&1)!=0;} 2. 找零时刻12345public class change{ punlic static void main (String[] args){ System.out.println(2.00-1.10); }} 以上不会输出 0.9,而是0.899999999999使用printf("%.2f%n"2.00-1.00);但是使用的double。△ Double是在一个很广的值域上提供一个很好的相识值,并不是精确值。在需要精确答案是,建议是要避免是用float和double,对于货币计算,建议使用int和long,Bigdecimal一定要使用Bigdecimal(String)构造器,千万不要使用BIgdecimal(double),返回仍会是不精确的值。 3. 长整除1234567public class LongDivsion{ public static void main(String[] args){ final long a=24*60*60*1000*1000; final long b=24*60*60*1000; System.out.println(a/b); }} 以上返回不会输出1000,而是5。因为24*60*60*1000*1000会溢出,它并不是一个Long型,而是先算出结果后在转换成Long型的a。 1234567public class LongDivsion{ public static void main(String[] args){ final long a=24L*60*60*1000*1000; final long b=24L*60*60*1000; System.out.println(a/b); }} △当操作很大的数时一定要提防溢出]]></content>
</entry>
<entry>
<title><![CDATA[Maven 学习笔记(一)]]></title>
<url>%2F2017%2F01%2F31%2FMaven-Note-1%2F</url>
<content type="text"><![CDATA[做的项目大部分都是用 Maven 构建的,一直没有系统的学习和整理 Maven 的知识。最近接手的一个项目,研究架构代码的时候,发现一个大牛们写的一个通过解析 PDM 生成对应数据的生成实体对象的一个 Maven 插件。研究的时候发现很多 Maven 知识还不甚了解,找了本 《Maven 实战》系统的学习和整理知识点一遍。 Maven IntroduceMaven 是一种构建工具,同时还是一个依赖管理工具和项目信息管理工具.它提供了中央仓库,能帮我们自动下载构件. Maven 文件目录 bin 该目录包含mvn运行的脚本,这些脚本用来配置Java命令,mvnDebug,主要是 Maven 运行时开启debug,调试 Maven 本身. m2.conf文件, classworlds的配置文件. boot 只有一个文件,plexus-classworlds-(version).jar. 一个类加载器. Maven使用它加载对应自己的类库 conf settings.xml, 全局定义Maven行为. lib Maven运行所需的Java类库. 存放的真正的Maven, 里面内置了很多Maven的超级POM. 设置HTTP代理12345678910111213141516171819<settings><proxies> <proxy> <id>my-proxy</id> <!-- 是否激活该代理 --> <active> false | true </active> <!-- 代理协议 --> <protocol>http</protocol> <host></host> <port></port> <!-- <username>***</username> <password>***</password> 设置不需要代理的主机名, * 表示所有以google.com的域名不使用代理 <nonProxyHosts>*.google.com</nonProxxyHosts> --> </proxy><proxies></settings> Maven ABC 编写POM 12345678910111213<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"> <!-- 指定当前POM版本,Maven2 以及Maven3 默认为 4.0.0 --> <modelVersion>4.0.0</modleVersion> <!-- groupId+artifaceId定义一个项目的基本坐标--> <groupId></groupId> <!-- 当前所属group中的Maven的唯一ID--> <artifactId><artifactId> <!-- artifast项目的版本号 --> <version></version> <!-- --> <name></name></project> 编写主代码主代码位于 src/main/java, Java类的包名需要跟POM中定义的groupId和artifactId相吻合,编译输出为target 编写测试代码测试代码位于 src/test/java Archetype生成项目骨架1mvn archetype:generate]]></content>
</entry>
</search>