MENU

Category: 有码

Spring Boot 整合 RabbitMQ

Spring Boot整合RabbitMQ是非常容易的,下面将通过一个最简单的例子实现消息的发送和接收;仅引用spring-boot-starter-amqp这个starter即可完成rabbitMQ的整合。

首先,创建一个maven项目,pom.xml加入依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    <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>

额外增加pring-boot-starter-web是为了方便调用生产消息。

增加配置文件application.yml,配置RabbitMQ相关信息:

spring:
  rabbitmq:
    host: 66.66.66.66
    port: 5672
    username: wangxuesong
    password: 123456

Read More

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