MENU

Category: 有码

String.valueOf(null)引出的两个问题

昨天有人在群里问了这么个问题:

System.out.println(String.valueOf(null));

会报空指针异常;而下面这样就可以打印null

Object obj = null;    
System.out.println(String.valueOf(obj));

debug代码会发现,两种方式执行了不同的重载方法,第一种执行了

public static String valueOf(char data[]) {
    return new String(data);
}

第二种执行了

public static String valueOf(Object obj) {
    return (obj == null) ? ""null"" : obj.toString();
}

如果对重载不熟悉,很难解释其中原因;当然null是另一个让人头疼的问。

重载

Java的重载解析过程是以两阶段运行的:

  • 第一阶段:选取所有可获得并且可应用的方法或构造器。

Read More

HTTP 代理池实现

首先,使用付费代理的用户可以忽略本文;如果经常使用免费代理又觉得不稳定的用户可以尝试下,尤其适合爬虫这类需要频繁换代理IP的场景。

该项目fork自 https://github.com/henson/ProxyPool;原项目使用了mongodb作为代理的存储,返回json类型数据,大概是这样:

{
    ""ip"": ""27.4.70.129:53281"",
    ""type"": ""http""
}

改造之后,将mongodb换成了redis,加入了cron任务,返回文本数据:27.4.70.129:53281

项目由四个功能构成,api、getter、storage和tasks。

api

//程序版本
const VERSION = ""/v1""

// 提供api服务
func Serve() {
    mux := http.NewServeMux()
    mux.HandleFunc(VERSION+""/ip"", ProxyHandler)
    log.Println(""Starting server"", util.NewConfig().Host)
    http.ListenAndServe(util.NewConfig().Host, mux)
}

//代理处理器
func ProxyHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method == ""GET"" {
        w.Header().Set(""content-type"", ""text/html"")
        ip := storage.ProxyGet()
        w.Write([]byte(ip))
    }
}

提供http服务,GET http://127.0.0.1:8080/v1/ip返回代理ip

Read More

Spring Boot 之 Configuration

在上一篇的Starter项目中,加入了两三个依赖就完成了一个CRUD的Web项目;Spring Boot是如何实现自动配置的呢?

如果是一个普通的Spring项目,我们需要较多的配置,比如web.xml中配置ContextLoaderListener,配置DispatcherServlet等,在Spring的配置文件中配置数据源、页面模版、JOSN序列化、静态资源等等;而在Spring Boot项目中,这些都在内部进行了配置,完全的约定优于配置,像端口监听8080、把/static目录暴露为静态资源、Thymeleaf模版文件要放在/templates目录。

在项目的依赖中找到spring-boot-autoconfigure这个jar,会发现很多配置类,挑个简单的打开看看,就ThymeleafProperties吧,下面是代码片段:

@ConfigurationProperties(""spring.thymeleaf"")
public class ThymeleafProperties {
    private static final Charset DEFAULT_ENCODING = Charset.forName(""UTF-8"");
    private static final MimeType DEFAULT_CONTENT_TYPE = MimeType.valueOf(""text/html"");
    public static final String DEFAULT_PREFIX = ""classpath:/templates/"";
    public static final String DEFAULT_SUFFIX = "".html"";
    private boolean checkTemplate = true;
    private boolean checkTemplateLocation = true;
    private String prefix = ""classpath:/templates/"";
    private String suffix = "".html"";
    private String mode = ""HTML5"";
    private Charset encoding;
    private MimeType contentType;
    private boolean cache;
    private Integer templateResolverOrder;
    private String[] viewNames;
    private String[] excludedViewNames;
    private boolean enabled;

看到这大概就明白这些自动配置是怎么回事了,配置一个都没少只是换地方了;不过,还有一个问题,这么配置项都在项目启动时进行配置肯定是不行;一定是按需配置的,依赖了Thymeleaf才去启动Thymeleaf的配置。这就用到了Spring 4.0的新特性,条件化配置;条件成立时才启用配置。

Spring Boot中定义了很多条件化配置的注解,用于配置类;配置类和条件化注解共同构成了自动配置。

Read More

Spring Boot 之 Starter

在实际项目开发中一个项目所依赖的类库通常是比较多的,而且还有考虑各个类库直接版本兼容性问题;所以或多或少的都会对第三方类库进行包装,比如封装成xx-web、xx-db、xx-cache等类库,在使用时仅依赖需要的模块即可,也方便版本升级。其实大部分类库都这样的,比如springframework包含的spring-core、spring-webmvc、spring-jdbc等等,只是划分粒度太小,一个单纯的web项目也要管理很多的依赖和版本兼容性。

在Spring Boot中提供了更粗粒度的依赖(当然也有细粒度的)starter,大大降低了依赖管理的复杂性;像Spring Boot 之 Hello World中的Hello World项目,仅仅使用了spring-boot-starter-web这一个依赖,项目就可以运行使用;打开它的pom.xml会发现是它的这些依赖组合在一起提供了web功能;spring-boot-starter-tomcat是另一个starter,提供了内嵌web服务器,也可以发现Spring Boot提供了不同粒度的starter方便更多场景下的使用。

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
        </dependency>
    </dependencies>

移步Spring Boot Starter 查询查看更多Starter。

接着之前的Hello World项目,完成一个简单的CRUD功能。

Read More

Spring Boot 之 Hello World

Spring boot 简化了基于 Spring 的应用开发,它为 Spring 以及第三方库提供了开箱即用的设置,减少了复杂配置;提供了内嵌服务器、健康监测等特性;我们可以使用java -jar来启动一个web应用。

本文将完成一个最简单的基于 spring boot 的 web 项目,通过这个项目来熟悉 spring boot 的项目结构;首先,需要安装jdk 1.7+、构建工具mavengradleintellij idea

$ java -version
java version ""1.8.0_131""
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)
$ mvn -version
Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5; 2015-11-11T00:41:47+08:00)
Maven home: C:\Program Files\apache-maven-3.3.9
Java version: 1.8.0_121, vendor: Oracle Corporation
Java home: C:\Program Files\Java\jdk1.8.0_121\jre
Default locale: zh_CN, platform encoding: GBK
OS name: ""windows 10"", version: ""10.0"", arch: ""amd64"", family: ""dos""

创建项目

创建一个maven项目,编辑pom.xml文件:

<?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>tech.sheli.xjc</groupId>
    <artifactId>xjc-web-hello</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- 继承自Spring Boot的默认parent -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.4.RELEASE</version>
    </parent>

    <dependencies>
        <!-- 添加Web应用程序的典型依赖项 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <!-- 包作为可执行jar -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

以上就是个典型的pom.xml文件,继承了spring-boot-starter-parent,它包含了java版本(1.6)、项目编码(UTF-8)、测试框架、spring-boot-maven-plugin等,当然也可以不使用spring-boot-starter-parent,自己配置,具体配置会有单独的文章说明;设置spring-boot-starter-web依赖,也是唯一显示配置的依赖。

Read More