Spring Framework 4和Java 8

Java 8附带了新的语言功能和库,而Spring 4.x已经支持其中的许多功能。 Java 8的某些新功能不会对Spring产生影响,只能按原样使用,而其他Java 8功能则需要Spring明确支持它们。 本文将向您介绍Spring 4.0和4.1支持的Java 8新功能。

Spring 4支持Java 6、7和8

使用Java 8编译器编译的代码会生成.class文件,这些文件至少需要运行Java 8虚拟机。 由于Spring大量使用反射和其他字节码操作库(例如ASM,CGLIB等),因此确保这些库能够理解新的Java 8类文件非常重要。 因此,Spring现在使用jar jar(https://code.google.com/p/jarjar/)将ASM,CGLIB和其他库嵌入到Spring框架中,以便Spring拥有一组可以与Java 6一起使用的可预测库。 7和8字节代码,而不会触发运行时错误。

使用带有命令行选项的Java 8编译器来编译Spring框架本身,以产生Java 6字节代码。 因此,您可以使用Java 6、7或8编译和运行Spring 4.x应用程序。

Spring和Java 8 Lambda表达式

Java 8的设计人员希望确保其向后兼容,以便Java 8 lambda表达式可与以前版本编译的代码一起使用。 通过定义功能接口的概念实现了向后兼容性。

基本上,Java 8设计人员分析了现有的Java代码主体,并注意到大多数Java程序员使用具有单一方法的接口来表示函数的思想。 例如,以下是JDK和Spring中仅使用一种方法的接口列表,这些接口被称为“功能接口”。

JDK功能接口:

public interface Runnable {
    public abstract void run();
}

public interface Comparable<T> {
    public int compareTo(T o);
}

Spring框架功能接口:

public interface ConnectionCallback<T> {
  T doInConnection(Connection con) throws SQLException, DataAccessException;
}

public interface RowMapper<T>
{
  T mapRow(ResultSet rs, int rowNum) throws SQLException;
}

在Java 8中,可以在将函数接口传递给方法或从方法返回的任何地方使用lambda表达式。例如,Spring JdbcTemplate类包含具有以下签名的方法

public <T> List<T> query(String sql, RowMapper<T> rowMapper)
  throws DataAccessException

请注意,查询方法的第二个参数需要RowMapper接口的实例。 使用Java 8,我们可以编写一个lambda表达式作为查询方法第二个参数的值。

而不是像这样编写代码:

jdbcTemplate.query("SELECT * from products", new RowMapper<Product>(){
  @Override
  public Product mapRow(ResultSet rs, int rowNum) throws SQLException {
    Integer id = rs.getInt("id");
    String description = rs.getString("description");
    Integer quantity = rs.getInt("quantity");
    BigDecimal price = rs.getBigDecimal("price");
    Date availability = rs.getDate("available_date");

    Product product = new Product();
    product.setId(id);
    product.setDescription(description);
    product.setQuantity(quantity);
    product.setPrice(price);
    product.setAvailability(availability);

    return product;
  }
});

我们编写如下代码:

jdbcTemplate.query("SELECT * from queries.products", (rs, rowNum) -> {
    Integer id = rs.getInt("id");
    String description = rs.getString("description");
    Integer quantity = rs.getInt("quantity");
    BigDecimal price = rs.getBigDecimal("price");
    Date availability = rs.getDate("available_date");

    Product product = new Product();
    product.setId(id);
    product.setDescription(description);
    product.setQuantity(quantity);
    product.setPrice(price);
    product.setAvailability(availability);

    return product;
});

请注意,此代码的Java 8版本正在使用lambda表达式,这比使用匿名内部类的先前版本中的代码更加紧凑和简洁。

涵盖Java 8功能接口的所有详细信息超出了本文的范围,强烈建议您在其他地方学习功能接口的详细信息。 但是,关键要点在于,如果方法接受功能接口,则可以将Java 8 lambda表达式传递给使用Java 7和更早版本编译的方法。

Spring代码库包含许多功能接口,因此lambda表达式可轻松用于Spring。 即使将Spring框架本身编译为Java 6 .class文件格式,您仍然可以使用Java 8 lambda表达式编写应用程序代码,使用Java 8编译器对其进行编译,然后在Java 8 VM上运行它就可以了。

总之,由于在Java 8正式定义功能接口之前,Spring框架一直在使用功能接口,因此在Spring中使用lambda表达式很容易。

Spring 4和Java 8 Time and Date API

Java开发人员长期以来一直抱怨java.util.Date类的设计缺陷,最后,对于Java 8,提供了一个全新的Date and Time API,可以解决这些长期存在的问题。 新的日期和时间API是对得起它的自己的文章 ,因此我们不会掩盖它比值得注意的是,新java.time包引入了许多新的类,如LOCALDATE的,本地时间和LocalDateTime其他细节。

Spring附带了一个数据转换框架,该框架可以将字符串从Java数据类型转换为Java数据类型。 Spring 4更新了转换框架,以支持Java 8 Date and Time API中的所有类。 因此,您可以编写这样的代码。

@RestController
public class ExampleController {

  @RequestMapping("/date/{localDate}")
  public String get(@DateTimeFormat(iso = ISO.DATE) LocalDate localDate)
  {
    return localDate.toString();
  }
}

请注意,在上面的示例中,get方法的参数为Java 8中的LocalDate类型,Spring 4将能够采用诸如2014-02-01之类的字符串并将其转换为Java 8 LocalDate的实例。

重要的是要注意,Spring常与其他库一起使用,例如Hibernate用于数据持久性,而Jackson用于将Java对象转换为JSON。

尽管Spring 4支持Java 8日期和时间库,但这并不意味着像Hibernate和Jackson这样的第三方框架都能够支持Java 8日期和时间。 在发布时,Hibernate JIRA包含一个开放票证HHH-8844,请求在Hibernate中支持Java 8日期和时间API。 。

Spring 4和重复注释

Java 8添加了对重复注释的支持,而Spring 4支持这些注释。 特别是Spring 4支持重复@Scheduled和@PropertySource批注。 例如,请注意下面的代码片段中重复的@PropertySource批注。

@Configuration
@ComponentScan
@EnableAutoConfiguration
@PropertySource("classpath:/example1.properties")
@PropertySource("classpath:/example2.properties")
public class Application {

	@Autowired
	private Environment env;

	@Bean
	public JdbcTemplate template(DataSource datasource) {
		System.out.println(env.getProperty("test.prop1"));
		System.out.println(env.getProperty("test.prop2"));
		return new JdbcTemplate(datasource);
	}

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

Java 8 Optional <>和Spring 4.1

忘记检查空引用是应用程序代码中错误的常见来源。 消除NullPointerExceptions的一种方法是确保方法始终返回非null值。 例如,考虑如下方法:

public interface CustomerRepository extends CrudRepository<Customer, Long> {
   /**
    * returns the customer for the specified id or
    * null if the value is not found
   */
   public Customer findCustomerById(String id);
}

CustomerRepository的用户可以编写如下错误代码:

Customer customer = customerRepository.findCustomerById(“123”);
customer.getName(); // get a null pointer exception

而不是正确的版本,如下所示:

Customer customer = customerRepository.findCustomerById(“123”);
if(customer != null) {
  customer.getName(); // avoid a null pointer exception
}

理想情况下,如果我们不检查值是否可以为null,我们希望编译器抱怨。 java.util.Optional类使编写这样的接口成为可能。

public interface CustomerRepository extends CrudRepository<Customer, Long> {
  public Optional<Customer> findCustomerById(String id);
}

因此,错误的代码版本将不再编译,程序员必须通过编写这样的代码来显式检查Optional是否包含值。

Optional<Customer> optional = customerRepository.findCustomerById(“123”);
if(optional.isPresent()) {
   Customer customer = optional.get();
   customer.getName();
}

因此,Optional的关键思想是确保程序员知道方法可以返回null,或者可以在无需读取Javadoc的情况下将null值传递给方法。 方法签名和编译器将有助于使您清楚该值是Optional。 找到有关Optional类的更详细的描述 在这里

Spring 4.1通过两种方式支持Java Optional。 Spring @Autowired批注包含“必需”属性,因此诸如

@Service
public class MyService {

    @Autowired(required=false)
    OtherService otherService;

    public doSomething() {
      if(otherService != null) {
        // use other service
      }
   }
}

可以替换为

public class MyService {

    @Autowired
    Optional<OtherService> otherService;

    public doSomething() {
      otherService.ifPresent( s ->  {
        // use s to do something
      });
    }
}

可以使用Optional的另一个地方是Spring MVC,它可以指示处理程序方法参数是可选的。 例如:

@RequestMapping(“/accounts/{accountId}”,requestMethod=RequestMethod.POST)
void update(Optional<String> accountId, @RequestBody Account account)

会告诉Spring accountId是可选的。

综上所述,Java 8 Optional类使编写代码变得更加容易,同时减少了NullPointerException错误,并且Spring与Java 8 Optional类可以很好地协同工作。

参数名称发现模型

Java 8增加了对在已编译代码中保留方法参数名称的支持。 这意味着Spring 4可以从方法中提取参数的名称,这使SpringMVC代码更加紧凑。 例如:

@RequestMapping("/accounts/{id}")
public Account getAccount(@PathVariable("id") String id)

可以写成

@RequestMapping("/accounts/{id}")
public Account getAccount(@PathVariable String id)

注意,我们将@PathVariable(“ id”)替换为@PathVariable,因为Spring 4可以从编译的Java 8代码中获取参数名称id。 如果使用–parameters标志调用,则Java 8编译器会将参数名称写到.class文件中。 在Java 8之前的版本中,如果代码是使用–debug选项编译的,则Spring能够从编译的代码中提取参数名称。

对于Java 7和更早版本,–debug选项不会在抽象方法上保留参数名称。 因此,对于像Spring Data这样基于Java接口自动生成存储库实现的项目,这会引起问题。 例如,考虑下面的界面。

interface CustomerRepository extends CrudRepository<Customer, Long> {
  @Query("select c from Customer c where c.lastname = :lastname")
  List<Customer> findByLastname(@Param("lastname") String lastname);
}

请注意,在findByLastname签名中需要@Param(“ lastname”),因为即使使用–debug Java 7及更早版本,由于findByLastname是抽象方法,因此也不会保留参数名称。 借助Java 8 –parameters选项,Spring Data能够发现抽象方法上的参数名称,因此我们可以将接口重写为。

interface CustomerRepository extends CrudRepository<Customer, Long> {
  @Query("select c from Customer c where c.lastname = :lastname")
  List<Customer> findByLastname(String lastname);
}

请注意,我们不再需要@Param(“ lastname”)来使我们的代码更简洁,更易于阅读。 因此,在使用Java 8时,最好使用–parameters标志来编译代码。

结论

Spring 4在Java 6、7和8上运行,作为开发人员,您可以使用Java 6、7、8中的任何一种编写应用程序代码。如果您使用Java 8,则可以使用lambda表达式编写更简洁的代码。有功能接口的任何地方都可以使用更紧凑的代码。 由于Spring使用了大量的功能接口,因此在Spring 4中使用lambda表达式的机会很多。

Java 8附带了改进的库,例如新的java.time包和Spring能够使用的Optional类,使编写清晰/简单的代码变得更加容易。

最后,使用–parameters选项编译Java 8代码将保留方法中的参数名称,并使编写更紧凑的Spring MVC方法处理程序和Spring Data查询方法成为可能。

如果您准备开始在项目中使用Java 8,您会发现Spring 4是一个很好的框架,可以利用Java 8的功能。

翻译自: https://www.infoq.com/articles/spring-4-java-8/?topicPageSponsorship=c1246725-b0a7-43a6-9ef9-68102c8d48e1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
框架说白了就是JAVA工作者多年以来总结出的一些开发标准。让我们可以以成功的经验模式来开发我们自已的系统,一般使用框架的好处是 ·在好的框架下,开发者只需要写一些必须的代码;他们不需要直接接触底层的API。 这一点很重要。 ·经过良好设计的框架可以为程序提供清晰的结构并且提高程序的内聚性。好清晰的结构使得其他人可以更容易加入项目。 ·一个容易使用的框架可以通过一些例子和文档为用户提供最佳实践。 ·采用成功的框架的代码比自己的代码容易测试 J2EE本身提供了一些框架。比如, Enterprise Java-Beans (EJB) container或者 Servlet engine 而这些框架一般在中小工程中我们都不会使用,会让我们把大量的时间浪费在开发框架上。 而现在比较流行开源框架,主要是struts,hibernate,spring等 比如struts是在原有mvc基础上实现在代码分离等功能,非常好用。 而hibernate可以把我们的关系型数据库转换成我们在JAVA中的面像对像来使用。从而让我们在开发时不需要直接写SQL语句,比如database.getName();就可以直接把数据库中的用户名取出来。 Spring J2EE框架被大规模地运用到项目中,而项目总要负责这些框架以及自己业务代码的连接,使之真正融合到一起。Spring就是专注于这个问题的,它和Hibernate融合的很好。 这三种框架在一起并不冲突,所以现在最常用的框架就是 struts+hibernate+spring就像我们盖房子一样,先把框架搭好,我们在在上面写代码就很规范。 Struts框架介绍 : Struts只是一个MVC框架(Framework),用于快速开发Java Web应用。Struts实现的重点在C(Controller),包括ActionServlet/RequestProcessor和我们定制的 Action,也为V(View)提供了一系列定制标签(Custom Tag)。但Struts几乎没有涉及M(Model),所以Struts可以采用JAVA实现的任何形式的商业逻辑。 Spring是一个轻型容器(light-weight container),其核心是Bean工厂(Bean Factory),用以构造我们所需要的M(Model)。在此基础之上,Spring提供了AOP(Aspect-Oriented Programming, 面向层面的编程)的实现,用它来提供非管理环境下申明方式的事务、安全等服务;对Bean工厂的扩展ApplicationContext更加方便我们实 现J2EE的应用;DAO/ORM的实现方便我们进行数据库的开发;Web MVC和Spring Web提供了Java Web应用的框架或与其他流行的Web框架进行集成。 就是说可将两者一起使用,达到将两者自身的特点进行互补。 spring 框架介绍 : 它关注的领域是其他许多流行的Framework未曾关注的。Spring要提供的是一种管理你的业务对象的方法。 Spring既是全面的又是模块化的。Spring有分层的体系结构,这意味着你能选择仅仅使用它任何一个独立的部分,而它的架构又是内部一致。 因此你能从你的学习中,得到最大的价值。例如,你可能选择仅仅使用Spring来简单化JDBC的使用,或用来管理所有的业务对象。 它的设计从一开始就是要帮助你编写易于测试的代码。Spring是使用测试驱动开发的工程的理想框架。 Spring不会给你的工程添加对其他的框架依赖。Spring也许称得上是个一站式解决方案,提供了一个典型应用所需要的大部分基础架构。它还涉及到了其他framework没有考虑到的内容。 尽管它仅仅是一个从2003年2月才开始的开源项目,但Spring有深厚的历史根基。 Spring架构上的好处 在我们进入细节之前,让我们来看看Spring能够给工程带来的种种好处: Spring能有效地组织你的中间层对象,不管你是否选择使用了EJB。如果你仅仅使用了Struts或其他为J2EE的 API特制的frameworkSpring致力于解决剩下的问题。 Spring能消除在许多工程中常见的对Singleton的过多使用。根据我的经验,这是一个很大的问题,它降低了系统的可测试性和面向对象的程度。 通过一种在不同应用程序和项目间一致的方法来处理配置文件,Spring能消除各种各样自定义格式的属性文件的需要。曾经对某个类要寻找的是哪个 魔法般的属性项或系统属性感到不解,为此不得不去读Javadoc甚至源编码?有了Spring,你仅仅需要看看类的JavaBean属性

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值