(更新中...)Java EE设计模式 Spring企业级开发最佳实践

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/emptylee/article/details/69362282

(更新中…)2017.4.6

Java EE设计模式 Spring企业级开发最佳实践

@(Java读书笔记)


Pro Java EE Spring Patterns
Best Practices and Design Strategies Implementing Java EE Pattern with the Spring Framework
[印] Dhrubojyoti Kayal 著
张平 龚波 李平芳 等译

第2章 使用Spring框架简化企业级Java应用程序

本章内容:
简要介绍了Spring应用框架及其重要性,然后将详细介绍Spring框架的每一个组成部分。

2.1 什么是Spring

Spring框架是个开源的应用程序框架,最初用于Java平台,现在也移植到.NET平台。

2.2 为什么Spring和重要

Java EE平台的目标是降低分布式应用程序开发的复杂性,旨在建立基于组件模型的应用程序,提高代码复用。
EJB目的:开发EJB的初衷是为了降低事务和分布式应用程序的开发难度。
EJB缺点:但过多的使用EJB,特别是会话bean来简化业务逻辑,必将导致在应用程序组件模型中引入分布式特性,这些特性非常复杂,且会消耗更多的CPU资源,也会导致产生与元数据相关的大量重复性代码,并且访问分布式应用程序组件需要网络往返传输数据,以及大规模数据集的组装和分解。因此,即使是一个非常简单的应用,滥用分布式对象也会导致不理想的执行结果。
Java EE包含大量本来就很复杂的技术和API。例如:完全掌握实体bean API是很难的,并且带来的价值又不大。由于Java EE组件在应用程序服务器容器内部运行,所以很难对其做单元测试,从而无法执行测试驱动开发(TDD)。

这种种限制直接导致了开发团队尝试寻求替代方法,继而出现了基于不同Java EE API所构建的框架。Spring框架同样也能解决与Java EE应用程序开发相关的复杂难题,它的优势在于:
1、Spring提供了一个全面的多层框架,可在应用程序的所有层使用。这一特性,有助于整合整个应用程序和现成的组件,以及集成最适合的单层框架(如Hibernate或struts等)
2、Spring框架提供一个基于POJO的简单编程模型,并且由于这些组件可在服务器容器之外运行,所以测试起来非常容易。
3、IOC容器是整个框架的核心,有助于粘合应用程序的不同部分从而形成一个整体
4、通过Spring的各种远程选项,这些POJO业务组件可以成为分布式对象,或者,可以使用POJO业务组件来开发和连接分布式EJB组件。
5、使用Spring AOP可向POJO组件透明的应用系统服务,如事务、安全和检测。
6、Spring的安全机制是一种全面的解决方案,足以满足任何企业级应用程序的安全需求。

2.3 Spring框架的组成部分

Spring是一个应用程序框架,可以分成若干个模块或者组件,每个模块都可以提供一组特定的功能,并且运行时具有一定的独立性。开发人员可以选择最适合当前问题域的模块,所以系统非常灵活。Spring框架的组成如图:
Spring框架的各组成模块.jpg

2.3.1 Spring Core

Core模块是整个Spring的核心,所有其他模块依赖于它。

1. IOC(Inversion of Control)

“好莱坞原则”是IOC的最佳描述:“不要给我们打电话,我们会给你打电话”。这一点在所有高内聚和低耦合的软件开发以及应用程序的流程控制中都非常重要。考虑一个简单的例子:应用程序要使用log4j执行某种计算操作,并输出最终结果。在这个例子中应用程序负责流程控制,在必要的时候再调用log4j API的方法。

IOC是所有框架的基础,借助IOC,应用程序对象被注册到框架,而框架负责在合适的时机或事件发生时,调用被注册对象的方法。简言之,IOC的基本原理是允许其他对象或框架在相关事件发生时调用自己应用程序对象中的方法。

之所以叫控制反转,这个反转体现在,不是应用程序调用了框架API,而是框架API调用了应用程序代码。

2. DI(Dependency Injection)

DI描述一个对象如何解析或查找提供所需方法的对象。存在多种DI实现方式,IOC只是其中的一种策略。

(1)直接实例化
public class FormulaOneDriver{
    public Car getCar(){
        Car car = new FerrariCar();
        return car;
    }
}

缺点:
* 增加耦合度
* 导致对象创建代码分散在应用程序中,增加代码维护和单元测试难度。

(2)工厂助手
public class FormulaOneDriver{
    public Car getCar(){
        Car car = CarFactory.getInstance("FERARI");
        return car;
    }
}

工厂是一种对象设计的最佳实战,也被成为面向接口编程。该原理规定,具体对象必须实现一个在调用程序中使用但不再具体对象中使用的接口。这样做的优点是可以轻易地使用其他替代实现方法,却不会对客户端产生任何影响。换句话说,由于并不直接依赖于具体实现,因此会降低耦合。

借助工厂助手,也能够支持对象创建的可配置性。

(3)在注册服务中定位

直接实例化和工厂助手,都属于拉(pull)DI,因为依赖对象都是由最终使用它的对象“拉进来”的。因此严格意义上说并不是“注入”,而是一种依赖的解决方案。
IOC可以实现真正的DI,即推(push)DI,在这种方法中,外部容器或应用程序框架会创建依赖对象,并将依赖对象传递给需要它的对象。依赖对象需要构造器或者setter方法创建。

(4)DI 的优点
  • 使用依赖注入有利于实现松耦合。可在应用程序外部设置,并提供热插拔功能。
  • 利于测试驱动开发。
  • Spring IOC支持push DI,因此应用程序就不需要查找诸如EJB远程接口之类的对象了。
  • DI有利于促进面向对象设计和复用——实现对象组成而不是通过继承进行复用。
(5)DI 的缺点
  • 依赖通常通过XML配置进行硬编码,这些文件是专有的,并且不标准。
  • 将多个实例融合在一起可能会比较危险,因为需要处理的实例及其依赖关系过多。
  • 依赖基于XML的元数据,过多地使用映射和字节码操作,可能会影响应用系统的性能。
3. bean factory

org.springframework.beans.factory.BeanFactory 是Spring的IOC容器或bean工厂的基础。
它是GOF工厂方法设计模式的高级实现,可以创建、缓冲、融合和管理应用程序对象。
由于Spring改进了POJO编程模型,这些对象被成为bean。
Spring提供bean工厂的多种实现方式,其中一种就是类XmlBeanFactory。

下面代码就是一个简单的Spring bean 配置文件,spring-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns="http://www.springframework.org/schema/beans" 
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-4.3.xsd ">

        <bean class="com.apress.simpleapp.service.CarServiceImpl"/>
</beans>

配置bean后,下面开始介绍IOC容器,如下面代码所示,SpringInitializer.java:

Resource res = new FileSystemResource("spring-config.xml");
BeanFactory factory = new XmlBeanFactory(res);

现在Spring容器已经存在并在运行中,所以可以从bean工厂中检索能够在应用程序中执行某些实用操作的bean,有多种方式:

(1)pull DI

如下面代码所示,CarServiceLocator.java:

CarService service = (CarService)factory.getBean("carService");

可以实现,但是不推荐。因为它通过指定的键在Spring bean工厂或IOC容器中检索CarService对象,但是CarService可能存在不同变种,因此每次有不同需要时都需要调用getBean方法。

为解决上述问题,建议使用以下两种push DI。

(2)Setter注入

对象在Spring IOC容器中通过调用无参构造函数来创建,然后,依赖对象作为参数传递给setter方法。如下述代码:
CarServiceImpl.java

public class CarServiceImpl implements CarService{
    private CarDao carDao;
    public void setCarDao(CarDao carDao){
        this.carDao = carDao;
    }

    public void save(){
        carDao.save(car);
    }
}

通过配置文件,让Spring知道如何解析和注入依赖(通过setter方式)
spring-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns="http://www.springframework.org/schema/beans" 
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-4.3.xsd ">
    <bean nam="carService" class="com.apress.simpleapp.service.CarServiceImpl">
        <property name="carDao" ref="carDao"/>
    </bean>
    <bean nam="carDao" class="com.apress.simpleapp.dao.CarDaoImpl" />
</beans>
(3)构造器注入

在这种方式中,依赖对象作为构造器调用的一部分被传递。如:
CarServiceImpl.java

public class CarServiceImpl implements CarService{
    private CarDao carDao;
    public void CarServiceImpl(CarDao carDao){
        this.carDao = carDao;
    }

    public void save(){
        carDao.save(car);
    }
}

要实现构造器注入,对应配置文件也应该修改为:
spring-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns="http://www.springframework.org/schema/beans" 
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-4.3.xsd ">
    <bean nam="carService" class="com.apress.simpleapp.service.CarServiceImpl">
        <constructor-arg>
            <ref bean="carDao"/>
        </constructor-arg>
    </bean>
    <bean nam="carDao" class="com.apress.simpleapp.dao.CarDaoImpl" />
</beans>
4. 应用上下文
展开阅读全文

没有更多推荐了,返回首页