Spring 项目中把属性或 SQL 语句写在 .xml 文件中

Spring 项目中把大量的 SQL 分散在 Java 代码中,无 Here Doc 的情况下用加号来连接写着实在是不爽,于是之前思考这个 Spring 项目中把 SQL 语句写在 .sql 文件中 --  把它们写在 *.sql 文件中,但是这个 *.sql 需要特定的格式来标识属性 Key

--!select.user
select id, firstname, lastname, address
--!update.user
update ........

而且还需要一个额外的类 SqlPropertySourceFactory 来解析上面的 *.sql 文件, 识别出 select.user 是 Key, 紧接着后面的块是相应的属性值,用注解引用它时还有点额外的 factory 属性来配置,如

@PropertySource(value = "classpath:sql/queries.sql", factory = SqlPropertySourceFactory.class)

所以一直在思考是否能够再简单些,是否能用一个自定义的注解,如

@SqlPropertySource("classpath:sql/queries.sql")

捉摸了很久,似乎有点难度,不过再不断发掘的过程中找到了这个类 org.springframework.core.io.support.PropertiesLoaderUtils, 有下面的代码片断 阅读全文 >>

JdbcTemplate 易被 Java 8 Lambda 带入的坑

Spring 的 JdbcTemplate 为我们操作数据库提供非常大的便利,不需要显式的管理资源和处理异常。在我们进入到了 Java 8 后,JdbcTemplate 方法中的回调函数可以用 Lambda 表达式进行简化,而本文要说的正是这种 Lambda 简化容易给我们带来的一个 Bug, 这是我在一个实际项目中写的单元测试发现的。

下面就是我们的一个样板代码,在我们的 UserRespository 中有一个方法 findAll() 用于获得所有用户:

阅读全文 >>

Spring 如何初始化泛型类实例

在 Java 中对于泛型类型,比如这样简单的类定义

class Processor<T> {}

如果直接初始化时要指定具体类型的话,我们可以这么写

Processor<String> processor = new Processor<>();  //Java 7 及以上版本

Spring 对基本泛型的初始化

如果我们要用 Spring 容器来初始化这个类,比如给上面那个类加个 @Named 注解

@Named
class Processor<T> {
}

这时候我们通过 beanFactory.getBean(Processor.class) 得到的是一个什么样的实例呢?Spring 怎么知道要指定什么具体类型呢?很简单,任何不确定的情况都是 Object。所以通过容器得到的  Processor 实例相当于用下面代码构造出来的

Processor processor = new Processor();  //更准确来讲是 Processor<Object> processor = new Processor<>();

再进一步,对于有上限约束的泛型定义,Spring 才如何应对呢?像 阅读全文 >>

Spring 项目中把 SQL 语句写在 .sql 文件中

我们在使用 JDBC 时, 如果把所有的 SQL 语句全写在 Java 文件中, 由于 Java 不支持 Here Document, 多行字符串要么用加号, 要么用 Java 8 的 String.join() 方法来连接, 同时不能对 SQL 语句进行语法加亮, 所以这样的 SQL 字符串阅读性很差. 别说为何不用 Hibernate 之类的而不直接写原始的 SQL 语句, 在操作复杂的系统时还是会用到 JdbcTemplate 吧.

所以我们希望能把 SQL 语句写在单独的 *.sql 文件里, 这样很多编辑器就能语法高亮显示, 或在输入时还能得到智能提示. 有种办法是把 *.sql 用作为属性文件, 那么在其中定义多行的 SQL 语句时就得这样

select.user=select id, firstname, lastname, address \
  from users \
  where id=?

加载后就能用 getProperty("select.user") 来引用相应的语句了. 属性文件的换行与 Bash  一样, 也是用  \, 但如此, 则 *.sql 并非一个纯粹的 SQL 文件, 不能正确的进行语法加亮, 一旦写上 SQL 的注释 -- 就更是在添乱了.

所以我们的第二个方案是: 首先 *.sql 就该是一个真正的  SQL 文件, 而不是伪装的属性文件, 为了能在程序中引用每一条 SQL 语句, 我们该如何表示各自的 Key 呢? 这里的灵感仍然是来自于 Linux Shell, 在 Linux Shell 中指定执行环境的用了特殊的注释方式 #!, 如

#!/bin/bash
#!/usr/bin/env python

阅读全文 >>

如何定制 Spring Boot 的 Banner

当我们启动一个 Spring Boot 的 Hello World 程序, 可以看到 Spring 会在控制台下输出一段 ASCII 字符组成的 Spring 字样, 像这个图中的样子, spring-boot-banner并且 ":: Spring Boot ::" 是绿色显示, 版本号灰色. 如果每个 Spring Boot 做的应用都用默认的 Banner 就不好玩了, 无外乎只在声明我正在用 Spring Boot. 好在 Spring 提供了多种方式让我们定制自己的 Banner.

官方文档: http://docs.spring.io/spring-boot/docs/1.3.8.RELEASE/reference/htmlsingle/#boot-features-banner

初始 Banner 的代码是 SpringApplicationBannerPrinter 类.

Spring Boot 默认寻找 Banner 的顺序是:

  1. 依次在 Classpath 下找 文件 banner.gif, banner.jpg, 和 banner.png, 先找到谁就用谁
  2. 继续 Classpath 下找 banner.txt
  3. 上面都没有找到的话, 用默认的 SpringBootBanner, 就是我们最常见到的那个

阅读全文 >>

小试 Spring Boot - Spring MVC

前阵想试下 Spring MVC 4 有了些什么新特性, 可真正用 Maven 在 IDE 中建立一个项目并不那么容易. Spring 当初在笑 EJB 的笨重时如今把自己也搞大了, 继而出台了一个 Spring Boot 来响应微服务的号召.

Spring Boot 的出世可以大大提升使用 Spring 框架时的开发效率. Spring 尽量简化 Spring 项目的配置, 一个 mvn package 就轻轻松的把一个 Web 项目打成一个  fat jar, 运行 java -jar spring-boot-sample-1.0-SNAPSHOT.jar 就能通过内嵌的 Tomcat 或 Jetty 来启动一个 Web 应用了, 更别提怎么应对普通控制台应用了.

现在就来体验一下 Spring Boot 做一个 Spring MVC 项目有多简单, 我们仍然是建立一个 Maven 项目, 最简单的 pom.xml 文件内容如下: 阅读全文 >>

Spring+AspectJ+ 简单方式来拦截方法,监测性能

还是在很久以前,作过一篇 用 AOP 来记录每个方法的执行时间(Spring 或直接 AspectJ), 其中例示了三种方法来拦截方法,用以监测方法调用时间它们分别是:

1. Spring 2.0 用 AspectJ 实现 AOP
2. Spring 通用的方法拦截
3. 直接用 AspectJ 实现

在这里再次使用 <aop:aspect-autoproxy/> 再 @Aspect 注解的方式来写个新的例子。原理与前面基本一致,只是在类里用 @Aspect, @Pointcut, @Before, @After, @Around, @AfterReturning, @AfterThrowing 来写拦截类。

局限仍然是必须通过 Spring 的 BeanFactory 获得的实例才能被拦截到,除非是在 Eclipse 里安装 AJDT 或是使用 Maven-AspectJ Plugin 来编译工程。

好,我们来看完整的例子,下面列出所有的项目文件,这是一个 Maven 的项目,所以从 pom.xml 开始。 阅读全文 >>

SPRING-MVC 访问静态文件, 如 jpg/js/css

如何你的DispatcherServlet拦截 .do这样的URL,就不存在访问不到静态资源的问题。如果你的DispatcherServlet拦截“/”,拦截了所有的请求,同时对.js,*.jpg的访问也就被拦截了。

 目的:可以正常访问静态文件,不要找不到静态文件报404。
 
方案一:激活Tomcat的defaultServlet来处理静态文件

要配置多个,每种文件配置一个  阅读全文 >>

Spring MVC 碰到 java.lang.NoSuchFieldError: APPLICATION_CONTEXT_ID_PREFIX

Spring MVC 应用在 Tomcat 启动的时候出现了下面的错误:

java.lang.NoSuchFieldError: APPLICATION_CONTEXT_ID_PREFIX
 at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:430)
 at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:458)
 at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:339)
 at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:306)
 at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:127)
 at javax.servlet.GenericServlet.init(GenericServlet.java:212)
 at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1173)
 at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:993)
 at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4350)
 at org.apache.catalina.core.StandardContext.start(StandardContext.java:4659)
 at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045) 阅读全文 >>

Spring 2.0可扩展XML配置初探[转]

本文通过一个简单的例子,说明如何去扩展XML配置,它大致需要的几个步骤。具体的需求是使用自定义标签定义一个简单的bean,这个bean有一个或多个属性,标签定义完成后,可以在其他项目中用自定义标签来定义该bean。

Spring 2.0版本支持扩展XML配置,着实兴奋了一下,在我看来,Spring作为目前最流行的框架,不能扩展用户自定义的配置,实在是Spring的一个很不爽的地方,的方式用起来比较通用,起码到目前为止符合大部分人的使用习惯,并且能完成Spring所有的配置操作,但是对于第三方的提供商或则会经常扩展Spring功能的开发者来说,使用这样的配置方式或许不是他们最想要的,他们需要使组件的配置更加直观、易阅读、易扩展……试想使用下面的配置方式。 阅读全文 >>